diff --git a/.dockerignore b/.dockerignore index 49a6388dd..901c21c3f 100644 --- a/.dockerignore +++ b/.dockerignore @@ -3,4 +3,5 @@ node_modules www/cache www/dist userdata -!userdata/wiki \ No newline at end of file +!userdata/wiki +.git \ No newline at end of file diff --git a/classes/Components/Mailer/Wrapper/LoggerWrapper.php b/classes/Components/Mailer/Wrapper/LoggerWrapper.php deleted file mode 100644 index a3b6f3e7e..000000000 --- a/classes/Components/Mailer/Wrapper/LoggerWrapper.php +++ /dev/null @@ -1,124 +0,0 @@ -LogFile() - */ -final class LoggerWrapper implements LoggerInterface -{ - /** @var erpAPI|MemoryLogger $erp */ - private $erp; - - /** - * @param erpAPI|MemoryLogger $erp - */ - public function __construct($erp) - { - $this->erp = $erp; - } - - /** - * @inheritDoc - */ - public function emergency($message, array $context = []) - { - $this->log('emergency', $message, $context); - } - - /** - * @inheritDoc - */ - public function alert($message, array $context = []) - { - $this->log('alert', $message, $context); - } - - /** - * @inheritDoc - */ - public function critical($message, array $context = []) - { - $this->log('critical', $message, $context); - } - - /** - * @inheritDoc - */ - public function error($message, array $context = []) - { - $this->log('error', $message, $context); - } - - /** - * @inheritDoc - */ - public function warning($message, array $context = []) - { - $this->log('warning', $message, $context); - } - - /** - * @inheritDoc - */ - public function notice($message, array $context = []) - { - $this->log('notice', $message, $context); - } - - /** - * @inheritDoc - */ - public function info($message, array $context = []) - { - $this->log('info', $message, $context); - } - - /** - * @inheritDoc - */ - public function debug($message, array $context = []) - { - $this->log('debug', $message, $context); - } - - /** - * @inheritDoc - */ - public function log($level, $message, array $context = []) - { - $message = sprintf('%s: %s', strtoupper($level), $message); - $stack = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS); - $caller = []; - foreach ($stack as $trace) { - if ($trace['class'] !== self::class) { - $caller = $trace; - - break; - } - } - if (!empty($caller)) { - $csplit = explode('\\', $caller['class']); - $module = $csplit[count($csplit)-1]; - $function = $caller['function']; - } else { - $module = ''; - $function = ''; - } - $action = ''; - if (array_key_exists('action', $context)) { - $action = $context['action']; - } - $dump = ''; - if (array_key_exists('dump', $context)) { - $dump = $context['dump']; - if (is_array($dump)) { - $dump = print_r($dump, true); - } - } - $this->erp->LogFile($message, $dump, $module, $action, $function); - } -} diff --git a/classes/Components/Mailer/Wrapper/MemoryLogger.php b/classes/Components/Mailer/Wrapper/MemoryLogger.php deleted file mode 100644 index 23bcc693f..000000000 --- a/classes/Components/Mailer/Wrapper/MemoryLogger.php +++ /dev/null @@ -1,20 +0,0 @@ -logmessages[] = $message; - } -} diff --git a/classes/Modules/DocuvitaSolutionsApi/DocuvitaSolutionsApiService.php b/classes/Modules/DocuvitaSolutionsApi/DocuvitaSolutionsApiService.php index 837d826b0..00ec66764 100644 --- a/classes/Modules/DocuvitaSolutionsApi/DocuvitaSolutionsApiService.php +++ b/classes/Modules/DocuvitaSolutionsApi/DocuvitaSolutionsApiService.php @@ -5,6 +5,7 @@ use Application; use CURLFile; +use Psr\Log\LoggerInterface; use RuntimeException; use Xentral\Components\Database\Database; use Xentral\Core\DependencyInjection\ServiceContainer; @@ -22,6 +23,8 @@ class DocuvitaSolutionsApiService * @var Database */ private $db; + + private LoggerInterface $logger; /** * @var string */ @@ -132,6 +135,7 @@ public function __construct( $this->app = $app; $this->container = $app->Container; $this->db = $this->container->get('Database'); + $this->logger = $this->container->get('Logger'); $this->username = $username; $this->password = $password; @@ -234,9 +238,9 @@ public function sendFileAsString($fileName, $content, $uploadGuid) return json_decode($response); } - private function log($message, $dump = '') + private function log($message, array $dump = null) { - $this->app->erp->LogFile($message, $dump, 'docuvitasolutions'); + $this->logger->info($message, $dump); } /** @@ -257,7 +261,7 @@ public function export() $this->generateVerbindlichkeitTemplates(), ]; if (!empty($this->missingFiles)) { - $this->log("missing files", implode("\n", $this->missingFiles)); + $this->log("missing files", $this->missingFiles); } for ($i = 0, $count = count($dataObjects); $i < $count; $i++) { if (count($dataObjects[$i]->getQueryResult()) === 0) { diff --git a/classes/Modules/EtsyApi/Credential/AbstractCredentialData.php b/classes/Modules/EtsyApi/Credential/AbstractCredentialData.php deleted file mode 100644 index 141814481..000000000 --- a/classes/Modules/EtsyApi/Credential/AbstractCredentialData.php +++ /dev/null @@ -1,98 +0,0 @@ -identifier = $identifier; - $this->secret = $secret; - } - - /** - * @param string $string - * - * @throws CredentialException - * - * @return static - */ - public static function fromString($string) - { - $base64Raw = strtr($string, '-_', '+/'); - $jsonString = base64_decode($base64Raw, true); - - $data = json_decode($jsonString, true); - - if (!isset($data['class'])) { - throw new CredentialException('Can not create credentials object from string. Class property is missing.'); - } - if ($data['class'] !== static::class) { - throw new CredentialException('Can not create credentials object from string. Class does not match.'); - } - - return static::fromArray($data); - } - - /** - * @param array $credentials - * - * @return static - */ - public static function fromArray(array $credentials) - { - return new static($credentials['identifier'], $credentials['secret']); - } - - /** - * @return string - */ - public function getIdentifier() - { - return $this->identifier; - } - - /** - * @return string - */ - public function getSecret() - { - return $this->secret; - } - - /** - * @return string - */ - public function toString() - { - $data = [ - 'identifier' => $this->identifier, - 'secret' => $this->secret, - 'class' => static::class, - ]; - $base64Raw = base64_encode(json_encode($data, JSON_HEX_TAG| JSON_HEX_AMP | JSON_HEX_APOS | JSON_HEX_QUOT)); - $base64Url = strtr($base64Raw, '+/', '-_'); - - return rtrim($base64Url, '='); - } - - /** - * @return string - */ - public function __toString() - { - return $this->toString(); - } -} diff --git a/classes/Modules/EtsyApi/Credential/ClientCredentialData.php b/classes/Modules/EtsyApi/Credential/ClientCredentialData.php deleted file mode 100644 index 22881d3c5..000000000 --- a/classes/Modules/EtsyApi/Credential/ClientCredentialData.php +++ /dev/null @@ -1,7 +0,0 @@ -server = new Y0lkEtsy([ - 'identifier' => $clientCredentials->getIdentifier(), - 'secret' => $clientCredentials->getSecret(), - 'callback_uri' => $callbackUri, - 'scope' => implode(' ', $scopes), - ]); - } catch (Exception $exception) { - throw new EtsyOAuthException($exception->getMessage(), $exception->getCode(), $exception); - } - } - - /** - * @throws EtsyOAuthException - * - * @return TemporaryCredentialData - */ - public function getTemporaryCredentials() - { - try { - /** @var LeagueTemporaryCredentials $temp */ - $temp = $this->server->getTemporaryCredentials(); - } catch (Exception $exception) { - throw new EtsyOAuthException($exception->getMessage(), $exception->getCode(), $exception); - } - - return new TemporaryCredentialData( - $temp->getIdentifier(), - $temp->getSecret() - ); - } - - /** - * @param TemporaryCredentialData $temporaryCredentials - * @param string $temporaryIdentifier - * @param string $verifier - * - * @throws EtsyOAuthException - * - * @return TokenCredentialData - */ - public function getTokenCredentials(TemporaryCredentialData $temporaryCredentials, $temporaryIdentifier, $verifier) - { - $leagueTemp = new LeagueTemporaryCredentials(); - $leagueTemp->setIdentifier($temporaryCredentials->getIdentifier()); - $leagueTemp->setSecret($temporaryCredentials->getSecret()); - - try { - $leagueToken = $this->server->getTokenCredentials($leagueTemp, $temporaryIdentifier, $verifier); - $tokenCredentials = new TokenCredentialData($leagueToken->getIdentifier(), $leagueToken->getSecret()); - } catch (Exception $exception) { - throw new EtsyOAuthException($exception->getMessage(), $exception->getCode(), $exception); - } - - return $tokenCredentials; - } - - /** - * @param TemporaryCredentialData $temporaryCredentials - * - * @throws EtsyOAuthException - * - * @return void - */ - public function authorize(TemporaryCredentialData $temporaryCredentials) - { - $leagueCredentials = new LeagueTemporaryCredentials(); - $leagueCredentials->setIdentifier($temporaryCredentials->getIdentifier()); - $leagueCredentials->setSecret($temporaryCredentials->getSecret()); - - try { - $this->server->authorize($leagueCredentials); - } catch (Exception $exception) { - throw new EtsyOAuthException($exception->getMessage(), $exception->getCode(), $exception); - } - } - - /** - * @param TemporaryCredentialData $temporaryCredentials - * - * @throws EtsyOAuthException - * - * @return string - */ - public function getAuthorizationUrl(TemporaryCredentialData $temporaryCredentials) - { - $leagueCredentials = new LeagueTemporaryCredentials(); - $leagueCredentials->setIdentifier($temporaryCredentials->getIdentifier()); - $leagueCredentials->setSecret($temporaryCredentials->getSecret()); - - try { - return $this->server->getAuthorizationUrl($leagueCredentials); - } catch (Exception $exception) { - throw new EtsyOAuthException($exception->getMessage(), $exception->getCode(), $exception); - } - } - - /** - * @param TokenCredentialData $tokenCredentials - * @param string $httpMethod - * @param string $url - * @param array $bodyParams - * - * @throws EtsyOAuthException - * - * @return array - */ - public function getHeaders(TokenCredentialData $tokenCredentials, $httpMethod, $url, array $bodyParams = []) - { - $leagueCredentials = new LeagueTokenCredentials(); - $leagueCredentials->setIdentifier($tokenCredentials->getIdentifier()); - $leagueCredentials->setSecret($tokenCredentials->getSecret()); - - try { - return $this->server->getHeaders($leagueCredentials, $httpMethod, $url, $bodyParams); - } catch (Exception $exception) { - throw new EtsyOAuthException($exception->getMessage(), $exception->getCode(), $exception); - } - } -} diff --git a/classes/Modules/EtsyApi/Exception/CredentialException.php b/classes/Modules/EtsyApi/Exception/CredentialException.php deleted file mode 100644 index b6b86e731..000000000 --- a/classes/Modules/EtsyApi/Exception/CredentialException.php +++ /dev/null @@ -1,9 +0,0 @@ - 12345678, - 'products' => '[{"product_id":98765431,"sku":"700001","property_values":[],"offerings":[{"offering_id":999888777,"price":{"amount":7900,"divisor":100,"currency_code":"EUR","currency_formatted_short":"\u20ac79.00","currency_formatted_long":"\u20ac79.00 EUR","currency_formatted_raw":"79.00"},"quantity":1,"is_enabled":1,"is_deleted":0}],"is_deleted":0}]', - ]; - - $headers = $etsyHelper->getHeaders($tokenCredentials, $method, $apiUrl, $data); - $client = new GuzzleHttp\Client(); - $response = $client->put($apiUrl, [ - 'headers' => $headers, - 'form_params' => $data, - ]); - - if ($response->getStatusCode() === 200) { - die('Erfolg'); - } - -} elseif (isset($_GET['oauth_token']) && isset($_GET['oauth_verifier'])) { - - /* - * SCHRITT 2 - */ - - if (!isset($_SESSION['temporary_credentials'])) { - die('No temporary credentials.'); - } - - // Temporary-Credentials aus Schritt 1 wiederherstellen - $temporaryCredentials = TemporaryCredentialData::fromString($_SESSION['temporary_credentials']); - - // Teil 3 der OAuth 1.0 Authentifizierung: Token-Credentials (früher Access-Tokens) abholen - $tokenCredentials = $etsyHelper->getTokenCredentials($temporaryCredentials, $_GET['oauth_token'], $_GET['oauth_verifier']); - - // Temporary-Credentials löschen und Token-Credentials in Session speichern - unset($_SESSION['temporary_credentials']); - $_SESSION['token_credentials'] = $tokenCredentials->toString(); - session_write_close(); - - // Benutzer zu Schritt 3 umleiten - header('Location: http://example.com/somefile?user=user'); - exit; - -} else { - - /* - * SCHRITT 1 - */ - - // Teil 1 der OAuth 1.0 Authentifizierung: Temporary-Credentials abholen - // Diese identifizieren uns als Client beim Server - $temporaryCredentials = $etsyHelper->getTemporaryCredentials(); - - // Credentials in Session speichern; für übernächsten Schritt - $_SESSION['temporary_credentials'] = $temporaryCredentials->toString(); - session_write_close(); - - // Teil 2 der OAuth 1.0 Authentifizierung: Resource Owner auf die Login-Seite umleiten - $redirectUrl = $etsyHelper->getAuthorizationUrl($temporaryCredentials); - header('Location: ' . $redirectUrl); - exit; -} -``` diff --git a/classes/Modules/Log/Bootstrap.php b/classes/Modules/Log/Bootstrap.php index 8bc5476bd..7ee6bdd4b 100644 --- a/classes/Modules/Log/Bootstrap.php +++ b/classes/Modules/Log/Bootstrap.php @@ -52,19 +52,6 @@ public static function onInitDatabaseLogGateway(ServiceContainer $container): Da */ public static function onInitLoggerConfigService(ServiceContainer $container): LoggerConfigService { - return new LoggerConfigService(self::onInitCompanyConfigWrapper($container)); - } - - /** - * @param ContainerInterface $container - * - * @return CompanyConfigWrapper - */ - private static function onInitCompanyConfigWrapper(ContainerInterface $container): CompanyConfigWrapper - { - /** @var \ApplicationCore $app */ - $app = $container->get('LegacyApplication'); - - return new CompanyConfigWrapper($app->erp); + return new LoggerConfigService($container->get('SystemConfigModule')); } } diff --git a/classes/Modules/Log/Service/LoggerConfigService.php b/classes/Modules/Log/Service/LoggerConfigService.php index 4f6accb2f..6d28a8080 100644 --- a/classes/Modules/Log/Service/LoggerConfigService.php +++ b/classes/Modules/Log/Service/LoggerConfigService.php @@ -7,23 +7,15 @@ use Xentral\Components\Logger\LogLevel; use Xentral\Modules\Log\Exception\InvalidArgumentException; use Xentral\Modules\Log\Exception\InvalidLoglevelException; -use Xentral\Modules\Log\Wrapper\CompanyConfigWrapper; +use Xentral\Modules\SystemConfig\SystemConfigModule; final class LoggerConfigService { - /** @var string CONFIG_KEY_LEVEL */ - private const CONFIG_KEY_LEVEL = 'logfile_logging_level'; + private const NAMESPACE = 'logger'; + private const CONFIG_KEY_LEVEL = 'log_level'; - /** @var CompanyConfigWrapper $db */ - private $companyConfig; - - /** - * @param CompanyConfigWrapper $companyConfig - */ - public function __construct(CompanyConfigWrapper $companyConfig) - { - $this->companyConfig = $companyConfig; - } + public function __construct(private readonly SystemConfigModule $systemConfigModule) + { } /** * @throws InvalidLoglevelException @@ -32,7 +24,12 @@ public function __construct(CompanyConfigWrapper $companyConfig) */ public function getLogLevel(): string { - $level = (string)$this->companyConfig->get(self::CONFIG_KEY_LEVEL); + $level = $this->systemConfigModule->tryGetValue(self::NAMESPACE, self::CONFIG_KEY_LEVEL); + if ($level === null) { + $level = $this->systemConfigModule->tryGetLegacyValue('logfile_logging_level'); + $level ??= LogLevel::ERROR; + $this->systemConfigModule->setValue(self::NAMESPACE, self::CONFIG_KEY_LEVEL, $level); + } $level = strtolower($level); if (!$this->isAllowedLogLevel($level)) { throw new InvalidLoglevelException(sprintf('Unrecognized Loglevel "%s".', $level)); @@ -53,7 +50,7 @@ public function setLogLevel(string $level): void if (!$this->isAllowedLogLevel($level)) { throw new InvalidArgumentException(sprintf('Unrecognised Loglevel "%s"', $level)); } - $this->companyConfig->set(self::CONFIG_KEY_LEVEL, $level); + $this->systemConfigModule->setValue(self::NAMESPACE, self::CONFIG_KEY_LEVEL, $level); } /** diff --git a/classes/Modules/Log/Wrapper/CompanyConfigWrapper.php b/classes/Modules/Log/Wrapper/CompanyConfigWrapper.php deleted file mode 100644 index e8823cc87..000000000 --- a/classes/Modules/Log/Wrapper/CompanyConfigWrapper.php +++ /dev/null @@ -1,45 +0,0 @@ -erp = $erp; - } - - /** - * @param string $name - * - * @return mixed - */ - public function get(string $name) - { - return $this->erp->GetKonfiguration($name); - } - - /** - * @param string $name - * @param mixed $value - * - * @return void - */ - public function set(string $name, $value) - { - $this->erp->SetKonfigurationValue($name, $value); - } -} diff --git a/composer.json b/composer.json index 06e2a500e..c56297207 100644 --- a/composer.json +++ b/composer.json @@ -1,9 +1,12 @@ { "require": { "php": "^8.1", - "ext-gd": "*", "ext-curl": "*", + "ext-gd": "*", + "ext-ldap": "*", + "ext-mysqli": "*", "ext-soap": "*", + "ext-zip": "*", "aura/sqlquery": "2.7.1", "aws/aws-sdk-php": "3.175.2", "ezyang/htmlpurifier": "v4.13.0", @@ -12,7 +15,6 @@ "laminas/laminas-mail": "^2.12.5", "league/color-extractor": "0.3.2", "league/flysystem": "^1.0.70", - "league/oauth1-client": "v1.9.0", "lfkeitel/phptotp": "^1.0", "nikic/fast-route": "^1.3", "phpmailer/phpmailer": "v6.3.0", @@ -22,8 +24,7 @@ "smarty/smarty": "v3.1.39", "swiss-payment-slip/swiss-payment-slip": "0.13.0 as 0.11.1", "swiss-payment-slip/swiss-payment-slip-fpdf": "0.6.0", - "tecnickcom/tcpdf": "6.3.5", - "y0lk/oauth1-etsy": "1.1.0" + "tecnickcom/tcpdf": "6.3.5" }, "replace": { "itbz/fpdf": "*" @@ -32,12 +33,43 @@ "psr-4": { "Xentral\\": "classes" }, - "classmap": ["www/lib/versandarten/"] + "classmap": [ + "conf/", + "phpwf/", + "www/docscan/", + "www/widgets/", + "www/lib/versandarten/", + "www/lib/class.navigation_edit.php", + "www/lib/class.xtea.php", + "www/lib/class.ustid.php", + "www/plugins/class.ics.php", + "www/lib/PrinterBase.php", + "www/lib/TransferBase.php", + "www/lib/ShopimporterBase.php", + "www/lib/imap.inc.php", + "www/lib/class.printer.php", + "www/lib/class.image.php", + "www/lib/class.location.php", + "www/lib/class.remote.php", + "www/lib/class.erpapi.php", + "www/eproosystem.php", + "www/lib/class.httpclient.php", + "www/lib/pdf/fpdf_final.php", + "www/lib/dokumente/", + "www/plugins/class.wikiparser.php", + "www/plugins/php-print.php", + "www/plugins/liveimport/LiveimportBase.php", + "www/lib/class.aes2.php", + "www/lib/pdf/fpdf_3.php" + ] }, "config": { "platform": { "php": "8.1", - "ext-gd": "8.1" + "ext-gd": "8.1", + "ext-ldap": "8.1", + "ext-mysqli": "8.1", + "ext-soap": "8.1" }, "optimize-autoloader": true } diff --git a/composer.lock b/composer.lock index 85d34929c..4e9c03734 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "229fd9b44bc0380415380fe519e53dfb", + "content-hash": "8803960c5ca6017b3869691f40be7ad7", "packages": [ { "name": "aura/sqlquery", @@ -676,20 +676,20 @@ }, { "name": "laminas/laminas-loader", - "version": "2.11.1", + "version": "2.12.0", "source": { "type": "git", "url": "https://github.com/laminas/laminas-loader.git", - "reference": "c507d5eccb969f7208434e3980680a1f6c0b1d8d" + "reference": "ec8cee33fb254ee4d9c8e8908c870e5c797e1272" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laminas/laminas-loader/zipball/c507d5eccb969f7208434e3980680a1f6c0b1d8d", - "reference": "c507d5eccb969f7208434e3980680a1f6c0b1d8d", + "url": "https://api.github.com/repos/laminas/laminas-loader/zipball/ec8cee33fb254ee4d9c8e8908c870e5c797e1272", + "reference": "ec8cee33fb254ee4d9c8e8908c870e5c797e1272", "shasum": "" }, "require": { - "php": "~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0" + "php": "^8.0.0" }, "conflict": { "zendframework/zend-loader": "*" @@ -729,7 +729,7 @@ } ], "abandoned": true, - "time": "2024-12-05T14:43:32+00:00" + "time": "2025-12-30T11:30:39+00:00" }, { "name": "laminas/laminas-mail", @@ -871,16 +871,16 @@ }, { "name": "laminas/laminas-servicemanager", - "version": "3.23.0", + "version": "3.23.1", "source": { "type": "git", "url": "https://github.com/laminas/laminas-servicemanager.git", - "reference": "a8640182b892b99767d54404d19c5c3b3699f79b" + "reference": "06594db3a644447521eace9b5efdb12dc8446a33" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laminas/laminas-servicemanager/zipball/a8640182b892b99767d54404d19c5c3b3699f79b", - "reference": "a8640182b892b99767d54404d19c5c3b3699f79b", + "url": "https://api.github.com/repos/laminas/laminas-servicemanager/zipball/06594db3a644447521eace9b5efdb12dc8446a33", + "reference": "06594db3a644447521eace9b5efdb12dc8446a33", "shasum": "" }, "require": { @@ -903,12 +903,12 @@ "require-dev": { "composer/package-versions-deprecated": "^1.11.99.5", "friendsofphp/proxy-manager-lts": "^1.0.18", - "laminas/laminas-code": "^4.14.0", + "laminas/laminas-code": "^4.16.0", "laminas/laminas-coding-standard": "~2.5.0", "laminas/laminas-container-config-test": "^0.8", "mikey179/vfsstream": "^1.6.12", - "phpbench/phpbench": "^1.3.1", - "phpunit/phpunit": "^10.5.36", + "phpbench/phpbench": "^1.4.1", + "phpunit/phpunit": "^10.5.51", "psalm/plugin-phpunit": "^0.18.4", "vimeo/psalm": "^5.26.1" }, @@ -957,7 +957,7 @@ "type": "community_bridge" } ], - "time": "2024-10-28T21:32:16+00:00" + "time": "2025-08-12T08:44:02+00:00" }, { "name": "laminas/laminas-stdlib", @@ -1020,16 +1020,16 @@ }, { "name": "laminas/laminas-validator", - "version": "2.64.2", + "version": "2.64.4", "source": { "type": "git", "url": "https://github.com/laminas/laminas-validator.git", - "reference": "771e504760448ac7af660710237ceb93be602e08" + "reference": "e2e6631f599a9b0db1e23adb633c09a2f0c68bed" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laminas/laminas-validator/zipball/771e504760448ac7af660710237ceb93be602e08", - "reference": "771e504760448ac7af660710237ceb93be602e08", + "url": "https://api.github.com/repos/laminas/laminas-validator/zipball/e2e6631f599a9b0db1e23adb633c09a2f0c68bed", + "reference": "e2e6631f599a9b0db1e23adb633c09a2f0c68bed", "shasum": "" }, "require": { @@ -1100,7 +1100,7 @@ "type": "community_bridge" } ], - "time": "2024-11-26T21:29:17+00:00" + "time": "2025-06-16T14:38:00+00:00" }, { "name": "league/color-extractor", @@ -1310,81 +1310,6 @@ ], "time": "2024-09-21T08:32:55+00:00" }, - { - "name": "league/oauth1-client", - "version": "v1.9.0", - "source": { - "type": "git", - "url": "https://github.com/thephpleague/oauth1-client.git", - "reference": "1e7e6be2dc543bf466236fb171e5b20e1b06aee6" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/thephpleague/oauth1-client/zipball/1e7e6be2dc543bf466236fb171e5b20e1b06aee6", - "reference": "1e7e6be2dc543bf466236fb171e5b20e1b06aee6", - "shasum": "" - }, - "require": { - "ext-json": "*", - "ext-openssl": "*", - "guzzlehttp/guzzle": "^6.0|^7.0", - "php": ">=7.1||>=8.0" - }, - "require-dev": { - "ext-simplexml": "*", - "friendsofphp/php-cs-fixer": "^2.17", - "mockery/mockery": "^1.3.3", - "phpstan/phpstan": "^0.12.42", - "phpunit/phpunit": "^7.5||9.5" - }, - "suggest": { - "ext-simplexml": "For decoding XML-based responses." - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0-dev", - "dev-develop": "2.0-dev" - } - }, - "autoload": { - "psr-4": { - "League\\OAuth1\\Client\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Ben Corlett", - "email": "bencorlett@me.com", - "homepage": "http://www.webcomm.com.au", - "role": "Developer" - } - ], - "description": "OAuth 1.0 Client Library", - "keywords": [ - "Authentication", - "SSO", - "authorization", - "bitbucket", - "identity", - "idp", - "oauth", - "oauth1", - "single sign on", - "trello", - "tumblr", - "twitter" - ], - "support": { - "issues": "https://github.com/thephpleague/oauth1-client/issues", - "source": "https://github.com/thephpleague/oauth1-client/tree/v1.9.0" - }, - "time": "2021-01-20T01:40:53+00:00" - }, { "name": "lfkeitel/phptotp", "version": "v1.1.0", @@ -2561,16 +2486,16 @@ }, { "name": "symfony/polyfill-intl-idn", - "version": "v1.31.0", + "version": "v1.33.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-idn.git", - "reference": "c36586dcf89a12315939e00ec9b4474adcb1d773" + "reference": "9614ac4d8061dc257ecc64cba1b140873dce8ad3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/c36586dcf89a12315939e00ec9b4474adcb1d773", - "reference": "c36586dcf89a12315939e00ec9b4474adcb1d773", + "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/9614ac4d8061dc257ecc64cba1b140873dce8ad3", + "reference": "9614ac4d8061dc257ecc64cba1b140873dce8ad3", "shasum": "" }, "require": { @@ -2624,7 +2549,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.31.0" + "source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.33.0" }, "funding": [ { @@ -2635,16 +2560,20 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2024-09-09T11:45:10+00:00" + "time": "2024-09-10T14:38:51+00:00" }, { "name": "symfony/polyfill-intl-normalizer", - "version": "v1.31.0", + "version": "v1.33.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-normalizer.git", @@ -2705,7 +2634,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.31.0" + "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.33.0" }, "funding": [ { @@ -2716,6 +2645,10 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" @@ -2725,19 +2658,20 @@ }, { "name": "symfony/polyfill-mbstring", - "version": "v1.31.0", + "version": "v1.33.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "85181ba99b2345b0ef10ce42ecac37612d9fd341" + "reference": "6d857f4d76bd4b343eac26d6b539585d2bc56493" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/85181ba99b2345b0ef10ce42ecac37612d9fd341", - "reference": "85181ba99b2345b0ef10ce42ecac37612d9fd341", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/6d857f4d76bd4b343eac26d6b539585d2bc56493", + "reference": "6d857f4d76bd4b343eac26d6b539585d2bc56493", "shasum": "" }, "require": { + "ext-iconv": "*", "php": ">=7.2" }, "provide": { @@ -2785,7 +2719,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.31.0" + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.33.0" }, "funding": [ { @@ -2796,12 +2730,16 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2024-09-09T11:45:10+00:00" + "time": "2024-12-23T08:48:59+00:00" }, { "name": "tecnickcom/tcpdf", @@ -2871,28 +2809,28 @@ }, { "name": "webmozart/assert", - "version": "1.11.0", + "version": "1.12.1", "source": { "type": "git", "url": "https://github.com/webmozarts/assert.git", - "reference": "11cb2199493b2f8a3b53e7f19068fc6aac760991" + "reference": "9be6926d8b485f55b9229203f962b51ed377ba68" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/webmozarts/assert/zipball/11cb2199493b2f8a3b53e7f19068fc6aac760991", - "reference": "11cb2199493b2f8a3b53e7f19068fc6aac760991", + "url": "https://api.github.com/repos/webmozarts/assert/zipball/9be6926d8b485f55b9229203f962b51ed377ba68", + "reference": "9be6926d8b485f55b9229203f962b51ed377ba68", "shasum": "" }, "require": { "ext-ctype": "*", + "ext-date": "*", + "ext-filter": "*", "php": "^7.2 || ^8.0" }, - "conflict": { - "phpstan/phpstan": "<0.12.20", - "vimeo/psalm": "<4.6.1 || 4.6.2" - }, - "require-dev": { - "phpunit/phpunit": "^8.5.13" + "suggest": { + "ext-intl": "", + "ext-simplexml": "", + "ext-spl": "" }, "type": "library", "extra": { @@ -2923,62 +2861,9 @@ ], "support": { "issues": "https://github.com/webmozarts/assert/issues", - "source": "https://github.com/webmozarts/assert/tree/1.11.0" - }, - "time": "2022-06-03T18:03:27+00:00" - }, - { - "name": "y0lk/oauth1-etsy", - "version": "1.1.0", - "source": { - "type": "git", - "url": "https://github.com/Y0lk/oauth1-etsy.git", - "reference": "3fef9d03787e01a72ef19cdcbbc243c166a5d425" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/Y0lk/oauth1-etsy/zipball/3fef9d03787e01a72ef19cdcbbc243c166a5d425", - "reference": "3fef9d03787e01a72ef19cdcbbc243c166a5d425", - "shasum": "" - }, - "require": { - "league/oauth1-client": "^1.7.0", - "php": ">=7.0" - }, - "require-dev": { - "phpunit/phpunit": "~6.0" - }, - "type": "library", - "autoload": { - "psr-4": { - "Y0lk\\OAuth1\\Client\\Server\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Y0lk", - "email": "gabriel@inkrebit.com", - "homepage": "https://github.com/Y0lk" - } - ], - "description": "Etsy API OAuth 1.0 Client Provider for The PHP League OAuth1-Client", - "keywords": [ - "authorisation", - "authorization", - "client", - "etsy", - "oauth", - "oauth1" - ], - "support": { - "issues": "https://github.com/Y0lk/oauth1-etsy/issues", - "source": "https://github.com/Y0lk/oauth1-etsy/tree/1.1.0" + "source": "https://github.com/webmozarts/assert/tree/1.12.1" }, - "time": "2021-02-03T16:15:30+00:00" + "time": "2025-10-29T15:56:20+00:00" } ], "packages-dev": [], @@ -2996,12 +2881,20 @@ "prefer-lowest": false, "platform": { "php": "^8.1", - "ext-gd": "*" + "ext-curl": "*", + "ext-gd": "*", + "ext-ldap": "*", + "ext-mysqli": "*", + "ext-soap": "*", + "ext-zip": "*" }, "platform-dev": {}, "platform-overrides": { "php": "8.1", - "ext-gd": "8.1" + "ext-gd": "8.1", + "ext-ldap": "8.1", + "ext-mysqli": "8.1", + "ext-soap": "8.1" }, "plugin-api-version": "2.6.0" } diff --git a/conf/main.conf.php b/conf/main.conf.php index b9d2aa84a..aa10d5f20 100644 --- a/conf/main.conf.php +++ b/conf/main.conf.php @@ -1,26 +1,22 @@ updateHost = getenv('XENTRAL_UPDATE_HOST') ?: 'removed.upgrade.host'; - - include("user.inc.php"); + include('user.inc.php'); - if (!isset($this->WFdbport) || empty($this->WFdbport)) { + if (empty($this->WFdbport)) { $this->WFdbport = 3306; } @@ -28,7 +24,6 @@ public function __construct() $this->WFconf['defaultpage'] = 'adresse'; $this->WFconf['defaultpageaction'] = 'list'; $this->WFconf['defaulttheme'] = 'new'; - //$this->WFconf['defaulttheme'] = 'default_redesign'; $this->WFconf['defaultgroup'] = 'web'; // allow that cols where dynamically added so structure diff --git a/conf/main.conf.php.tpl b/conf/main.conf.php.tpl index dd1d1cc0a..74edf92b4 100644 --- a/conf/main.conf.php.tpl +++ b/conf/main.conf.php.tpl @@ -1,32 +1,28 @@ WFdbport) || empty($this->WFdbport)) { - $this->WFdbport = 3306; + if (empty($this->WFdbport)) { + $this->WFdbport = 3306; } // define defaults $this->WFconf['defaultpage'] = 'adresse'; $this->WFconf['defaultpageaction'] = 'list'; $this->WFconf['defaulttheme'] = 'new'; - //$this->WFconf['defaulttheme'] = 'default_redesign'; $this->WFconf['defaultgroup'] = 'web'; // allow that cols where dynamically added so structure diff --git a/cronjobs/amazon.php b/cronjobs/amazon.php index 3a0faac09..f0084af0b 100644 --- a/cronjobs/amazon.php +++ b/cronjobs/amazon.php @@ -134,7 +134,8 @@ function GetUsername() $app->remote = $remote; } $app->Secure = new Secure($app); - +/** @var \Psr\Log\LoggerInterface $logger */ +$logger = $app->Container->get('Logger'); $firmendatenid = $app->DB->Select("SELECT MAX(id) FROM firmendaten LIMIT 1"); @@ -153,7 +154,7 @@ function GetUsername() ); return; } -$app->erp->LogFile('Starte Amazon Cronjob'); +$logger->info('Starte Amazon Cronjob'); $app->DB->Update( "UPDATE prozessstarter SET letzteausfuerhung = now(), mutex = 1, mutexcounter = 0 WHERE aktiv = 1 AND parameter = 'amazon'" ); @@ -186,5 +187,5 @@ function GetUsername() "UPDATE prozessstarter SET letzteausfuerhung = now(), mutex = 0, mutexcounter = 0 WHERE aktiv = 1 AND parameter = 'amazon'" ); -$app->erp->LogFile('Ende Amazon Cronjob'); +$logger->info('Ende Amazon Cronjob'); diff --git a/cronjobs/api_uebertragungen.php b/cronjobs/api_uebertragungen.php index 0bdd81712..b49684c85 100644 --- a/cronjobs/api_uebertragungen.php +++ b/cronjobs/api_uebertragungen.php @@ -394,6 +394,8 @@ public function GetLaender() //ENDE $app->FormHandler = new FormHandler($app); +/** @var \Psr\Log\LoggerInterface $logger */ +$logger = $app->Container->get('Logger'); if(!$app->erp->ModulVorhanden('uebertragungen')) { return; @@ -458,7 +460,7 @@ public function GetLaender() $app->erp->ProzessstarterStatus('Artikel übertragen '.$uebertragung_account['bezeichnung']); $countTransferAricle = $uebertragungen->transferAricle($uebertragung_account); if($countTransferAricle > 0) { - $app->erp->LogFile($uebertragung_account['bezeichnung'].': '.$countTransferAricle.' Artikel uebertragen'); + $logger->info($uebertragung_account['bezeichnung'].': '.$countTransferAricle.' Artikel uebertragen'); } $app->DB->Update( "UPDATE prozessstarter SET letzteausfuerhung=NOW(), mutex = 1,mutexcounter=0 WHERE parameter = 'api_uebertragungen'" @@ -470,7 +472,7 @@ public function GetLaender() foreach($uebertragungen_accounts as $uebertragungen_account) { $uebertragungen->datei_id = null; if($uebertragungen->createSaleReport($uebertragungen_account)) { - $app->erp->LogFile($uebertragung_account['bezeichnung'].': SaleReport uebertragen'); + $logger->info($uebertragung_account['bezeichnung'].': SaleReport uebertragen'); } $uebertragungen->datei_id = null; } @@ -540,7 +542,7 @@ public function GetLaender() } } catch(Exception $e) { - $app->erp->LogFile( + $logger->error('Parse file error', [ 'ParseFileError'=>$e->getMessage(), 'Module'=>$uebertragung_account['xml_pdf'] diff --git a/cronjobs/autoversand_manuell.php b/cronjobs/autoversand_manuell.php index 76a70de59..b781c3794 100644 --- a/cronjobs/autoversand_manuell.php +++ b/cronjobs/autoversand_manuell.php @@ -81,7 +81,7 @@ function file_append($filename,$text) { $objAuftrag = $app->loadModule('auftrag'); if($objAuftrag == null || !method_exists($objAuftrag, 'AuftragVersand')) { - $app->erp->LogFile($cronjobname." failed. Error while loading module 'auftrag'."); + $app->Container->get('Logger')->error($cronjobname." failed. Error while loading module 'auftrag'."); exit; } diff --git a/cronjobs/belegeimport.php b/cronjobs/belegeimport.php index 272f9e6de..871fe3f2c 100644 --- a/cronjobs/belegeimport.php +++ b/cronjobs/belegeimport.php @@ -1,7 +1,7 @@ erp->MailSend($fromMail,$fromName,$toMail,$toName,$subject,$text,"","",false,"","", true); - $app->erp->LogFile("Mailed ".$subject." to ".$toMail); + $app->Container->get('Logger')->info("Mailed ".$subject." to ".$toMail); } diff --git a/cronjobs/command.php b/cronjobs/command.php index 530dcb102..65934b6f9 100644 --- a/cronjobs/command.php +++ b/cronjobs/command.php @@ -19,7 +19,6 @@ } define('FROMSTARTER2', $fromstarter2 > 0); -require_once dirname(__DIR__) . '/xentral_autoloader.php'; require_once dirname(__DIR__) . '/vendor/autoload.php'; @@ -68,6 +67,8 @@ class app_t extends ApplicationCore { $phpinfo = ob_get_contents(); ob_end_clean(); $app->erp->SetKonfigurationValue('system_cronjob_phpinfo', $app->DB->real_escape_string($phpinfo)); +/** @var \Psr\Log\LoggerInterface $logger */ +$logger = $app->Container->get('Logger'); if (method_exists($app->erp, 'CheckCronjob') && !$app->erp->CheckCronjob()) { $app->DB->Close(); @@ -81,7 +82,7 @@ class app_t extends ApplicationCore { $systemHealthService = $app->Container->get('SystemHealthService'); if ($DEBUG) { - $app->erp->LogFile('starter.php'); + $logger->debug('starter.php'); } $task = $app->DB->SelectArr( @@ -110,7 +111,7 @@ class app_t extends ApplicationCore { } } } catch (Exception $e) { - $app->erp->LogFile('can not evaluate disk space for cronjob: ' . $e->getMessage()); + $logger->warning('can not evaluate disk space for cronjob: ' . $e->getMessage()); } if ($fromstarter2) { @@ -118,7 +119,7 @@ class app_t extends ApplicationCore { } else { $run = 0; if ($DEBUG) { - $app->erp->LogFile('Task: ' . $task[$task_index]['bezeichnung'] . ' ' . $task[$task_index]['art']); + $logger->debug('Task: ' . $task[$task_index]['bezeichnung'] . ' ' . $task[$task_index]['art']); } if ($task[$task_index]['art'] === 'periodisch') { @@ -173,7 +174,7 @@ class app_t extends ApplicationCore { $app->erp->setCronjobRunning(CRONJOBUID, $task[$task_index], true); } if ($DEBUG) { - $app->erp->LogFile('Prozessstarter ' . $task[$task_index]['parameter']); + $logger->debug('Prozessstarter ' . $task[$task_index]['parameter']); } //update letzte ausfuerhung $app->DB->Update( @@ -221,14 +222,14 @@ class app_t extends ApplicationCore { $app->erp->ProzessstarterStatus('abgeschlossen', $task[$task_index]['id']); $app->erp->ProzessstarterStatus('', 0); } catch (Exception $e) { - $app->erp->LogFile( + $logger->error( $app->DB->real_escape_string( 'Prozessstarter Fehler bei Aufruf des Moduls ' . $task[$task_index]['parameter'] . ': ' . $e->getMessage()." Trace: ".$e->GetTraceAsString() ) ); } } else { - $app->erp->LogFile( + $logger->error( $app->DB->real_escape_string( 'Der Prozessstarter ' . $task[$task_index]['parameter'] . ' wurde nicht gefunden' ) diff --git a/cronjobs/ebay_bulkjobs.php b/cronjobs/ebay_bulkjobs.php index 5fe5c9558..d05a02143 100644 --- a/cronjobs/ebay_bulkjobs.php +++ b/cronjobs/ebay_bulkjobs.php @@ -1,9 +1,6 @@ erp = $erp; $app->String = new WawiString(); -$app->erp->LogFile("MLM gestartet"); +$app->Container->get('Logger')->info("MLM gestartet"); $app->printer = new Printer($app); $app->Secure = new Secure($app); diff --git a/cronjobs/folgebestaetigung.php b/cronjobs/folgebestaetigung.php index 910e48961..796f821cf 100644 --- a/cronjobs/folgebestaetigung.php +++ b/cronjobs/folgebestaetigung.php @@ -31,27 +31,29 @@ class app_t { $app->DB = new DB($conf->WFdbhost,$conf->WFdbname,$conf->WFdbuser,$conf->WFdbpass,null,$conf->WFdbport); $erp = new erpAPI($app); $app->erp = $erp; +/** @var \Psr\Log\LoggerInterface $logger */ +$logger = $app->Container->get('Logger'); -$app->erp->LogFile("Folgebestaetigung gestartet"); +$logger->info("Folgebestaetigung gestartet"); $firmendatenid = $app->DB->Select("SELECT MAX(id) FROM firmendaten LIMIT 1"); $app->Secure = new Secure($app); $app->User = new User($app); -$app->erp->LogFile("Folgebestaetigung start AuftraegeBerechnen"); +$logger->info("Folgebestaetigung start AuftraegeBerechnen"); $app->erp->AuftraegeBerechnen(); -$app->erp->LogFile("Folgebestaetigung start Versand"); +$logger->info("Folgebestaetigung start Versand"); $result = $app->DB->SelectArr("SELECT DISTINCT adresse FROM auftrag WHERE status='freigegeben'"); for($i=0;$ierp->LogFile("Folgebestaetigung Adresse ".$result[$i]['adresse']); + $logger->info("Folgebestaetigung Adresse ".$result[$i]['adresse']); $app->erp->Folgebestaetigung($result[$i]['adresse']); } -$app->erp->LogFile("Folgebestaetigung erfolgreich versendet"); +$logger->info("Folgebestaetigung erfolgreich versendet"); //echo "done\r\n"; ?> diff --git a/cronjobs/getarticles.php b/cronjobs/getarticles.php index 7b4464cd1..2cb712059 100644 --- a/cronjobs/getarticles.php +++ b/cronjobs/getarticles.php @@ -98,7 +98,7 @@ public function GetUsername() if(empty($app->User)){ $app->User = new User($app); } -$app->erp->LogFile('Cronjob Artikelimport Start'); +$app->Container->get('Logger')->info('Cronjob Artikelimport Start'); $app->DB->Update("UPDATE prozessstarter SET mutexcounter = mutexcounter + 1 WHERE mutex = 1 AND parameter = 'getarticles' AND aktiv = 1"); if($app->DB->Select("SELECT mutex FROM prozessstarter WHERE parameter = 'getarticles' LIMIT 1") == 1){ @@ -124,5 +124,5 @@ public function GetUsername() $check = $app->DB->Select('SELECT sg.id FROM shopexport_getarticles sg JOIN shopexport s ON sg.shop=s.id LIMIT 1'); } $app->DB->Update("UPDATE prozessstarter SET letzteausfuerhung=NOW(), mutex = 0,mutexcounter=0 WHERE parameter = 'getarticles'"); -$app->erp->LogFile('Cronjob Artikelimport Ende '.$anz.' importiert'); +$app->Container->get('Logger')->info('Cronjob Artikelimport Ende '.$anz.' importiert'); diff --git a/cronjobs/internetmarke.php b/cronjobs/internetmarke.php index d0eeb8454..587d7f2f2 100644 --- a/cronjobs/internetmarke.php +++ b/cronjobs/internetmarke.php @@ -49,7 +49,7 @@ function update($app) //file already the same return false; } - $app->erp->LogFile("Update link: {$link}", '', 'Internetmarke'); + $app->Container->get('Logger')->info("Internetmarke Update link: {$link}"); $written = file_put_contents($csvFile, $csv); @@ -94,22 +94,23 @@ function checkCurlError($curl, $result) } } -// include dirname(__DIR__) . '/xentral_autoloader.php'; $app = new ApplicationCore(); +/** @var \Psr\Log\LoggerInterface $logger */ +$logger = $app->Container->get('Logger'); if(!isInternetmarkeInUse($app)){ - $app->erp->LogFile('Internetmarke not in use', '', 'Internetmarke'); + $logger->info('Internetmarke not in use'); return; } try { if(update($app)){ - $app->erp->LogFile('Successfully updated Internetmarke PPL', '', 'Internetmarke'); + $logger->info('Successfully updated Internetmarke PPL'); }else{ - $app->erp->LogFile('no new PPL', '', 'Internetmarke'); + $logger->info('Internetmarke: no new PPL'); } } catch (RuntimeException $e) { - $app->erp->LogFile('Error updating PPL', $e->getMessage(), 'Internetmarke'); + $logger->error('Internetmarke: Error updating PPL', ['error' => $e->getMessage()]); /** @var Systemhealth $systemHealth */ $systemHealth = $app->loadModule('systemhealth'); $systemHealth->createEntryWithCategoryIfError( diff --git a/cronjobs/lagerzahlen.php b/cronjobs/lagerzahlen.php index bd50830c1..0e999cd1e 100644 --- a/cronjobs/lagerzahlen.php +++ b/cronjobs/lagerzahlen.php @@ -33,7 +33,10 @@ $app->remote = new Remote($app); } } -$app->erp->LogFile("Lagerzahlen-Synchronisation Start"); +/** @var \Psr\Log\LoggerInterface $logger */ +$logger = $app->Container->get('Logger'); + +$logger->info("Lagerzahlen-Synchronisation Start"); //$app->DB->Update("UPDATE artikel SET cache_lagerplatzinhaltmenge='999'"); @@ -47,13 +50,13 @@ if (!$app->DB->Select( "SELECT `id` FROM `prozessstarter` WHERE `mutex` = 0 AND `parameter` = 'lagerzahlen' AND `aktiv` = 1" )) { - $app->erp->LogFile("Lagerzahlen-Synchronisation Ende: Prozessstarter-Mutex nicht bereit"); + $logger->warning("Lagerzahlen-Synchronisation Ende: Prozessstarter-Mutex nicht bereit"); return; } $shops = $app->DB->SelectArr('SELECT * FROM `shopexport` WHERE `aktiv` = 1'); if (empty($shops)) { - $app->erp->LogFile("Lagerzahlen-Synchronisation Ende: Keine aktiven Shops"); + $logger->info("Lagerzahlen-Synchronisation Ende: Keine aktiven Shops"); return; } $shopByIds = []; @@ -98,7 +101,7 @@ ); if (empty($lagerartikel)) { - $app->erp->LogFile("Lagerzahlen-Synchronisation Ende: Keine fälligen Artikel"); + $logger->info("Lagerzahlen-Synchronisation Ende: Keine fälligen Artikel"); return; } @@ -111,7 +114,7 @@ } $clagerartikel = $lagerartikel ? count($lagerartikel) : 0; -$app->erp->LogFile('Lagerzahlen-Synchronisation, Artikel gesamt: ' . $clagerartikel); +$logger->info('Lagerzahlen-Synchronisation, Artikel gesamt: ' . $clagerartikel); foreach ($lagerartikel as $articleCounter => $articleId) { $app->DB->Update( "UPDATE `prozessstarter` @@ -136,7 +139,7 @@ SET `mutex` = 0 , `mutexcounter` = 0, `letzteausfuerhung` = NOW() WHERE `parameter` = 'lagerzahlen' AND `aktiv` = 1" ); - $app->erp->LogFile("Lagerzahlen-Synchronisation Ende: lagerzahlen-Job kann nicht geladen werden"); + $logger->warning("Lagerzahlen-Synchronisation Ende: lagerzahlen-Job kann nicht geladen werden"); return; } // $app->erp->LogFile("Lagerzahlen-Synchronisation: Warte 10 Sekunden"); @@ -171,10 +174,10 @@ } } } catch (Exception $exception) { - $app->erp->LogFile("Lagerzahlen-Synchronisation Exception:" . $app->DB->real_escape_string($exception->getMessage())); + $logger->error("Lagerzahlen-Synchronisation Exception:" . $app->DB->real_escape_string($exception->getMessage())); } } -$app->erp->LogFile("Lagerzahlen-Synchronisation Ende"); +$logger->info("Lagerzahlen-Synchronisation Ende"); diff --git a/cronjobs/mlm.php b/cronjobs/mlm.php index e83e7b9b7..39dcc395b 100644 --- a/cronjobs/mlm.php +++ b/cronjobs/mlm.php @@ -31,8 +31,10 @@ class app_t { $app->DB = new DB($conf->WFdbhost,$conf->WFdbname,$conf->WFdbuser,$conf->WFdbpass,null,$conf->WFdbport); $erp = new erpAPI($app); $app->erp = $erp; +/** @var \Psr\Log\LoggerInterface $logger */ +$logger = $app->Container->get('Logger'); -$app->erp->LogFile("MLM gestartet"); +$logger->info("MLM gestartet"); $app->Secure = new Secure($app); $app->User = new User($app); @@ -61,7 +63,7 @@ class app_t { } } -$app->erp->LogFile("MLM fertig"); +$logger->info("MLM fertig"); $shops = $app->DB->SelectArr("SELECT id from shopexport s where s.geloescht <> '1' AND s.aktiv = '1'"); if($shops) @@ -77,8 +79,8 @@ class app_t { } } } else { - $app->erp->LogFile("Partner Export Shop: Keine Shops"); + $logger->info("Partner Export Shop: Keine Shops"); } -$app->erp->LogFile("Partner Export Shop"); +$logger->info("Partner Export Shop"); ?> diff --git a/cronjobs/onlineshops_tasks.php b/cronjobs/onlineshops_tasks.php index e4e4fd8e3..f4cdf9bb0 100644 --- a/cronjobs/onlineshops_tasks.php +++ b/cronjobs/onlineshops_tasks.php @@ -132,7 +132,7 @@ public function GetUsername() $app->remote->RemoteCommand($onlineShopTask['shop_id'], $command); } catch (Exception $e) { - $app->erp->LogFile(['error'=>$e->getMessage()]); + $app->Container->get('Logger')->error($e->getMessage()); } } diff --git a/cronjobs/pdfarchiv.php b/cronjobs/pdfarchiv.php index 9abada08d..036b3ecd4 100644 --- a/cronjobs/pdfarchiv.php +++ b/cronjobs/pdfarchiv.php @@ -92,7 +92,7 @@ class app_t $erp = new erpAPI($app); $app->erp = $erp; $app->String = new WawiString(); -$app->erp->LogFile("MLM gestartet"); +$app->Container->get('Logger')->info("MLM gestartet"); $app->Secure = new Secure($app); $app->User = new User($app); diff --git a/cronjobs/pdfarchiv_app.php b/cronjobs/pdfarchiv_app.php index 278ef8a72..28872f1e9 100644 --- a/cronjobs/pdfarchiv_app.php +++ b/cronjobs/pdfarchiv_app.php @@ -1,7 +1,5 @@ app = $app; $this->folder = $this->app->Conf->WFuserdata."/pdfarchiv/".$this->app->Conf->WFdbname; + $this->logger = $app->Container->get('Logger'); } /** @@ -550,7 +551,7 @@ protected function run_next() $cgc = gc_collect_cycles(); if($cgc > 0) { - $this->app->erp->LogFile($cgc.' cycles collected'); + $this->logger->info($cgc.' cycles collected'); } } $check = $this->app->DB->Query("SELECT t.id,t.projekt,t.schreibschutz FROM $table t LEFT JOIN pdfarchiv p ON p.table_id = t.id AND p.table_name = '$table' AND CHAR_LENGTH(p.belegnummer) > 2 AND p.belegnummer <> 'SAB' WHERE t.belegnr <> '' AND t.status <> 'angelegt' AND t.status <> 'angelegta' AND t.status <> 'a' @@ -664,7 +665,7 @@ protected function run_next() $cgc = gc_collect_cycles(); if($cgc > 0) { - $this->app->erp->LogFile($cgc.' cycles collected'); + $this->logger->info($cgc.' cycles collected'); } } if(empty($row['schreibschutz'])) @@ -746,7 +747,7 @@ protected function run_next() $ziparchiv = new ZipArchive; if($ziparchiv->open($pfad.'.zip', ZipArchive::CREATE) !== true) { - $this->app->erp->LogFile($pfad.'.zip '.(file_exists($pfad.'.zip')?'ex':'ex nicht')); + $this->logger->info($pfad.'.zip '.(file_exists($pfad.'.zip')?'ex':'ex nicht')); $this->app->DB->Update("UPDATE pdfarchiv_jobs SET status = 'Fehler', kommentar = 'Es konnte kein Zip-Archiv erstellt werden' WHERE id = '".$job['id']."' LIMIT 1"); return false; @@ -785,7 +786,7 @@ protected function run_next() $cgc = gc_collect_cycles(); if($cgc > 0) { - $this->app->erp->LogFile($cgc.' cycles collected'); + $this->logger->info($cgc.' cycles collected'); } } echo $row['id']; @@ -846,7 +847,7 @@ protected function run_next() $cgc = gc_collect_cycles(); if($cgc > 0) { - $this->app->erp->LogFile($cgc.' cycles collected'); + $this->logger->info($cgc.' cycles collected'); } } echo $row['id']; @@ -912,7 +913,7 @@ protected function run_next() $this->app->DB->Update("UPDATE pdfarchiv_jobs SET status = 'Fehler', kommentar = 'Fehler beim Speichern des Zip-Archives' WHERE id = '".$job['id']."' LIMIT 1"); return false; } - $this->app->erp->LogFile($pfad.'.zip '.(file_exists($pfad.'.zip')?'ex':'ex nicht')); + $this->logger->info($pfad.'.zip '.(file_exists($pfad.'.zip')?'ex':'ex nicht')); $this->app->DB->Update("UPDATE pdfarchiv_jobs SET status = 'abgeschlossen',kommentar = '', datei = '".$pfad_rel.".zip' WHERE id = '".$job['id']."' LIMIT 1"); }elseif($gz){ system("cd ".$this->folder." && tar cfz ".$pfad.".tar.gz $pfad_rel $1>/dev/null"); diff --git a/cronjobs/produktion_berechnen.php b/cronjobs/produktion_berechnen.php index fc1b69954..a69c21122 100644 --- a/cronjobs/produktion_berechnen.php +++ b/cronjobs/produktion_berechnen.php @@ -1,10 +1,6 @@ remote->RemoteCommand($row['shop'],'sendadresse',$row['adresse']); }catch(Execption $exception) { - $app->erp->LogFile($app->DB->real_escape_string($exception->getMessage())); + $app->Container->get('Logger')->error($app->DB->real_escape_string($exception->getMessage())); } $app->DB->Delete("DELETE FROM shopexport_adressenuebertragen WHERE id='".$row['id']."' LIMIT 1"); $app->DB->Update("UPDATE prozessstarter SET letzteausfuerhung=NOW(), mutex = 1,mutexcounter=0 WHERE parameter = 'shopexport_adressexport'"); @@ -170,4 +170,4 @@ class app_t { } $app->DB->Update("UPDATE prozessstarter SET letzteausfuerhung=NOW(), mutex = 0,mutexcounter=0 WHERE parameter = 'shopexport_adressexport'"); -$app->erp->LogFile('Cronjob Adressuebertragung Ende '.$anz.' uebertragen'); +$app->Container->get('Logger')->info('Cronjob Adressuebertragung Ende '.$anz.' uebertragen'); diff --git a/cronjobs/shopexport_voucher.php b/cronjobs/shopexport_voucher.php index 4b04fb8b8..7154da179 100644 --- a/cronjobs/shopexport_voucher.php +++ b/cronjobs/shopexport_voucher.php @@ -1,9 +1,6 @@ remote = $remote; $app->FormHandler = new FormHandler($app); +/** @var \Psr\Log\LoggerInterface $logger */ +$logger = $app->Container->get('Logger'); $app->DB->Update("UPDATE prozessstarter SET mutexcounter = mutexcounter + 1 WHERE mutex = 1 AND (parameter = 'shopexport_voucher') AND aktiv = 1"); if(!$app->DB->Select("SELECT id FROM prozessstarter WHERE mutex = 0 AND parameter = 'shopexport_voucher' AND aktiv = 1")){ @@ -87,7 +86,7 @@ class app_t extends ApplicationCore $vouchers = $app->remote->RemoteCommand($shop['id'],'getvouchers'); }catch(Exception $exception) { - $app->erp->LogFile($app->DB->real_escape_string($exception->getMessage())); + $logger->error($app->DB->real_escape_string($exception->getMessage())); } if($vouchers['success']){ foreach ($vouchers['data'] as $voucherInShop){ @@ -127,11 +126,11 @@ class app_t extends ApplicationCore $app->DB->Update($sql); } }else{ - $app->erp->LogFile('voucher was not send to shop. Shopid: '.$shop['id'].' - voucher Code: '.$voucherToSend['voucher_code'],print_r($response['message'],true)); + $logger->warning('voucher was not send to shop. Shopid: '.$shop['id'].' - voucher Code: '.$voucherToSend['voucher_code'], $response['message']); } }catch(Exception $exception) { - $app->erp->LogFile($app->DB->real_escape_string($exception->getMessage())); + $logger->error($app->DB->real_escape_string($exception->getMessage())); } $app->DB->Update("UPDATE prozessstarter SET letzteausfuerhung=NOW(), mutex = 1,mutexcounter=0 WHERE parameter = 'shopexport_voucher'"); } diff --git a/cronjobs/shopimport.php b/cronjobs/shopimport.php index 3b2619fcc..f59ec9420 100644 --- a/cronjobs/shopimport.php +++ b/cronjobs/shopimport.php @@ -448,6 +448,8 @@ function GetUsername() } $app->Secure = new Secure($app); $app->User = new User($app); +/** @var \Psr\Log\LoggerInterface $logger */ +$logger = $app->Container->get('Logger'); $app->FormHandler = new FormHandler($app); $firmendatenid = $app->DB->Select("SELECT MAX(id) FROM firmendaten LIMIT 1"); @@ -476,10 +478,10 @@ function GetUsername() $demomodus = $shop['demomodus']; $app->DB->Update("UPDATE prozessstarter SET letzteausfuerhung=NOW(), mutex = 1,mutexcounter=0 WHERE parameter = 'shopimport'"); $direktimport = $shop['direktimport']; - $app->erp->LogFile('Shopimport '.$id); + $logger->info('Shopimport '.$id); if($direktimport) { - $app->erp->LogFile('direktimport '.$id); + $logger->info('direktimport '.$id); $shopimp = new Shopimport($app, true); } @@ -671,7 +673,7 @@ function GetUsername() } else { $warenkorb = $app->erp->CleanDataBeforImport($warenkorb, false); } - foreach($warenkorb as $k => $v) $warenkorb[$k] = $app->erp->fixeUmlaute($v); + foreach($warenkorb as $k => $v) $warenkorb[$k] = $app->String->fixeUmlaute($v); $kundenurvonprojekt = $app->DB->Select("SELECT kundenurvonprojekt FROM shopexport WHERE id = '$id' LIMIT 1"); $adresseprojekt = ''; if($kundenurvonprojekt) @@ -921,7 +923,7 @@ function GetUsername() //if($gesamtanzahl > 1)$gesamtanzahl = 1; if($gesamtanzahl > 0) { - $app->erp->LogFile("Hole ".$gesamtanzahl." aus Shop ".$id); + $logger->info("Hole ".$gesamtanzahl." aus Shop ".$id); for($i=0;$i<$gesamtanzahl;$i++) { $app->DB->Update("UPDATE prozessstarter SET letzteausfuerhung=NOW(), mutex = 1,mutexcounter=0 WHERE parameter = 'shopimport'"); @@ -1065,7 +1067,7 @@ function GetUsername() } else { $warenkorb = $app->erp->CleanDataBeforImport($warenkorb, false); } - foreach($warenkorb as $k => $v) $warenkorb[$k] = $app->erp->fixeUmlaute($v); + foreach($warenkorb as $k => $v) $warenkorb[$k] = $app->String->fixeUmlaute($v); $warenkorb['email'] = trim($warenkorb['email']," \t\n\r\0\x0B\xc2\xa0"); $kundenurvonprojekt = $app->DB->Select("SELECT kundenurvonprojekt FROM shopexport WHERE id = '$id' LIMIT 1"); $adresseprojekt = ''; @@ -1123,7 +1125,7 @@ function GetUsername() $import_kundennummer = $checkidemail; } //echo "Kundennummer: ".$import_kundennummer."\r\n"; - $app->erp->LogFile("Importiere Auftrag ".$auftrag); + $logger->info("Importiere Auftrag ".$auftrag); $unbekanntezahlungsweisen = null; $shopimp->KundeAnlegenUpdate($insid,$auftrag, $warenkorb, $kundennummer, $import_kundennummer, $unbekanntezahlungsweisen); $checkid = ''; @@ -1139,7 +1141,7 @@ function GetUsername() } if(!$app->DB->Select("SELECT aktiv FROM shopexport WHERE id = '$id' LIMIT 1"))$gesamtanzahl = $i + 1; } - $app->erp->LogFile($gesamtanzahl." aus Shop ".$id." geholt"); + $logger->info($gesamtanzahl." aus Shop ".$id." geholt"); } } } diff --git a/cronjobs/shopimport_auftragarchiv.php b/cronjobs/shopimport_auftragarchiv.php index 949e4bb04..533de4e02 100644 --- a/cronjobs/shopimport_auftragarchiv.php +++ b/cronjobs/shopimport_auftragarchiv.php @@ -468,6 +468,8 @@ public function GetParameter() $app->User = new User($app); $app->FormHandler = new FormHandler($app); +/** @var \Psr\Log\LoggerInterface $logger */ +$logger = $app->Container->get('Logger'); /*if(false){ $auftraege = $app->DB->Query("SELECT a.id as auftrag, s.* FROM auftrag a INNER JOIN shopimport_auftraege s ON a.shop =s.shopid AND a.internet = s.extid WHERE a.datum = '2018-10-29'"); if($auftraege){ @@ -591,10 +593,10 @@ public function GetParameter() $pageContents = $app->remote->RemoteConnection($shopid); } catch (Exception $e) { - $app->erp->LogFile(['RemoteConnection Error'=>$e->getMessage()]); + $logger->error('RemoteConnection Error', [$e->getMessage()]); $pageContents = 'failed'; } - $app->erp->LogFile( + $logger->info( $app->DB->real_escape_string( 'shopimport_auftragarchiv Shop: '.$shopid.' Auth: '. print_r($pageContents,true).' arr: '.print_r($archivauftraege[$i],true) @@ -621,10 +623,10 @@ public function GetParameter() ); } catch (Exception $e) { - $app->erp->LogFile(['RemoteGetAuftraegeAnzahl Error'=>$e->getMessage()]); + $logger->error('RemoteGetAuftraegeAnzahl Error', [$e->getMessage()]); $anzahlauftraege = 0; } - $app->erp->LogFile('shopimport_auftragarchiv Shop: '.$shopid.' gefundene Auftraege: '.$anzahlauftraege); + $logger->info('shopimport_auftragarchiv Shop: '.$shopid.' gefundene Auftraege: '.$anzahlauftraege); if($anzahlauftraege > 0) { $app->DB->Update( sprintf( @@ -667,7 +669,7 @@ public function GetParameter() $data['anzgleichzeitig'] = 50; $data['holeallestati'] = 1; $data['archive'] = 1; - $app->erp->LogFile($app->DB->real_escape_string('shopimport_auftragarchiv Shop: '.$shopid.' Zeitraum: '.print_r($data,true))); + $logger->info($app->DB->real_escape_string('shopimport_auftragarchiv Shop: '.$shopid.' Zeitraum: '.print_r($data,true))); } $shopimp = new Shopimport($app, true); $erfolgreich = 0; @@ -696,7 +698,7 @@ public function GetParameter() ); } catch(Exception $e) { - $app->erp->LogFile(['RemoteGetAuftrag Error'=>$e->getMessage()]); + $logger->error('RemoteGetAuftrag Error', [$e->getMessage()]); $result = ''; } if(!is_array($result)) { @@ -706,7 +708,7 @@ public function GetParameter() continue; } $app->erp->ProzessstarterStatus('Id '.$shopid.' keine (weiteren) Auftraege gefunden', $cronjobTmpId); - $app->erp->LogFile('shopimport_auftragarchiv Shop: '.$shopid.' keine (weiteren) Auftraege gefunden'); + $logger->info('shopimport_auftragarchiv Shop: '.$shopid.' keine (weiteren) Auftraege gefunden'); $app->DB->Update("UPDATE `shopexport_archiv` SET `status` = 'abgeschlossen' WHERE `id` = " . $archivauftraege[$i]['id']); break; } @@ -750,7 +752,7 @@ public function GetParameter() $mintime = false; $cw = count($result); if($archivauftraege[$i]['type'] === 'zeitraum') { - $app->erp->LogFile('shopimport_auftragarchiv Shop: '.$shopid.' gefundene Auftraege: '.$cw); + $logger->info('shopimport_auftragarchiv Shop: '.$shopid.' gefundene Auftraege: '.$cw); $app->erp->ProzessstarterStatus('Id '.$shopid.' anz '.$cw, $cronjobTmpId); } for ($ii = 0; $ii < $cw; $ii++) { @@ -872,7 +874,7 @@ public function GetParameter() $warenkorb = $app->erp->CleanDataBeforImport($warenkorb, false); }*/ foreach($warenkorb as $k => $v) { - $warenkorb[$k] = $app->erp->fixeUmlaute($v); + $warenkorb[$k] = $app->String->fixeUmlaute($v); } $projekt = $app->DB->Select( "SELECT `projekt` FROM `shopexport` WHERE `id` = '$shopid' LIMIT 1" @@ -1190,7 +1192,7 @@ public function GetParameter() } } else{ - $app->erp->LogFile( + $logger->info( $app->DB->real_escape_string( 'shopimport_auftragarchiv Shop: '.$shopid.' Auth: '.print_r($pageContents,true) ) diff --git a/cronjobs/starter.php b/cronjobs/starter.php index d09afe85b..f9c40eca1 100644 --- a/cronjobs/starter.php +++ b/cronjobs/starter.php @@ -1,10 +1,7 @@ erp->SetKonfigurationValue('prozessstarter_letzteraufruf',date('Y-m-d H:i:s')); + /** @var \Psr\Log\LoggerInterface $logger */ + $logger = $app->Container->get('Logger'); usleep(mt_rand(100000,1000000)); $tasks = $app->DB->SelectArr( "SELECT * @@ -119,7 +118,7 @@ class app_t extends ApplicationCore { } $run = 0; if($DEBUG){ - $app->erp->LogFile('Task: ' . $task['bezeichnung'] . ' ' . $task['art']); + $logger->debug('Task: ' . $task['bezeichnung'] . ' ' . $task['art']); } if($task['art'] === 'periodisch'){ @@ -179,7 +178,7 @@ class app_t extends ApplicationCore { $app->erp->setCronjobRunning(CRONJOBUID, $task, true); if($DEBUG){ - $app->erp->LogFile('Prozessstarter ' . $task['parameter']); + $logger->debug('Prozessstarter ' . $task['parameter']); } //update letzte ausfuerhung $app->DB->Update( @@ -231,7 +230,7 @@ class app_t extends ApplicationCore { for ($outputLineInxed = $startIndex; $outputLineInxed < $coutput; $outputLineInxed++) { $lastLines[] = $output[$outputLineInxed]; } - $app->erp->LogFile( + $logger->info('Cronjob result', [ 'cmd' => $cmd, 'parameter' => $task['parameter'], @@ -248,7 +247,7 @@ class app_t extends ApplicationCore { unset($returnvar); } else{ - $app->erp->LogFile( + $logger->warning( $app->DB->real_escape_string( 'Der Prozessstarter ' . $task['parameter'] . ' wurde nicht gefunden' ) diff --git a/cronjobs/starter2.php b/cronjobs/starter2.php index f7814efb3..08e477783 100644 --- a/cronjobs/starter2.php +++ b/cronjobs/starter2.php @@ -1,10 +1,7 @@ app = $app; $app->erp = $erp; $app->DB = new DB($multiDbConf->WFdbhost,$multiDbConf->WFdbname,$multiDbConf->WFdbuser,$multiDbConf->WFdbpass,$app,$multiDbConf->WFdbport); + /** @var \Psr\Log\LoggerInterface $logger */ + $logger = $app->Container->get('Logger'); $multiDb = $multiDbConf->WFdbname; if(method_exists($app->erp, 'CheckCronjob') && !$app->erp->CheckCronjob()) { @@ -115,7 +114,7 @@ class app_t extends ApplicationCore { } $run = 0; if($DEBUG){ - $app->erp->LogFile('Task: ' . $task['bezeichnung'] . ' ' . $task['art']); + $logger->debug('Task: ' . $task['bezeichnung'] . ' ' . $task['art']); } if($task['art'] === 'periodisch'){ @@ -171,7 +170,7 @@ class app_t extends ApplicationCore { $app->erp->setCronjobRunning(CRONJOBUID, $task, true); if($DEBUG){ - $app->erp->LogFile('Prozessstarter ' . $task['parameter']); + $logger->debug('Prozessstarter ' . $task['parameter']); } //update letzte ausfuerhung $app->DB->Update( @@ -226,7 +225,7 @@ class app_t extends ApplicationCore { for ($outputLineInxed = $startIndex; $outputLineInxed < $coutput; $outputLineInxed++) { $lastLines[] = $output[$outputLineInxed]; } - $app->erp->LogFile( + $logger->info('Cronjob result', [ 'cmd' => $cmd, 'parameter' => $task['parameter'], @@ -243,7 +242,7 @@ class app_t extends ApplicationCore { unset($returnvar); } else { - $app->erp->LogFile( + $logger->info( $app->DB->real_escape_string( 'Der Prozessstarter ' . $task['parameter'] . ' wurde nicht gefunden' ) diff --git a/cronjobs/test.php b/cronjobs/test.php index 826d5de74..f387b886d 100644 --- a/cronjobs/test.php +++ b/cronjobs/test.php @@ -25,7 +25,7 @@ class app_t { $app->DB = new DB($conf->WFdbhost,$conf->WFdbname,$conf->WFdbuser,$conf->WFdbpass,null,$conf->WFdbport); $erp = new erpAPI($app); $app->erp = $erp; -$app->erp->LogFile("Testprozess"); +$app->Container->get('Logger')->info("Testprozess"); ?> diff --git a/cronjobs/vertriebscockpit.php b/cronjobs/vertriebscockpit.php index 161813d87..3cb10d46e 100644 --- a/cronjobs/vertriebscockpit.php +++ b/cronjobs/vertriebscockpit.php @@ -50,7 +50,7 @@ class app_t { } } -$app->erp->LogFile("Starte Synchronisation"); +$app->Container->get('Logger')->info("Starte Synchronisation"); //$app->DB->Update("UPDATE artikel SET cache_lagerplatzinhaltmenge='999'"); diff --git a/docker-compose.yml b/docker-compose.yml index 02bacd4fa..84d7c61b7 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,4 +1,3 @@ -version: '3.9' services: vite: build: diff --git a/docker/Dockerfile b/docker/Dockerfile index 69deb9a8b..a64678581 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -1,8 +1,6 @@ -ARG PHP_EXT="gd ldap imap mysqli soap zip" -ARG DEB_PKG="libc-client2007e libaom3 libavif15 libdav1d6 libfreetype6 libjpeg62-turbo libldap-common libpng16-16 libwebp7 libxpm4 libzip4" -ARG DEB_PKG_TMP="cmake gnutls-dev libaom-dev libavif-dev libbz2-dev libc-client-dev libdav1d-dev libfreetype6-dev libjpeg62-turbo-dev libkrb5-dev libldap2-dev libpng-dev libssl-dev libwebp-dev libxml2-dev libxpm-dev libzip-dev zlib1g-dev" +ARG PHP_EXT="bcmath exif gd ldap imap mysqli pcntl pdo_mysql soap zip" -FROM node:20 as frontend +FROM node:20 AS frontend WORKDIR /app COPY package.json package-lock.json vite.config.js /app/ RUN npm install @@ -11,19 +9,17 @@ COPY resources /app/resources COPY www /app/www RUN npm run build -#FROM php:8.1-fpm as fpm_server -FROM php:8.1-apache as web_server +FROM php:8.1-apache AS web_server ARG PHP_EXT -ARG DEB_PKG -ARG DEB_PKG_TMP -WORKDIR /app -RUN apt-get update && apt-get install -y ${DEB_PKG} ${DEB_PKG_TMP} && \ - docker-php-ext-configure imap --with-kerberos --with-imap-ssl && \ - docker-php-ext-install ${PHP_EXT} && \ - apt-get remove --purge -y ${DEB_PKG_TMP} && \ - mv "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini" +COPY --from=mlocati/php-extension-installer /usr/bin/install-php-extensions /usr/local/bin/ +RUN install-php-extensions ${PHP_EXT} && \ + a2enmod rewrite headers && \ + mv "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini" COPY docker/php "$PHP_INI_DIR/conf.d/" -COPY --chown=www-data:www-data . /var/www/html + +FROM web_server AS openxe + +COPY --chown=www-data:www-data --exclude=userdata . /var/www/html COPY --chown=www-data:www-data --from=frontend /app/www/dist /var/www/html/www/dist \ No newline at end of file diff --git a/phpwf/class.application.php b/phpwf/class.application.php index 7d422360c..03fa70f89 100644 --- a/phpwf/class.application.php +++ b/phpwf/class.application.php @@ -1,4 +1,4 @@ - +*/ +?> Conf= $config; - - //include dirname(__DIR__).'/phpwf/plugins/class.mysql.php'; + parent::__construct($config); if(!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS']==='on'){ $this->http = 'https'; @@ -149,19 +94,16 @@ public function __construct($config,$group='') if(WithGUI()){ $this->Tpl = new TemplateParser($this); $this->FormHandler = new FormHandler($this); - $this->Table = new Table($this); $this->Widget = new WidgetAPI($this); $this->PageBuilder = new PageBuilder($this); $this->Page = new Page($this); $this->ObjAPI = new ObjectAPI($this); - $this->WFM = new WFMonitor($this); $this->ModuleScriptCache = new ModuleScriptCache(); } //$this->YUI = new YUI($this); //$this->User = new User($this); //$this->acl = new Acl($this); - //$this->WF = new phpWFAPI($this); //$this->String = new WawiString(); $this->BuildNavigation = true; @@ -246,11 +188,4 @@ public function ActionHandlerListen($app) } } } - - public function DisableLayoutFix() - { - if(WithGUI()){ - $this->Tpl->Set('LAYOUTFIXMARKERCLASS', ''); - } - } } diff --git a/phpwf/class.application_core.php b/phpwf/class.application_core.php index 60aaf41d3..a277a0c02 100644 --- a/phpwf/class.application_core.php +++ b/phpwf/class.application_core.php @@ -1,593 +1,586 @@ - -Conf = ConfigLoader::load(); - }else{ - $this->Conf = $config; - } - - $registry = include dirname(__DIR__) . '/classes/bootstrap.php'; - $registry->add('LegacyApplication', $this); - $this->Container = $registry->get('ServiceContainer'); - - $this->getter = array( - 'User'=>array('class'=>'User','app'=>true), - 'Tpl'=>array('class'=>'TemplateParser','app'=>true), - 'Conf'=>array('class'=>'Config'), - 'YUI'=>array('class'=>'YUI','app'=>true), - 'String'=>array('class'=>'WawiString'), - 'FormHandler'=>array('class'=>'FormHandler','app'=>true), - 'Table'=>array('class'=>'Table','app'=>true), - 'WF'=>array('class'=>'phpWFAPI','app'=>true), - 'WFM'=>array('class'=>'WFMonitor','app'=>true), - 'Secure'=>array('class'=>'Secure','app'=>true), - 'mail'=>array('class'=>'PHPMailer','app'=>true), - 'help'=>array('class'=>'Help','app'=>true), - 'stringcleaner'=>array('class'=>'StringCleaner','app'=>true), - 'acl'=>array('class'=>'Acl','app'=>true), - 'ModuleScriptCache'=>array('class'=>'ModuleScriptCache'), - 'ObjAPI'=>array('class'=>'ObjectAPI','app'=>true), - 'FormSecure'=>array('class'=>'FormSecure','app'=>true), - 'Location'=>array('class'=>'Location','app'=>true), - 'DatabaseUpgrade'=>array('class'=>'DatabaseUpgrade','app'=>true), - 'PageBuilder' => ['class' => 'PageBuilder','app'=>true], - ); - $this->gettercustom = array( - 'erp'=>array( - 'class'=>'erpAPI', - 'class_custom'=>'erpAPICustom', - 'file'=>dirname(__DIR__).'/www/lib/class.erpapi.php', - 'file_custom'=>dirname(__DIR__).'/www/lib/class.erpapi_custom.php' - ), - 'remote'=>array( - 'class'=>'Remote', - 'class_custom'=>'RemoteCustom', - 'file'=>dirname(__DIR__).'/www/lib/class.remote.php', - 'file_custom'=>dirname(__DIR__).'/www/lib/class.remote_custom.php' - ), - 'printer'=>array( - 'class'=>'Printer', - 'class_custom'=>'PrinterCustom', - 'file'=>dirname(__DIR__).'/www/lib/class.printer.php', - 'file_custom'=>dirname(__DIR__).'/www/lib/class.printer_custom.php' - ), - ); - } - - /** - * @return array - */ - public function getDbs() - { - return ConfigLoader::loadAllDescriptions(); - } - - /** - * @param int $status - */ - public function ExitXentral($status = 0) - { - if(class_exists('DevTools')){ - DevTools::exitcustom($this, $status); - } - - $dbConnected = !empty($this->DB) && !empty($this->DB->connection); - $cronjobToClose = defined('CRONJOBUID') && defined('FROMSTARTER2'); - if($dbConnected && $cronjobToClose && method_exists($this->erp,'closeAndLogCronjob')) { - $this->erp->closeAndLogCronjob(CRONJOBUID, FROMSTARTER2); - } - - if($dbConnected){ - $this->DB->Close(); - } - - exit($status); - } - - /** - * @param string $value - * - * @return mixed - */ - public function __get($value) - { - if(isset($this->getter[$value])) - { - $class = $this->getter[$value]['class']; - if($this->getter[$value]['app']){ - $this->$value = new $class($this); - return $this->$value; - } - $this->$value = new $class(); - return $this->$value; - } - if(isset($this->gettercustom[$value])) - { - if(is_file($this->gettercustom[$value]['file_custom'])) - { - $class = $this->gettercustom[$value]['class_custom']; - }else{ - $class = $this->gettercustom[$value]['class']; - } - $this->$value = new $class($this); - return $this->$value; - } - if($value === 'DB') - { - $this->DB = new DB($this->Conf->WFdbhost,$this->Conf->WFdbname,$this->Conf->WFdbuser,$this->Conf->WFdbpass,$this,$this->Conf->WFdbport); - return $this->DB; - } - } - - /** - * @param string $value - * - * @return bool - */ - public function __isset($value) - { - if (isset($this->$value)){ - return true; - } - - if($value === 'DB'){ - return class_exists('DB', true); - } - - if(isset($this->getter[$value])){ - $className = $this->getter[$value]['class']; - if(class_exists($className, true)){ - return true; - } - } - - if(isset($this->gettercustom[$value])){ - $className = $this->gettercustom[$value]['class']; - $classNameCustom = $this->gettercustom[$value]['class_custom']; - if(class_exists($classNameCustom, true) || class_exists($className, true)){ - return true; - } - } - - return false; - } - - /** - * @param string $name - * @param mixed $value - */ - public function __set($name, $value) - { - $this->$name = $value; - } - - /** - * @param string $class - * @param bool $ownInstance - * - * @return mixed|null - */ - public function loadModule($class, $ownInstance = true) { - $class = ucfirst($class); - $classcustom = $class.'Custom'; - if(!$ownInstance && !empty($this->loadedModules[$classcustom])) { - return $this->loadedModules[$classcustom]; - } - if(!$ownInstance && !empty($this->loadedModules[$class])) { - return $this->loadedModules[$class]; - } - $phpname = strtolower($class); - if(!class_exists($class) && @is_file(dirname(__DIR__) . '/www/pages/' . $phpname . '.php')){ - include_once dirname(__DIR__) . '/www/pages/' . $phpname . '.php'; - } - if(!class_exists($classcustom) && @is_file(dirname(__DIR__) . '/www/pages/' . $phpname . '_custom.php') && class_exists($class)) { - include_once dirname(__DIR__) . '/www/pages/' . $phpname . '_custom.php'; - } - - if(class_exists($classcustom)) { - if(method_exists($classcustom, '__construct')) { - try { - $r = new ReflectionMethod($classcustom, '__construct'); - $params = $r->getParameters(); - } catch( Exception $e) { - return null; - } - $anzargs = count($params); - if($anzargs > 1) { - $obj = new $classcustom($this, true); - } - }else{ - $obj = new $classcustom($this, true); - } - } - - if(!empty($obj)) { - if($ownInstance) { - return $obj; - } - $this->loadedModules[$classcustom] = $obj; - return $this->loadedModules[$classcustom]; - } - if(!class_exists($class)) { - return null; - } - - if(method_exists($class, '__construct')) - { - try { - $r = new ReflectionMethod($class, '__construct'); - $params = $r->getParameters(); - } catch (Exception $e) { - return null; - } - $anzargs = count($params); - if($anzargs > 1) { - $obj = new $class($this, true); - } - }else{ - $obj = new $class($this, true); - } - if(empty($obj)) { - return null; - } - if($ownInstance) { - return $obj; - } - $this->loadedModules[$class] = $obj; - return $this->loadedModules[$class]; - } - - /** - * @return array|null - * @throws ReflectionException - */ - function getAppList() - { - /** @var Appstore $obj */ - $obj = $this->loadModule('appstore'); - if(!empty($obj) && method_exists($obj,'getAppList')) - { - return $obj->getAppList(); - } - - return null; - } - - public function IsWindows() - { - return strtoupper(substr(PHP_OS, 0, 3)) === 'WIN'; - } - - public function getTmpFolder() - { - $userdata = $this->Conf->WFuserdata; - - if ($this->IsWindows()) { - $tmp = $userdata."\\tmp\\"; - } else { - $tmp = $userdata."/tmp/"; - } - - $tmp = str_replace('//','/',$tmp); - - if(!is_dir($tmp) && !mkdir($tmp) && !is_dir($tmp)) { - return $tmp; - } - - return $tmp; - } - - public function GetLandLang($isocode) - { - $flipped = array_flip($this->GetLaender()); - if(isset($flipped[$isocode])){ - $land = $flipped[$isocode]; - } - else - { - $land = 'unkown'; - } - return $land; - } - public function GetLaender() - { - $laender = array( - 'Afghanistan' => 'AF', - 'Ägypten' => 'EG', - 'Albanien' => 'AL', - 'Algerien' => 'DZ', - 'Andorra' => 'AD', - 'Angola' => 'AO', - 'Anguilla' => 'AI', - 'Antarktis' => 'AQ', - 'Antigua und Barbuda' => 'AG', - 'Äquatorial Guinea' => 'GQ', - 'Argentinien' => 'AR', - 'Armenien' => 'AM', - 'Aruba' => 'AW', - 'Aserbaidschan' => 'AZ', - 'Äthiopien' => 'ET', - 'Australien' => 'AU', - 'Bahamas' => 'BS', - 'Bahrain' => 'BH', - 'Bangladesh' => 'BD', - 'Barbados' => 'BB', - 'Belgien' => 'BE', - 'Belize' => 'BZ', - 'Benin' => 'BJ', - 'Bermudas' => 'BM', - 'Bhutan' => 'BT', - 'Birma' => 'MM', - 'Bolivien' => 'BO', - 'Bosnien-Herzegowina' => 'BA', - 'Botswana' => 'BW', - 'Bouvet Inseln' => 'BV', - 'Brasilien' => 'BR', - 'Britisch-Indischer Ozean' => 'IO', - 'Brunei' => 'BN', - 'Bulgarien' => 'BG', - 'Burkina Faso' => 'BF', - 'Burundi' => 'BI', - 'Chile' => 'CL', - 'China' => 'CN', - 'Christmas Island' => 'CX', - 'Cook Inseln' => 'CK', - 'Costa Rica' => 'CR', - 'Dänemark' => 'DK', - 'Deutschland' => 'DE', - 'Djibuti' => 'DJ', - 'Dominika' => 'DM', - 'Dominikanische Republik' => 'DO', - 'Ecuador' => 'EC', - 'El Salvador' => 'SV', - 'Elfenbeinküste' => 'CI', - 'Eritrea' => 'ER', - 'Estland' => 'EE', - 'Falkland Inseln' => 'FK', - 'Färöer Inseln' => 'FO', - 'Fidschi' => 'FJ', - 'Finnland' => 'FI', - 'Frankreich' => 'FR', - 'Französisch Guyana' => 'GF', - 'Französisch Polynesien' => 'PF', - 'Französisches Süd-Territorium' => 'TF', - 'Gabun' => 'GA', - 'Gambia' => 'GM', - 'Georgien' => 'GE', - 'Ghana' => 'GH', - 'Gibraltar' => 'GI', - 'Grenada' => 'GD', - 'Griechenland' => 'GR', - 'Grönland' => 'GL', - 'Großbritannien' => 'UK', - 'Großbritannien (UK)' => 'GB', - 'Guadeloupe' => 'GP', - 'Guam' => 'GU', - 'Guatemala' => 'GT', - 'Guinea' => 'GN', - 'Guinea Bissau' => 'GW', - 'Guyana' => 'GY', - 'Haiti' => 'HT', - 'Heard und McDonald Islands' => 'HM', - 'Honduras' => 'HN', - 'Hong Kong' => 'HK', - 'Indien' => 'IN', - 'Indonesien' => 'ID', - 'Irak' => 'IQ', - 'Iran' => 'IR', - 'Irland' => 'IE', - 'Island' => 'IS', - 'Israel' => 'IL', - 'Italien' => 'IT', - 'Jamaika' => 'JM', - 'Japan' => 'JP', - 'Jemen' => 'YE', - 'Jordanien' => 'JO', - 'Jugoslawien' => 'YU', - 'Kaiman Inseln' => 'KY', - 'Kambodscha' => 'KH', - 'Kamerun' => 'CM', - 'Kanada' => 'CA', - 'Kap Verde' => 'CV', - 'Kasachstan' => 'KZ', - 'Kenia' => 'KE', - 'Kirgisistan' => 'KG', - 'Kiribati' => 'KI', - 'Kokosinseln' => 'CC', - 'Kolumbien' => 'CO', - 'Komoren' => 'KM', - 'Kongo' => 'CG', - 'Kongo, Demokratische Republik' => 'CD', - 'Kosovo' => 'KO', - 'Kroatien' => 'HR', - 'Kuba' => 'CU', - 'Kuwait' => 'KW', - 'Laos' => 'LA', - 'Lesotho' => 'LS', - 'Lettland' => 'LV', - 'Libanon' => 'LB', - 'Liberia' => 'LR', - 'Libyen' => 'LY', - 'Liechtenstein' => 'LI', - 'Litauen' => 'LT', - 'Luxemburg' => 'LU', - 'Macao' => 'MO', - 'Madagaskar' => 'MG', - 'Malawi' => 'MW', - 'Malaysia' => 'MY', - 'Malediven' => 'MV', - 'Mali' => 'ML', - 'Malta' => 'MT', - 'Marianen' => 'MP', - 'Marokko' => 'MA', - 'Marshall Inseln' => 'MH', - 'Martinique' => 'MQ', - 'Mauretanien' => 'MR', - 'Mauritius' => 'MU', - 'Mayotte' => 'YT', - 'Mazedonien' => 'MK', - 'Mexiko' => 'MX', - 'Mikronesien' => 'FM', - 'Mocambique' => 'MZ', - 'Moldavien' => 'MD', - 'Monaco' => 'MC', - 'Mongolei' => 'MN', - 'Montenegro' => 'ME', - 'Montserrat' => 'MS', - 'Namibia' => 'NA', - 'Nauru' => 'NR', - 'Nepal' => 'NP', - 'Neukaledonien' => 'NC', - 'Neuseeland' => 'NZ', - 'Nicaragua' => 'NI', - 'Niederlande' => 'NL', - 'Niederländische Antillen' => 'AN', - 'Niger' => 'NE', - 'Nigeria' => 'NG', - 'Niue' => 'NU', - 'Nord Korea' => 'KP', - 'Norfolk Inseln' => 'NF', - 'Norwegen' => 'NO', - 'Oman' => 'OM', - 'Österreich' => 'AT', - 'Pakistan' => 'PK', - 'Palästina' => 'PS', - 'Palau' => 'PW', - 'Panama' => 'PA', - 'Papua Neuguinea' => 'PG', - 'Paraguay' => 'PY', - 'Peru' => 'PE', - 'Philippinen' => 'PH', - 'Pitcairn' => 'PN', - 'Polen' => 'PL', - 'Portugal' => 'PT', - 'Puerto Rico' => 'PR', - 'Qatar' => 'QA', - 'Reunion' => 'RE', - 'Ruanda' => 'RW', - 'Rumänien' => 'RO', - 'Rußland' => 'RU', - 'Saint Lucia' => 'LC', - 'Sambia' => 'ZM', - 'Samoa' => 'AS', - 'Samoa' => 'WS', - 'San Marino' => 'SM', - 'Sao Tome' => 'ST', - 'Saudi Arabien' => 'SA', - 'Schweden' => 'SE', - 'Schweiz' => 'CH', - 'Senegal' => 'SN', - 'Serbien' => 'RS', - 'Seychellen' => 'SC', - 'Sierra Leone' => 'SL', - 'Singapur' => 'SG', - 'Slowakei -slowakische Republik-' => 'SK', - 'Slowenien' => 'SI', - 'Solomon Inseln' => 'SB', - 'Somalia' => 'SO', - 'South Georgia, South Sandwich Isl.' => 'GS', - 'Spanien' => 'ES', - 'Sri Lanka' => 'LK', - 'St. Helena' => 'SH', - 'St. Kitts Nevis Anguilla' => 'KN', - 'St. Pierre und Miquelon' => 'PM', - 'St. Vincent' => 'VC', - 'Süd Korea' => 'KR', - 'Südafrika' => 'ZA', - 'Sudan' => 'SD', - 'Surinam' => 'SR', - 'Svalbard und Jan Mayen Islands' => 'SJ', - 'Swasiland' => 'SZ', - 'Syrien' => 'SY', - 'Tadschikistan' => 'TJ', - 'Taiwan' => 'TW', - 'Tansania' => 'TZ', - 'Thailand' => 'TH', - 'Timor' => 'TP', - 'Togo' => 'TG', - 'Tokelau' => 'TK', - 'Tonga' => 'TO', - 'Trinidad Tobago' => 'TT', - 'Tschad' => 'TD', - 'Tschechische Republik' => 'CZ', - 'Tunesien' => 'TN', - 'Türkei' => 'TR', - 'Turkmenistan' => 'TM', - 'Turks und Kaikos Inseln' => 'TC', - 'Tuvalu' => 'TV', - 'Uganda' => 'UG', - 'Ukraine' => 'UA', - 'Ungarn' => 'HU', - 'Uruguay' => 'UY', - 'Usbekistan' => 'UZ', - 'Vanuatu' => 'VU', - 'Vatikan' => 'VA', - 'Venezuela' => 'VE', - 'Vereinigte Arabische Emirate' => 'AE', - 'Vereinigte Staaten von Amerika' => 'US', - 'Vietnam' => 'VN', - 'Virgin Island (Brit.)' => 'VG', - 'Virgin Island (USA)' => 'VI', - 'Wallis et Futuna' => 'WF', - 'Weißrußland' => 'BY', - 'Westsahara' => 'EH', - 'Zentralafrikanische Republik' => 'CF', - 'Zimbabwe' => 'ZW', - 'Zypern' => 'CY' - ); - return $laender; - } -} + +Conf = ConfigLoader::load(); + }else{ + $this->Conf = $config; + } + + $registry = include dirname(__DIR__) . '/classes/bootstrap.php'; + $registry->add('LegacyApplication', $this); + $this->Container = $registry->get('ServiceContainer'); + + $this->getter = array( + 'User'=>array('class'=>'User','app'=>true), + 'Tpl'=>array('class'=>'TemplateParser','app'=>true), + 'Conf'=>array('class'=>'Config'), + 'YUI'=>array('class'=>'YUI','app'=>true), + 'String'=>array('class'=>'WawiString'), + 'FormHandler'=>array('class'=>'FormHandler','app'=>true), + 'Secure'=>array('class'=>'Secure','app'=>true), + 'mail'=>array('class'=>'PHPMailer','app'=>true), + 'stringcleaner'=>array('class'=>'StringCleaner','app'=>true), + 'acl'=>array('class'=>'Acl','app'=>true), + 'ModuleScriptCache'=>array('class'=>'ModuleScriptCache'), + 'ObjAPI'=>array('class'=>'ObjectAPI','app'=>true), + 'FormSecure'=>array('class'=>'FormSecure','app'=>true), + 'Location'=>array('class'=>'Location','app'=>true), + 'DatabaseUpgrade'=>array('class'=>'DatabaseUpgrade','app'=>true), + 'PageBuilder' => ['class' => 'PageBuilder','app'=>true], + ); + $this->gettercustom = array( + 'erp'=>array( + 'class'=>'erpAPI', + 'class_custom'=>'erpAPICustom', + 'file'=>dirname(__DIR__).'/www/lib/class.erpapi.php', + 'file_custom'=>dirname(__DIR__).'/www/lib/class.erpapi_custom.php' + ), + 'remote'=>array( + 'class'=>'Remote', + 'class_custom'=>'RemoteCustom', + 'file'=>dirname(__DIR__).'/www/lib/class.remote.php', + 'file_custom'=>dirname(__DIR__).'/www/lib/class.remote_custom.php' + ), + 'printer'=>array( + 'class'=>'Printer', + 'class_custom'=>'PrinterCustom', + 'file'=>dirname(__DIR__).'/www/lib/class.printer.php', + 'file_custom'=>dirname(__DIR__).'/www/lib/class.printer_custom.php' + ), + ); + } + + /** + * @return array + */ + public function getDbs() + { + return ConfigLoader::loadAllDescriptions(); + } + + /** + * @param int $status + */ + public function ExitXentral($status = 0) + { + if(class_exists('DevTools')){ + DevTools::exitcustom($this, $status); + } + + $dbConnected = !empty($this->DB) && !empty($this->DB->connection); + $cronjobToClose = defined('CRONJOBUID') && defined('FROMSTARTER2'); + if($dbConnected && $cronjobToClose && method_exists($this->erp,'closeAndLogCronjob')) { + $this->erp->closeAndLogCronjob(CRONJOBUID, FROMSTARTER2); + } + + if($dbConnected){ + $this->DB->Close(); + } + + exit($status); + } + + /** + * @param string $value + * + * @return mixed + */ + public function __get($value) + { + if(isset($this->getter[$value])) + { + $class = $this->getter[$value]['class']; + if($this->getter[$value]['app'] ?? false){ + $this->$value = new $class($this); + return $this->$value; + } + $this->$value = new $class(); + return $this->$value; + } + if(isset($this->gettercustom[$value])) + { + if(is_file($this->gettercustom[$value]['file_custom'])) + { + $class = $this->gettercustom[$value]['class_custom']; + }else{ + $class = $this->gettercustom[$value]['class']; + } + $this->$value = new $class($this); + return $this->$value; + } + if($value === 'DB') + { + $this->DB = new DB($this->Conf->WFdbhost,$this->Conf->WFdbname,$this->Conf->WFdbuser,$this->Conf->WFdbpass,$this,$this->Conf->WFdbport); + return $this->DB; + } + } + + /** + * @param string $value + * + * @return bool + */ + public function __isset($value) + { + if (isset($this->$value)){ + return true; + } + + if($value === 'DB'){ + return class_exists('DB', true); + } + + if(isset($this->getter[$value])){ + $className = $this->getter[$value]['class']; + if(class_exists($className, true)){ + return true; + } + } + + if(isset($this->gettercustom[$value])){ + $className = $this->gettercustom[$value]['class']; + $classNameCustom = $this->gettercustom[$value]['class_custom']; + if(class_exists($classNameCustom, true) || class_exists($className, true)){ + return true; + } + } + + return false; + } + + /** + * @param string $name + * @param mixed $value + */ + public function __set($name, $value) + { + $this->$name = $value; + } + + /** + * @param string $class + * @param bool $ownInstance + * + * @return mixed|null + */ + public function loadModule($class, $ownInstance = true) { + $class = ucfirst($class); + $classcustom = $class.'Custom'; + if(!$ownInstance && !empty($this->loadedModules[$classcustom])) { + return $this->loadedModules[$classcustom]; + } + if(!$ownInstance && !empty($this->loadedModules[$class])) { + return $this->loadedModules[$class]; + } + $phpname = strtolower($class); + if(!class_exists($class) && @is_file(dirname(__DIR__) . '/www/pages/' . $phpname . '.php')){ + include_once dirname(__DIR__) . '/www/pages/' . $phpname . '.php'; + } + if(!class_exists($classcustom) && @is_file(dirname(__DIR__) . '/www/pages/' . $phpname . '_custom.php') && class_exists($class)) { + include_once dirname(__DIR__) . '/www/pages/' . $phpname . '_custom.php'; + } + + if(class_exists($classcustom)) { + if(method_exists($classcustom, '__construct')) { + try { + $r = new ReflectionMethod($classcustom, '__construct'); + $params = $r->getParameters(); + } catch( Exception $e) { + return null; + } + $anzargs = count($params); + if($anzargs > 1) { + $obj = new $classcustom($this, true); + } + }else{ + $obj = new $classcustom($this, true); + } + } + + if(!empty($obj)) { + if($ownInstance) { + return $obj; + } + $this->loadedModules[$classcustom] = $obj; + return $this->loadedModules[$classcustom]; + } + if(!class_exists($class)) { + return null; + } + + if(method_exists($class, '__construct')) + { + try { + $r = new ReflectionMethod($class, '__construct'); + $params = $r->getParameters(); + } catch (Exception $e) { + return null; + } + $anzargs = count($params); + if($anzargs > 1) { + $obj = new $class($this, true); + } + }else{ + $obj = new $class($this, true); + } + if(empty($obj)) { + return null; + } + if($ownInstance) { + return $obj; + } + $this->loadedModules[$class] = $obj; + return $this->loadedModules[$class]; + } + + /** + * @return array|null + * @throws ReflectionException + */ + function getAppList() + { + /** @var Appstore $obj */ + $obj = $this->loadModule('appstore'); + if(!empty($obj) && method_exists($obj,'getAppList')) + { + return $obj->getAppList(); + } + + return null; + } + + public function IsWindows() + { + return strtoupper(substr(PHP_OS, 0, 3)) === 'WIN'; + } + + public function getTmpFolder() + { + $userdata = $this->Conf->WFuserdata; + + if ($this->IsWindows()) { + $tmp = $userdata."\\tmp\\"; + } else { + $tmp = $userdata."/tmp/"; + } + + $tmp = str_replace('//','/',$tmp); + + if(!is_dir($tmp) && !mkdir($tmp) && !is_dir($tmp)) { + return $tmp; + } + + return $tmp; + } + + public function GetLandLang($isocode) + { + $flipped = array_flip($this->GetLaender()); + if(isset($flipped[$isocode])){ + $land = $flipped[$isocode]; + } + else + { + $land = 'unkown'; + } + return $land; + } + public function GetLaender() + { + $laender = array( + 'Afghanistan' => 'AF', + 'Ägypten' => 'EG', + 'Albanien' => 'AL', + 'Algerien' => 'DZ', + 'Andorra' => 'AD', + 'Angola' => 'AO', + 'Anguilla' => 'AI', + 'Antarktis' => 'AQ', + 'Antigua und Barbuda' => 'AG', + 'Äquatorial Guinea' => 'GQ', + 'Argentinien' => 'AR', + 'Armenien' => 'AM', + 'Aruba' => 'AW', + 'Aserbaidschan' => 'AZ', + 'Äthiopien' => 'ET', + 'Australien' => 'AU', + 'Bahamas' => 'BS', + 'Bahrain' => 'BH', + 'Bangladesh' => 'BD', + 'Barbados' => 'BB', + 'Belgien' => 'BE', + 'Belize' => 'BZ', + 'Benin' => 'BJ', + 'Bermudas' => 'BM', + 'Bhutan' => 'BT', + 'Birma' => 'MM', + 'Bolivien' => 'BO', + 'Bosnien-Herzegowina' => 'BA', + 'Botswana' => 'BW', + 'Bouvet Inseln' => 'BV', + 'Brasilien' => 'BR', + 'Britisch-Indischer Ozean' => 'IO', + 'Brunei' => 'BN', + 'Bulgarien' => 'BG', + 'Burkina Faso' => 'BF', + 'Burundi' => 'BI', + 'Chile' => 'CL', + 'China' => 'CN', + 'Christmas Island' => 'CX', + 'Cook Inseln' => 'CK', + 'Costa Rica' => 'CR', + 'Dänemark' => 'DK', + 'Deutschland' => 'DE', + 'Djibuti' => 'DJ', + 'Dominika' => 'DM', + 'Dominikanische Republik' => 'DO', + 'Ecuador' => 'EC', + 'El Salvador' => 'SV', + 'Elfenbeinküste' => 'CI', + 'Eritrea' => 'ER', + 'Estland' => 'EE', + 'Falkland Inseln' => 'FK', + 'Färöer Inseln' => 'FO', + 'Fidschi' => 'FJ', + 'Finnland' => 'FI', + 'Frankreich' => 'FR', + 'Französisch Guyana' => 'GF', + 'Französisch Polynesien' => 'PF', + 'Französisches Süd-Territorium' => 'TF', + 'Gabun' => 'GA', + 'Gambia' => 'GM', + 'Georgien' => 'GE', + 'Ghana' => 'GH', + 'Gibraltar' => 'GI', + 'Grenada' => 'GD', + 'Griechenland' => 'GR', + 'Grönland' => 'GL', + 'Großbritannien' => 'UK', + 'Großbritannien (UK)' => 'GB', + 'Guadeloupe' => 'GP', + 'Guam' => 'GU', + 'Guatemala' => 'GT', + 'Guinea' => 'GN', + 'Guinea Bissau' => 'GW', + 'Guyana' => 'GY', + 'Haiti' => 'HT', + 'Heard und McDonald Islands' => 'HM', + 'Honduras' => 'HN', + 'Hong Kong' => 'HK', + 'Indien' => 'IN', + 'Indonesien' => 'ID', + 'Irak' => 'IQ', + 'Iran' => 'IR', + 'Irland' => 'IE', + 'Island' => 'IS', + 'Israel' => 'IL', + 'Italien' => 'IT', + 'Jamaika' => 'JM', + 'Japan' => 'JP', + 'Jemen' => 'YE', + 'Jordanien' => 'JO', + 'Jugoslawien' => 'YU', + 'Kaiman Inseln' => 'KY', + 'Kambodscha' => 'KH', + 'Kamerun' => 'CM', + 'Kanada' => 'CA', + 'Kap Verde' => 'CV', + 'Kasachstan' => 'KZ', + 'Kenia' => 'KE', + 'Kirgisistan' => 'KG', + 'Kiribati' => 'KI', + 'Kokosinseln' => 'CC', + 'Kolumbien' => 'CO', + 'Komoren' => 'KM', + 'Kongo' => 'CG', + 'Kongo, Demokratische Republik' => 'CD', + 'Kosovo' => 'KO', + 'Kroatien' => 'HR', + 'Kuba' => 'CU', + 'Kuwait' => 'KW', + 'Laos' => 'LA', + 'Lesotho' => 'LS', + 'Lettland' => 'LV', + 'Libanon' => 'LB', + 'Liberia' => 'LR', + 'Libyen' => 'LY', + 'Liechtenstein' => 'LI', + 'Litauen' => 'LT', + 'Luxemburg' => 'LU', + 'Macao' => 'MO', + 'Madagaskar' => 'MG', + 'Malawi' => 'MW', + 'Malaysia' => 'MY', + 'Malediven' => 'MV', + 'Mali' => 'ML', + 'Malta' => 'MT', + 'Marianen' => 'MP', + 'Marokko' => 'MA', + 'Marshall Inseln' => 'MH', + 'Martinique' => 'MQ', + 'Mauretanien' => 'MR', + 'Mauritius' => 'MU', + 'Mayotte' => 'YT', + 'Mazedonien' => 'MK', + 'Mexiko' => 'MX', + 'Mikronesien' => 'FM', + 'Mocambique' => 'MZ', + 'Moldavien' => 'MD', + 'Monaco' => 'MC', + 'Mongolei' => 'MN', + 'Montenegro' => 'ME', + 'Montserrat' => 'MS', + 'Namibia' => 'NA', + 'Nauru' => 'NR', + 'Nepal' => 'NP', + 'Neukaledonien' => 'NC', + 'Neuseeland' => 'NZ', + 'Nicaragua' => 'NI', + 'Niederlande' => 'NL', + 'Niederländische Antillen' => 'AN', + 'Niger' => 'NE', + 'Nigeria' => 'NG', + 'Niue' => 'NU', + 'Nord Korea' => 'KP', + 'Norfolk Inseln' => 'NF', + 'Norwegen' => 'NO', + 'Oman' => 'OM', + 'Österreich' => 'AT', + 'Pakistan' => 'PK', + 'Palästina' => 'PS', + 'Palau' => 'PW', + 'Panama' => 'PA', + 'Papua Neuguinea' => 'PG', + 'Paraguay' => 'PY', + 'Peru' => 'PE', + 'Philippinen' => 'PH', + 'Pitcairn' => 'PN', + 'Polen' => 'PL', + 'Portugal' => 'PT', + 'Puerto Rico' => 'PR', + 'Qatar' => 'QA', + 'Reunion' => 'RE', + 'Ruanda' => 'RW', + 'Rumänien' => 'RO', + 'Rußland' => 'RU', + 'Saint Lucia' => 'LC', + 'Sambia' => 'ZM', + 'Samoa' => 'AS', + 'Samoa' => 'WS', + 'San Marino' => 'SM', + 'Sao Tome' => 'ST', + 'Saudi Arabien' => 'SA', + 'Schweden' => 'SE', + 'Schweiz' => 'CH', + 'Senegal' => 'SN', + 'Serbien' => 'RS', + 'Seychellen' => 'SC', + 'Sierra Leone' => 'SL', + 'Singapur' => 'SG', + 'Slowakei -slowakische Republik-' => 'SK', + 'Slowenien' => 'SI', + 'Solomon Inseln' => 'SB', + 'Somalia' => 'SO', + 'South Georgia, South Sandwich Isl.' => 'GS', + 'Spanien' => 'ES', + 'Sri Lanka' => 'LK', + 'St. Helena' => 'SH', + 'St. Kitts Nevis Anguilla' => 'KN', + 'St. Pierre und Miquelon' => 'PM', + 'St. Vincent' => 'VC', + 'Süd Korea' => 'KR', + 'Südafrika' => 'ZA', + 'Sudan' => 'SD', + 'Surinam' => 'SR', + 'Svalbard und Jan Mayen Islands' => 'SJ', + 'Swasiland' => 'SZ', + 'Syrien' => 'SY', + 'Tadschikistan' => 'TJ', + 'Taiwan' => 'TW', + 'Tansania' => 'TZ', + 'Thailand' => 'TH', + 'Timor' => 'TP', + 'Togo' => 'TG', + 'Tokelau' => 'TK', + 'Tonga' => 'TO', + 'Trinidad Tobago' => 'TT', + 'Tschad' => 'TD', + 'Tschechische Republik' => 'CZ', + 'Tunesien' => 'TN', + 'Türkei' => 'TR', + 'Turkmenistan' => 'TM', + 'Turks und Kaikos Inseln' => 'TC', + 'Tuvalu' => 'TV', + 'Uganda' => 'UG', + 'Ukraine' => 'UA', + 'Ungarn' => 'HU', + 'Uruguay' => 'UY', + 'Usbekistan' => 'UZ', + 'Vanuatu' => 'VU', + 'Vatikan' => 'VA', + 'Venezuela' => 'VE', + 'Vereinigte Arabische Emirate' => 'AE', + 'Vereinigte Staaten von Amerika' => 'US', + 'Vietnam' => 'VN', + 'Virgin Island (Brit.)' => 'VG', + 'Virgin Island (USA)' => 'VI', + 'Wallis et Futuna' => 'WF', + 'Weißrußland' => 'BY', + 'Westsahara' => 'EH', + 'Zentralafrikanische Republik' => 'CF', + 'Zimbabwe' => 'ZW', + 'Zypern' => 'CY' + ); + return $laender; + } +} diff --git a/phpwf/class.player.php b/phpwf/class.player.php index 39467ca5d..4b3822b9a 100644 --- a/phpwf/class.player.php +++ b/phpwf/class.player.php @@ -27,25 +27,10 @@ class Player { - public $DefautTemplates; - public $DefautTheme; - - /** @var erpooSystem $app the application object */ - public $app; + public Application $app; function __construct() { - $this->DefautTemplates="defaulttemplates"; - $this->DefautTheme="default"; - } - - function SetDefaultTemplates($path) - { - } - - function SetDefaultTheme($path) - { - } public function BuildNavigation() @@ -57,7 +42,7 @@ public function BuildNavigation() $this->app->Page->CreateNavigation($this->app->erp->Navigation()); } - public function Run($sessionObj) + public function Run(Session $sessionObj) { $this->app = $sessionObj->app; // play application only when layer 2 said that its ok @@ -149,6 +134,7 @@ public function Run($sessionObj) if($r2->isStatic()) { $allowed = $constr::AllowedVersion(); + $version_revision = ''; include(dirname(__DIR__) . '/version.php'); if((isset($allowed['max']) && ((float)$allowed['max'] < (float)$version_revision)) || diff --git a/phpwf/class.session.php b/phpwf/class.session.php index 3f3c3049a..26483d59c 100644 --- a/phpwf/class.session.php +++ b/phpwf/class.session.php @@ -1,4 +1,4 @@ - +*/ +?> check; } - - public function UserSessionCheck() - { - $this->check = false; - $this->reason = 'PLEASE_LOGIN'; - return true; - } - } diff --git a/phpwf/htmltags/class.form.php b/phpwf/htmltags/class.form.php index 3b2317fde..4ec4ebabc 100644 --- a/phpwf/htmltags/class.form.php +++ b/phpwf/htmltags/class.form.php @@ -291,7 +291,7 @@ function AddOptionsDimensionalArray($values) { foreach($values as $key=>$value) { - $this->options[] = array($value[wert],$value[schluessel]); + $this->options[] = array($value['wert'],$value['schluessel']); } } diff --git a/phpwf/plugins/class.acl.php b/phpwf/plugins/class.acl.php index 086dd676c..8b93ed221 100644 --- a/phpwf/plugins/class.acl.php +++ b/phpwf/plugins/class.acl.php @@ -557,6 +557,7 @@ public function Login() { $this->refresh_githash(); + $version_revision = ''; include dirname(__DIR__).'/../version.php'; $this->app->Tpl->Set('XENTRALVERSION',"V.".$version_revision); diff --git a/phpwf/plugins/class.formhandler.php b/phpwf/plugins/class.formhandler.php index c28d0d944..7e7cd5d10 100644 --- a/phpwf/plugins/class.formhandler.php +++ b/phpwf/plugins/class.formhandler.php @@ -1,4 +1,4 @@ - +*/ +?> value = $value; } - if(get_class($htmlobject)=="blindfield") + if(get_class($field->htmlobject)=="blindfield") $field->value=$field->htmlobject->value; diff --git a/phpwf/plugins/class.modulescriptcache.php b/phpwf/plugins/class.modulescriptcache.php index b7c79013d..5ece95090 100644 --- a/phpwf/plugins/class.modulescriptcache.php +++ b/phpwf/plugins/class.modulescriptcache.php @@ -322,9 +322,9 @@ private function includeChunk(string $chunkName, bool $isRoot = false) : void return; $manifestEntry = $this->assetManifest->$chunkName; - foreach ($manifestEntry->css as $cssFile) + foreach ($manifestEntry->css ?? [] as $cssFile) $this->renderedCss[] = $cssFile; - foreach ($manifestEntry->imports as $import) + foreach ($manifestEntry->imports ?? [] as $import) $this->includeChunk($import); if ($isRoot) diff --git a/phpwf/plugins/class.mysql.php b/phpwf/plugins/class.mysql.php index 083a04f69..5cde99149 100644 --- a/phpwf/plugins/class.mysql.php +++ b/phpwf/plugins/class.mysql.php @@ -1548,7 +1548,7 @@ public function LogIfError($echo = false) return false; } if(!empty($this->app)) { - $this->app->erp->LogFile(mysqli_real_escape_string($this->connection, $error)); + $this->app->Container->get('Logger')->error($error); } if($echo) { diff --git a/phpwf/plugins/class.phpwfapi.php b/phpwf/plugins/class.phpwfapi.php deleted file mode 100644 index 6e5287cab..000000000 --- a/phpwf/plugins/class.phpwfapi.php +++ /dev/null @@ -1,144 +0,0 @@ - -app=&$app; - } - - function ReBuildPageFrame() - { - $this->app->Tpl->ResetParser(); - $this->BuildPageFrame(); - } - - - function BuildPageFrame() - { - $this->app->Tpl->ReadTemplatesFromPath(__DIR__."/../defaulttemplates/"); - - // build template tree - $this->app->Page->LoadTheme($this->app->WFconf['defaulttheme']); - - if($this->app->User->GetType()=="") - $this->app->Page->CreateNavigation($this->app->WFconf['menu'][$this->app->WFconf['defaultgroup']]); - else - $this->app->Page->CreateNavigation($this->app->WFconf['menu'][$this->app->User->GetType()]); - - // start acutally application instance - $this->app->Tpl->ReadTemplatesFromPath("pages/content/_gen"); - $this->app->Tpl->ReadTemplatesFromPath("pages/content/"); - } - - - function StartRequestedCommand() - { - $defaultpage = $this->app->WFconf['defaultpage']; - $defaultpageaction = $this->app->WFconf['defaultpageaction']; - - $module = $this->app->Secure->GetGET('module','alpha'); - $action = $this->app->Secure->GetGET('action','alpha'); - - if(!file_exists("pages/".$module.".php")) - $module = $defaultpage; - - if($action=="") - $action = $defaultpageaction; - - if(!$this->app->acl->Check($this->app->User->GetType(),$module,$action)) - return; - - - // start module - if(file_exists("pages/".$module.".php")) - { - include("pages/".$module.".php"); - //create dynamical an object - $constr=strtoupper($module[0]).substr($module, 1); - $myApp = new $constr($this->app); - } - else - { - echo $this->app->WFM->Error("Module $module doesn't exists in pages/"); - - } - $this->app->acl->CheckTimeOut(); - } - - /// mit dem "erstellen Formular" einfach bearbeiten liste + formular anzeigen - function EasyTableList($tablename,$cols,$parsetarget,$pkname,$delmsg,$delmsgcol) - { - // show list - - // create html table - $table = new HTMLTable("0","100%"); - $table->AddRowAsHeading($cols); - - $all = $this->app->DB->SelectTable($tablename,$cols); - - $table->AddField($all); - - $action = $this->app->Secure->GetGET("action","alpha"); - $module = $this->app->Secure->GetGET("module","alpha"); - - $table->AddCompleteCol(0, - "bearbeiten"); - - $table->AddCompleteCol(0, - " - loeschen",$delmsgcol); - - $table->ChangingRowColors('#ffffff','#dddddd'); - - $this->app->Tpl->Set($parsetarget,$table->Get()); - } - - function Message($msg,$parsetarget='MSGBOX') - { - $this->app->Tpl->Add('MSGBOXTEXT',$msg); - $this->app->Tpl->Parse($parsetarget,"messagebox.tpl"); - } - // emailvorlage aus db senden - - function EmailFromTemplate($template,$to,$values) - { - $betreff = $this->app->DB->Select("SELECT betreff - FROM emailvorlagen WHERE name='$template' LIMIT 1"); - - $nachricht = $this->app->DB->Select("SELECT nachricht - FROM emailvorlagen WHERE name='$template' LIMIT 1"); - - if(count($values) > 0) - { - foreach($values as $key=>$value) - { - $nachricht = str_replace("%".$key."%",$value,$nachricht); - $betreff = str_replace("%".$key."%",$value,$betreff); - } - } - - $nachricht = str_replace('#BR#',"\n",$nachricht); - mail($to,$betreff,$nachricht,"From: ActConnect Team "); - - } -} -?> diff --git a/phpwf/plugins/class.picosafelogin.php b/phpwf/plugins/class.picosafelogin.php deleted file mode 100644 index 8e43f163a..000000000 --- a/phpwf/plugins/class.picosafelogin.php +++ /dev/null @@ -1,245 +0,0 @@ - -seconds_valid_password=180; - } - - // please overload these methods - function GetUserAES() - { - // PLEASE FILL WITH YOUR DATA!! - - // 32 signs - //return "soopu9goBoay9vongooth2ooLu8keed1"; - return $this->user_aes;//"soopu9goBoay9vongooth2ooLu8keed1"; - } - - function GetUserCounter() - { - // PLEASE FILL WITH YOUR DATA!! - return $this->user_counter;//179; - } - - function GetUserDatablock() - { - // PLEASE FILL WITH YOUR DATA!! - // 10 signs - return $this->user_datablock;//"eeng5jo7th"; - } - - function SetUserLastCounter($username,$counter) - { - // PLEASE FILL WITH YOUR DATA!! - // set internal counter from user to new value givn from givenOtp - } - - function IsPicosafeLocked($username) - { - // PLEASE FILL WITH YOUR DATA!! - return false; - } - - - function GetServerTimestamp() - { - // instead of the local time function a server time or something other can be used - date_default_timezone_set("UTC"); - return time(); - } - - /************************************************/ - // or use set methods to load user values from external - - function SetUserAES($aes) - { - $this->user_aes = $aes; - } - - function SetUserDatablock($datablock) - { - $this->user_datablock = $datablock; - } - - - function SetUserCounter($counter) - { - $this->user_counter = $counter; - } - - - function GetLastValidCounter() - { - return $this->last_valid_counter; - } - - - /************************************************/ - - function LoginOTP($givenOtp)//,$aes,$datablock,$counter)//$username) - { - $aes = $this->GetUserAES(); - - // $aes = substr($server_aes, 0, 32); - // $data = substr($server_aes, 32, 10); - - $counter = $this->GetUserCounter(); - $data = $this->GetUserDatablock(); - $locked = $this->IsPicosafeLocked(); - - - // check if device is locked? perhaps the user lost his device .... - if($locked) - { - $this->error_message = "Picosafe is locked"; - return false; - } - $datablock = null; - $result = $this->ParseOTP($givenOtp,$aes,$datablock); - - //check if is the right aes for the given user - if($result['datablock']!=$datablock && $datablock!="") - { - $this->error_message = "Wrong Key to given username"; - return false; - } - - // server counter is greater than aes counter - if($result['counter'] < $counter) - { - $this->error_message = "Server counter is greater than aes counter"; - return false; - } - - // time differences - $time_diff_abs_between_aes_server = abs($this->GetServerTimestamp() - $result['timestamp']); - - if($time_diff_abs_between_aes_server > $this->seconds_valid_password) - { - $this->error_message = "Time difference between server and aes greater than ".$this->seconds_valid_password." seconds"; - return false; - } - - // Update Counter in server - //$this->SetUserLastCounter($username,$result['counter']); - $this->last_valid_counter = $result['counter']; - - return true; - } - - function ParseOTP($givenOtp,$aes,$datablock = null) - { - // base64 Kodierung des Sticks korrigieren - $givenOtp = rtrim($givenOtp); - - // Sonderzeichen in korrekte Sonderzeichen umwandeln - // (diese werden vom Stick anders vorgegeben, um von - // unterschiedl. Tastaturlayouts unabhängig zu werden) - $cgivenOtp = strlen($givenOtp); - for($i = 0; $i < $cgivenOtp; $i++) { - if($givenOtp[$i] == "!") { $givenOtp[$i] = "/"; } - elseif($givenOtp[$i] == ".") { $givenOtp[$i] = "="; } - elseif($givenOtp[$i] == "-") { $givenOtp[$i] = "+"; } - } - - // erstes Zeichen pruefen ob z oder y - // abhaengig davon alle y durch z ersetzen und umgekehrt - $z = $givenOtp[0]; - $crypted = substr($givenOtp, 1); - - if($z == "y" or $z == "Y") { - $ccrypted = strlen($crypted); - for($i = 0; $i < $ccrypted; $i++) { - if ($crypted[$i] == 'y') { $crypted[$i] = "z"; } - elseif($crypted[$i] == 'Y') { $crypted[$i] = "Z"; } - elseif($crypted[$i] == 'z') { $crypted[$i] = "y"; } - elseif($crypted[$i] == 'Z') { $crypted[$i] = "Y"; } - } - } - - if($z == "Y" or $z == "Z") { - $ccrypted = strlen($crypted); - for($i = 0; $i < $ccrypted; $i++) { - if(ctype_upper($crypted[$i])) { - $crypted[$i] = strtolower($crypted[$i]); - } else { - $crypted[$i] = strtoupper($crypted[$i]); - } - } - } - - $crypted = base64_decode($crypted); - // gegebenes One Time Passwort mit AES entschluesseln - $td = mcrypt_module_open("rijndael-128", "", "ecb", ""); - $iv = mcrypt_create_iv(mcrypt_enc_get_iv_size($td), MCRYPT_DEV_URANDOM); - mcrypt_generic_init($td, $aes, $iv); - $plain = mdecrypt_generic($td, $crypted); - - - // aktueller Zaehlstand - $i = substr($plain, 0,1); - $j = substr($plain, 1,1); - $n = ord($i) + (ord($j) << 8); - $timestamp = (ord($plain[12]) << 24) + (ord($plain[13]) << 16) + (ord($plain[14]) << 8) + ord($plain[15]); - - // entschluesseltes Passwort aufteilen in - // und Datenblock - $plain = substr($plain, 2, 10); - - $result['counter']=$n; - $result['datablock']=$plain; - $result['timestamp']=$timestamp; - - - /* - echo "
"; - echo "Nummer: " . $n . "
"; - echo "Datenblock: " . $plain . " (" . $data . ")
"; - echo "Timestamp: " . $timestamp . "
"; - echo "Datetime: " . date("d.m.Y H:i:s",$timestamp) . "
"; - */ - //printf("4 Byte: %x \n", substr($plain,10)); - return $result; - } - -} - - diff --git a/phpwf/plugins/class.string.php b/phpwf/plugins/class.string.php index 00bfa3b16..49e9b8062 100644 --- a/phpwf/plugins/class.string.php +++ b/phpwf/plugins/class.string.php @@ -1,4 +1,4 @@ - +*/ +?> FindPercentValues($input); + $regexp = $this->BuildRegExp($array); - function __construct() - { - } - - function Convert($value,$input,$output) - { - if($input=="") - return $value; - + $elements = + preg_split($regexp, $value, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY); - /*if (strpos($a, '\\') !== false) - $input = str_replace('/','\/',$input);*/ + // input und elements stimmmen ueberein - $array = $this->FindPercentValues($input); - $regexp = $this->BuildRegExp($array); + $newout = $output; + $i = 0; + foreach ($array as $key => $value) { + $newout = str_replace($key, $elements[$i] ?? '', $newout); + $i++; + } + return $newout; + } - $elements = - preg_split($regexp,$value,-1,PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY); + private function BuildRegExp(array $array): string + { + $regexp = '/^'; + foreach ($array as $value) { + $value = str_replace('.', '\.', $value); + $value = str_replace('+', '\+', $value); + $value = str_replace('*', '\*', $value); + $value = str_replace('?', '\?', $value); + $regexp .= '(\S+)' . $value; + } + $regexp .= '/'; - // input und elements stimmmen ueberein + return $regexp; + } - $newout = $output; - $i = 0; - foreach($array as $key=>$value) + private function FindPercentValues(string $pattern): array { - $newout = str_replace($key,isset($elements[$i])?$elements[$i]:'',$newout); - $i++; - } - return $newout; - } + preg_match_all('/(?:(%[0-9]+)|.)/i', $pattern, $matches); + $hash = ''; + $collect = ''; + $start = true; + foreach ($matches[1] as $key => $value) { + if ($value == '') + $collecting = true; + else { + $collecting = false; + $oldhash = $hash ?? null; + $hash = $value; + } - /** - * @param string $string - * - * @return string - */ - public function removeUtf8Bom($string) { - if(!is_string($string) || strlen($string)< 3) { - return $string; - } - if(ord($string[0]) === 239 && ord($string[1]) === 187 && ord($string[2]) === 191) { - return substr($string,3); + if (!$collecting) { + if (!$start) + $replace[$oldhash] = $collect; + $collect = ''; + } else + $collect .= $matches[0][$key]; + $start = false; + } + $replace[$hash] = $collect; + return $replace; } - return $string; - } - - function BuildRegExp($array) - { - $regexp = '/^'; - foreach($array as $value) + public function decodeText($_str, $_form = true) { - $value = str_replace('.','\.',$value); - $value = str_replace('+','\+',$value); - $value = str_replace('*','\*',$value); - $value = str_replace('?','\?',$value); - $regexp .= '(\S+)'.$value; + if ($_form) { + $_str = str_replace('#BR#', "\r\n", $_str); + } else { + $_str = str_replace('#BR#', '
', $_str); + } + return ($_str); } - $regexp .= '/'; - return $regexp; - } - - function FindPercentValues($pattern) - { - preg_match_all('/(?:(%[0-9]+)|.)/i', $pattern, $matches); - $hash = ''; - $collect = ''; - $start = true; - foreach($matches[1] as $key=>$value) + public function fixeUmlaute(mixed $text): mixed { - if($value=="") - $collecting = true; - else - { - $collecting = false; - $oldhash = isset($hash)?$hash:null; - $hash = $value; - } + if (!is_string($text)) { + return $text; + } + $umlaute = $this->getUmlauteArray(); - if(!$collecting) - { - if(!$start) - $replace[$oldhash] = $collect; - $collect=""; - } - else - $collect .=$matches[0][$key]; - $start = false; + return str_replace(array_keys($umlaute), array_values($umlaute), $text); } - $replace[$hash] = $collect; - return $replace; - } - - function encodeText($string) - { - $string = str_replace("\\r\\n","#BR#",$string); - $string = str_replace("\n","#BR#",$string); - $encoded = htmlspecialchars(stripslashes($string), ENT_QUOTES); - - return $encoded; - } - - function decodeText($_str, $_form=true) - { - if ($_form) { - $_str = str_replace("#BR#", "\r\n", $_str); - } - else { - $_str = str_replace("#BR#", "
", $_str); - } - return($_str); - } - - function valid_utf8( $string ) - { - return !((bool)preg_match('~\xF5\xF6\xF7\xF8\xF9\xFA\xFB\xFC\xFD\xFE\xFF\xC0\xC1~ms',$string)); - } - - /** - * @param mixed $text - * - * @return string - */ - public function fixeUmlaute($text) { - if(!is_string($text)) { - return $text; + private function getUmlauteArray(): array + { + return [ + 'ü' => 'ü', + 'ä' => 'ä', + 'ö' => 'ö', + 'Ö' => 'Ö', + 'Ã?' => 'ß', + 'ß' => 'ß', + 'à ' => 'à', + 'á' => 'á', + 'â' => 'â', + 'ã' => 'ã', + 'ù' => 'ù', + 'ú' => 'ú', + 'û' => 'û', + 'Ù' => 'Ù', + 'Ú' => 'Ú', + 'Û' => 'Û', + 'Ü' => 'Ü', + 'ò' => 'ò', + 'ó' => 'ó', + 'ô' => 'ô', + 'è' => 'è', + 'é' => 'é', + 'ê' => 'ê', + 'ë' => 'ë', + 'À' => 'À', + 'Ã<81>' => 'Á', + 'Â' => 'Â', + 'Ã' => 'Ã', + 'Ä' => 'Ä', + 'Ã…' => 'Å', + 'Ç' => 'Ç', + 'È' => 'È', + 'É' => 'É', + 'Ê' => 'Ê', + 'Ë' => 'Ë', + 'ÃŒ' => 'Ì', + 'Ã<8d>' => 'Í', + 'ÃŽ' => 'Î', + 'Ã<8f>' => 'Ï', + 'Ñ' => 'Ñ', + 'Ã’' => 'Ò', + 'Ó' => 'Ó', + 'Ô' => 'Ô', + 'Õ' => 'Õ', + 'Ø' => 'Ø', + 'Ã¥' => 'å', + 'æ' => 'æ', + 'ç' => 'ç', + 'ì' => 'ì', + 'í' => 'í', + 'î' => 'î', + 'ï' => 'ï', + 'ð' => 'ð', + 'ñ' => 'ñ', + 'õ' => 'õ', + 'ø' => 'ø', + 'ý' => 'ý', + 'ÿ' => 'ÿ', + '€' => '€', + ]; } - $umlaute = $this->getUmlauteArray(); - - return str_replace(array_keys($umlaute),array_values($umlaute), $text); - } - /** - * @return array - */ - public function getUmlauteArray() { - return array( 'ü'=>'ü', 'ä'=>'ä', 'ö'=>'ö', 'Ö'=>'Ö', 'Ã?'=>'ß','ß'=>'ß', 'à '=>'à', 'á'=>'á', 'â'=>'â', 'ã'=>'ã', 'ù'=>'ù', 'ú'=>'ú', 'û'=>'û', 'Ù'=>'Ù', 'Ú'=>'Ú', 'Û'=>'Û', 'Ü'=>'Ü', 'ò'=>'ò', 'ó'=>'ó', 'ô'=>'ô', 'è'=>'è', 'é'=>'é', 'ê'=>'ê', 'ë'=>'ë', 'À'=>'À', 'Ã<81>'=>'Á', 'Â'=>'Â', 'Ã'=>'Ã', 'Ä'=>'Ä', 'Ã…'=>'Å', 'Ç'=>'Ç', 'È'=>'È', 'É'=>'É', 'Ê'=>'Ê', 'Ë'=>'Ë', 'ÃŒ'=>'Ì', 'Ã<8d>'=>'Í', 'ÃŽ'=>'Î', 'Ã<8f>'=>'Ï', 'Ñ'=>'Ñ', 'Ã’'=>'Ò', 'Ó'=>'Ó', 'Ô'=>'Ô', 'Õ'=>'Õ', 'Ø'=>'Ø', 'Ã¥'=>'å', 'æ'=>'æ', 'ç'=>'ç', 'ì'=>'ì', 'í'=>'í', 'î'=>'î', 'ï'=>'ï', 'ð'=>'ð', 'ñ'=>'ñ', 'õ'=>'õ', 'ø'=>'ø', 'ý'=>'ý', 'ÿ'=>'ÿ', '€'=>'€' ); - } + public function unicode_decode(string $content): string + { + $ISO10646XHTMLTrans = [ + '&' . '#34;' => '"', + '&' . '#38;' => '&', + '&' . '#39;' => ''', + '&' . '#60;' => '<', + '&' . '#62;' => '>', + '&' . '#128;' => '€', + '&' . '#160;' => '', + '&' . '#161;' => '¡', + '&' . '#162;' => '¢', + '&' . '#163;' => '£', + '&' . '#164;' => '¤', + '&' . '#165;' => '¥', + '&' . '#166;' => '¦', + '&' . '#167;' => '§', + '&' . '#168;' => '¨', + '&' . '#169;' => '©', + '&' . '#170;' => 'ª', + '&' . '#171;' => '«', + '&' . '#172;' => '¬', + '&' . '#173;' => '­', + '&' . '#174;' => '®', + '&' . '#175;' => '¯', + '&' . '#176;' => '°', + '&' . '#177;' => '±', + '&' . '#178;' => '²', + '&' . '#179;' => '³', + '&' . '#180;' => '´', + '&' . '#181;' => 'µ', + '&' . '#182;' => '¶', + '&' . '#183;' => '·', + '&' . '#184;' => '¸', + '&' . '#185;' => '¹', + '&' . '#186;' => 'º', + '&' . '#187;' => '»', + '&' . '#188;' => '¼', + '&' . '#189;' => '½', + '&' . '#190;' => '¾', + '&' . '#191;' => '¿', + '&' . '#192;' => 'À', + '&' . '#193;' => 'Á', + '&' . '#194;' => 'Â', + '&' . '#195;' => 'Ã', + '&' . '#196;' => 'Ä', + '&' . '#197;' => 'Å', + '&' . '#198;' => 'Æ', + '&' . '#199;' => 'Ç', + '&' . '#200;' => 'È', + '&' . '#201;' => 'É', + '&' . '#202;' => 'Ê', + '&' . '#203;' => 'Ë', + '&' . '#204;' => 'Ì', + '&' . '#205;' => 'Í', + '&' . '#206;' => 'Î', + '&' . '#207;' => 'Ï', + '&' . '#208;' => 'Ð', + '&' . '#209;' => 'Ñ', + '&' . '#210;' => 'Ò', + '&' . '#211;' => 'Ó', + '&' . '#212;' => 'Ô', + '&' . '#213;' => 'Õ', + '&' . '#214;' => 'Ö', + '&' . '#215;' => '×', + '&' . '#216;' => 'Ø', + '&' . '#217;' => 'Ù', + '&' . '#218;' => 'Ú', + '&' . '#219;' => 'Û', + '&' . '#220;' => 'Ü', + '&' . '#221;' => 'Ý', + '&' . '#222;' => 'Þ', + '&' . '#223;' => 'ß', + '&' . '#224;' => 'à', + '&' . '#225;' => 'á', + '&' . '#226;' => 'â', + '&' . '#227;' => 'ã', + '&' . '#228;' => 'ä', + '&' . '#229;' => 'å', + '&' . '#230;' => 'æ', + '&' . '#231;' => 'ç', + '&' . '#232;' => 'è', + '&' . '#233;' => 'é', + '&' . '#234;' => 'ê', + '&' . '#235;' => 'ë', + '&' . '#236;' => 'ì', + '&' . '#237;' => 'í', + '&' . '#238;' => 'î', + '&' . '#239;' => 'ï', + '&' . '#240;' => 'ð', + '&' . '#241;' => 'ñ', + '&' . '#242;' => 'ò', + '&' . '#243;' => 'ó', + '&' . '#244;' => 'ô', + '&' . '#245;' => 'õ', + '&' . '#246;' => 'ö', + '&' . '#247;' => '÷', + '&' . '#248;' => 'ø', + '&' . '#249;' => 'ù', + '&' . '#250;' => 'ú', + '&' . '#251;' => 'û', + '&' . '#252;' => 'ü', + '&' . '#253;' => 'ý', + '&' . '#254;' => 'þ', + '&' . '#255;' => 'ÿ', + '&' . '#338;' => 'Œ', + '&' . '#339;' => 'œ', + '&' . '#352;' => 'Š', + '&' . '#353;' => 'š', + '&' . '#376;' => 'Ÿ', + '&' . '#402;' => 'ƒ', + '&' . '#710;' => 'ˆ', + '&' . '#732;' => '˜', + '&' . '#913;' => 'Α', + '&' . '#914;' => 'Β', + '&' . '#915;' => 'Γ', + '&' . '#916;' => 'Δ', + '&' . '#917;' => 'Ε', + '&' . '#918;' => 'Ζ', + '&' . '#919;' => 'Η', + '&' . '#920;' => 'Θ', + '&' . '#921;' => 'Ι', + '&' . '#922;' => 'Κ', + '&' . '#923;' => 'Λ', + '&' . '#924;' => 'Μ', + '&' . '#925;' => 'Ν', + '&' . '#926;' => 'Ξ', + '&' . '#927;' => 'Ο', + '&' . '#928;' => 'Π', + '&' . '#929;' => 'Ρ', + '&' . '#931;' => 'Σ', + '&' . '#932;' => 'Τ', + '&' . '#933;' => 'Υ', + '&' . '#934;' => 'Φ', + '&' . '#935;' => 'Χ', + '&' . '#936;' => 'Ψ', + '&' . '#937;' => 'Ω', + '&' . '#945;' => 'α', + '&' . '#946;' => 'β', + '&' . '#947;' => 'γ', + '&' . '#948;' => 'δ', + '&' . '#949;' => 'ε', + '&' . '#950;' => 'ζ', + '&' . '#951;' => 'η', + '&' . '#952;' => 'θ', + '&' . '#953;' => 'ι', + '&' . '#954;' => 'κ', + '&' . '#955;' => 'λ', + '&' . '#956;' => 'μ', + '&' . '#957;' => 'ν', + '&' . '#958;' => 'ξ', + '&' . '#959;' => 'ο', + '&' . '#960;' => 'π', + '&' . '#961;' => 'ρ', + '&' . '#962;' => 'ς', + '&' . '#963;' => 'σ', + '&' . '#964;' => 'τ', + '&' . '#965;' => 'υ', + '&' . '#966;' => 'φ', + '&' . '#967;' => 'χ', + '&' . '#968;' => 'ψ', + '&' . '#969;' => 'ω', + '&' . '#977;' => 'ϑ', + '&' . '#978;' => 'ϒ', + '&' . '#982;' => 'ϖ', + '&' . '#8194;' => ' ', + '&' . '#8195;' => ' ', + '&' . '#8201;' => ' ', + '&' . '#8204;' => '‌', + '&' . '#8205;' => '‍', + '&' . '#8206;' => '‎', + '&' . '#8207;' => '‏', + '&' . '#8211;' => '–', + '&' . '#8212;' => '—', + '&' . '#8216;' => '‘', + '&' . '#8217;' => '’', + '&' . '#8218;' => '‚', + '&' . '#8220;' => '“', + '&' . '#8221;' => '”', + '&' . '#8222;' => '„', + '&' . '#8224;' => '†', + '&' . '#8225;' => '‡', + '&' . '#8226;' => '•', + '&' . '#8230;' => '…', + '&' . '#8240;' => '‰', + '&' . '#8242;' => '′', + '&' . '#8243;' => '″', + '&' . '#8249;' => '‹', + '&' . '#8250;' => '›', + '&' . '#8254;' => '‾', + '&' . '#8260;' => '⁄', + '&' . '#8364;' => '€', + '&' . '#8465;' => 'ℑ', + '&' . '#8472;' => '℘', + '&' . '#8476;' => 'ℜ', + '&' . '#8482;' => '™', + '&' . '#8501;' => 'ℵ', + '&' . '#8592;' => '←', + '&' . '#8593;' => '↑', + '&' . '#8594;' => '→', + '&' . '#8595;' => '↓', + '&' . '#8596;' => '↔', + '&' . '#8629;' => '↵', + '&' . '#8656;' => '⇐', + '&' . '#8657;' => '⇑', + '&' . '#8658;' => '⇒', + '&' . '#8659;' => '⇓', + '&' . '#8660;' => '⇔', + '&' . '#8704;' => '∀', + '&' . '#8706;' => '∂', + '&' . '#8707;' => '∃', + '&' . '#8709;' => '∅', + '&' . '#8711;' => '∇', + '&' . '#8712;' => '∈', + '&' . '#8713;' => '∉', + '&' . '#8715;' => '∋', + '&' . '#8719;' => '∏', + '&' . '#8721;' => '∑', + '&' . '#8722;' => '−', + '&' . '#8727;' => '∗', + '&' . '#8730;' => '√', + '&' . '#8733;' => '∝', + '&' . '#8734;' => '∞', + '&' . '#8736;' => '∠', + '&' . '#8743;' => '∧', + '&' . '#8744;' => '∨', + '&' . '#8745;' => '∩', + '&' . '#8746;' => '∪', + '&' . '#8747;' => '∫', + '&' . '#8756;' => '∴', + '&' . '#8764;' => '∼', + '&' . '#8773;' => '≅', + '&' . '#8776;' => '≈', + '&' . '#8800;' => '≠', + '&' . '#8801;' => '≡', + '&' . '#8804;' => '≤', + '&' . '#8805;' => '≥', + '&' . '#8834;' => '⊂', + '&' . '#8835;' => '⊃', + '&' . '#8836;' => '⊄', + '&' . '#8838;' => '⊆', + '&' . '#8839;' => '⊇', + '&' . '#8853;' => '⊕', + '&' . '#8855;' => '⊗', + '&' . '#8869;' => '⊥', + '&' . '#8901;' => '⋅', + '&' . '#8968;' => '⌈', + '&' . '#8969;' => '⌉', + '&' . '#8970;' => '⌊', + '&' . '#8971;' => '⌋', + '&' . '#9001;' => '⟨', + '&' . '#9002;' => '⟩', + '&' . '#9674;' => '◊', + '&' . '#9824;' => '♠', + '&' . '#9827;' => '♣', + '&' . '#9829;' => '♥', + '&' . '#9830;' => '♦', + ]; - function unicode_decode($content) { - $ISO10646XHTMLTrans = array( - "&"."#34;" => """, - "&"."#38;" => "&", - "&"."#39;" => "'", - "&"."#60;" => "<", - "&"."#62;" => ">", - "&"."#128;" => "€", - "&"."#160;" => "", - "&"."#161;" => "¡", - "&"."#162;" => "¢", - "&"."#163;" => "£", - "&"."#164;" => "¤", - "&"."#165;" => "¥", - "&"."#166;" => "¦", - "&"."#167;" => "§", - "&"."#168;" => "¨", - "&"."#169;" => "©", - "&"."#170;" => "ª", - "&"."#171;" => "«", - "&"."#172;" => "¬", - "&"."#173;" => "­", - "&"."#174;" => "®", - "&"."#175;" => "¯", - "&"."#176;" => "°", - "&"."#177;" => "±", - "&"."#178;" => "²", - "&"."#179;" => "³", - "&"."#180;" => "´", - "&"."#181;" => "µ", - "&"."#182;" => "¶", - "&"."#183;" => "·", - "&"."#184;" => "¸", - "&"."#185;" => "¹", - "&"."#186;" => "º", - "&"."#187;" => "»", - "&"."#188;" => "¼", - "&"."#189;" => "½", - "&"."#190;" => "¾", - "&"."#191;" => "¿", - "&"."#192;" => "À", - "&"."#193;" => "Á", - "&"."#194;" => "Â", - "&"."#195;" => "Ã", - "&"."#196;" => "Ä", - "&"."#197;" => "Å", - "&"."#198;" => "Æ", - "&"."#199;" => "Ç", - "&"."#200;" => "È", - "&"."#201;" => "É", - "&"."#202;" => "Ê", - "&"."#203;" => "Ë", - "&"."#204;" => "Ì", - "&"."#205;" => "Í", - "&"."#206;" => "Î", - "&"."#207;" => "Ï", - "&"."#208;" => "Ð", - "&"."#209;" => "Ñ", - "&"."#210;" => "Ò", - "&"."#211;" => "Ó", - "&"."#212;" => "Ô", - "&"."#213;" => "Õ", - "&"."#214;" => "Ö", - "&"."#215;" => "×", - "&"."#216;" => "Ø", - "&"."#217;" => "Ù", - "&"."#218;" => "Ú", - "&"."#219;" => "Û", - "&"."#220;" => "Ü", - "&"."#221;" => "Ý", - "&"."#222;" => "Þ", - "&"."#223;" => "ß", - "&"."#224;" => "à", - "&"."#225;" => "á", - "&"."#226;" => "â", - "&"."#227;" => "ã", - "&"."#228;" => "ä", - "&"."#229;" => "å", - "&"."#230;" => "æ", - "&"."#231;" => "ç", - "&"."#232;" => "è", - "&"."#233;" => "é", - "&"."#234;" => "ê", - "&"."#235;" => "ë", - "&"."#236;" => "ì", - "&"."#237;" => "í", - "&"."#238;" => "î", - "&"."#239;" => "ï", - "&"."#240;" => "ð", - "&"."#241;" => "ñ", - "&"."#242;" => "ò", - "&"."#243;" => "ó", - "&"."#244;" => "ô", - "&"."#245;" => "õ", - "&"."#246;" => "ö", - "&"."#247;" => "÷", - "&"."#248;" => "ø", - "&"."#249;" => "ù", - "&"."#250;" => "ú", - "&"."#251;" => "û", - "&"."#252;" => "ü", - "&"."#253;" => "ý", - "&"."#254;" => "þ", - "&"."#255;" => "ÿ", - "&"."#338;" => "Œ", - "&"."#339;" => "œ", - "&"."#352;" => "Š", - "&"."#353;" => "š", - "&"."#376;" => "Ÿ", - "&"."#402;" => "ƒ", - "&"."#710;" => "ˆ", - "&"."#732;" => "˜", - "&"."#913;" => "Α", - "&"."#914;" => "Β", - "&"."#915;" => "Γ", - "&"."#916;" => "Δ", - "&"."#917;" => "Ε", - "&"."#918;" => "Ζ", - "&"."#919;" => "Η", - "&"."#920;" => "Θ", - "&"."#921;" => "Ι", - "&"."#922;" => "Κ", - "&"."#923;" => "Λ", - "&"."#924;" => "Μ", - "&"."#925;" => "Ν", - "&"."#926;" => "Ξ", - "&"."#927;" => "Ο", - "&"."#928;" => "Π", - "&"."#929;" => "Ρ", - "&"."#931;" => "Σ", - "&"."#932;" => "Τ", - "&"."#933;" => "Υ", - "&"."#934;" => "Φ", - "&"."#935;" => "Χ", - "&"."#936;" => "Ψ", - "&"."#937;" => "Ω", - "&"."#945;" => "α", - "&"."#946;" => "β", - "&"."#947;" => "γ", - "&"."#948;" => "δ", - "&"."#949;" => "ε", - "&"."#950;" => "ζ", - "&"."#951;" => "η", - "&"."#952;" => "θ", - "&"."#953;" => "ι", - "&"."#954;" => "κ", - "&"."#955;" => "λ", - "&"."#956;" => "μ", - "&"."#957;" => "ν", - "&"."#958;" => "ξ", - "&"."#959;" => "ο", - "&"."#960;" => "π", - "&"."#961;" => "ρ", - "&"."#962;" => "ς", - "&"."#963;" => "σ", - "&"."#964;" => "τ", - "&"."#965;" => "υ", - "&"."#966;" => "φ", - "&"."#967;" => "χ", - "&"."#968;" => "ψ", - "&"."#969;" => "ω", - "&"."#977;" => "ϑ", - "&"."#978;" => "ϒ", - "&"."#982;" => "ϖ", - "&"."#8194;" => " ", - "&"."#8195;" => " ", - "&"."#8201;" => " ", - "&"."#8204;" => "‌", - "&"."#8205;" => "‍", - "&"."#8206;" => "‎", - "&"."#8207;" => "‏", - "&"."#8211;" => "–", - "&"."#8212;" => "—", - "&"."#8216;" => "‘", - "&"."#8217;" => "’", - "&"."#8218;" => "‚", - "&"."#8220;" => "“", - "&"."#8221;" => "”", - "&"."#8222;" => "„", - "&"."#8224;" => "†", - "&"."#8225;" => "‡", - "&"."#8226;" => "•", - "&"."#8230;" => "…", - "&"."#8240;" => "‰", - "&"."#8242;" => "′", - "&"."#8243;" => "″", - "&"."#8249;" => "‹", - "&"."#8250;" => "›", - "&"."#8254;" => "‾", - "&"."#8260;" => "⁄", - "&"."#8364;" => "€", - "&"."#8465;" => "ℑ", - "&"."#8472;" => "℘", - "&"."#8476;" => "ℜ", - "&"."#8482;" => "™", - "&"."#8501;" => "ℵ", - "&"."#8592;" => "←", - "&"."#8593;" => "↑", - "&"."#8594;" => "→", - "&"."#8595;" => "↓", - "&"."#8596;" => "↔", - "&"."#8629;" => "↵", - "&"."#8656;" => "⇐", - "&"."#8657;" => "⇑", - "&"."#8658;" => "⇒", - "&"."#8659;" => "⇓", - "&"."#8660;" => "⇔", - "&"."#8704;" => "∀", - "&"."#8706;" => "∂", - "&"."#8707;" => "∃", - "&"."#8709;" => "∅", - "&"."#8711;" => "∇", - "&"."#8712;" => "∈", - "&"."#8713;" => "∉", - "&"."#8715;" => "∋", - "&"."#8719;" => "∏", - "&"."#8721;" => "∑", - "&"."#8722;" => "−", - "&"."#8727;" => "∗", - "&"."#8730;" => "√", - "&"."#8733;" => "∝", - "&"."#8734;" => "∞", - "&"."#8736;" => "∠", - "&"."#8743;" => "∧", - "&"."#8744;" => "∨", - "&"."#8745;" => "∩", - "&"."#8746;" => "∪", - "&"."#8747;" => "∫", - "&"."#8756;" => "∴", - "&"."#8764;" => "∼", - "&"."#8773;" => "≅", - "&"."#8776;" => "≈", - "&"."#8800;" => "≠", - "&"."#8801;" => "≡", - "&"."#8804;" => "≤", - "&"."#8805;" => "≥", - "&"."#8834;" => "⊂", - "&"."#8835;" => "⊃", - "&"."#8836;" => "⊄", - "&"."#8838;" => "⊆", - "&"."#8839;" => "⊇", - "&"."#8853;" => "⊕", - "&"."#8855;" => "⊗", - "&"."#8869;" => "⊥", - "&"."#8901;" => "⋅", - "&"."#8968;" => "⌈", - "&"."#8969;" => "⌉", - "&"."#8970;" => "⌊", - "&"."#8971;" => "⌋", - "&"."#9001;" => "⟨", - "&"."#9002;" => "⟩", - "&"."#9674;" => "◊", - "&"."#9824;" => "♠", - "&"."#9827;" => "♣", - "&"."#9829;" => "♥", - "&"."#9830;" => "♦" - ); - - return str_replace(array_keys($ISO10646XHTMLTrans), array_values($ISO10646XHTMLTrans), $content); - } + return str_replace(array_keys($ISO10646XHTMLTrans), array_values($ISO10646XHTMLTrans), $content); + } - /** - * @param string $string - * - * @return string - */ - public function ReadyForPDF($string='') - { - return trim( - html_entity_decode( - str_replace( - ['“','„','–',"’","'","NONBLOCKINGZERO"], - ['"','','-',"'","'",''], - $string - ), - ENT_QUOTES, - 'UTF-8' - ) - ); - } + public function ReadyForPDF(string $string = ''): string + { + return trim( + html_entity_decode( + str_replace( + ['“', '„', '–', '’', ''', 'NONBLOCKINGZERO'], + ['"', '', '-', "'", "'", ''], + $string, + ), + ENT_QUOTES, + 'UTF-8', + ), + ); + } } diff --git a/phpwf/plugins/class.templateparser.php b/phpwf/plugins/class.templateparser.php index 8e1def444..40875dcc9 100644 --- a/phpwf/plugins/class.templateparser.php +++ b/phpwf/plugins/class.templateparser.php @@ -307,7 +307,7 @@ protected function addPath($_path) protected function pathLoaded($_path) { - if(!$this->pathes)return false; + if(!isset($this->pathes))return false; $rpos = strrpos($_path, '/www/'); if($rpos !== false) { diff --git a/phpwf/plugins/class.user.php b/phpwf/plugins/class.user.php index 29a4954e6..a4beb2ca2 100644 --- a/phpwf/plugins/class.user.php +++ b/phpwf/plugins/class.user.php @@ -472,7 +472,7 @@ public function GetName() } $this->loadAddressRowInCacheProperty(); - return $this->cache[$cacheKey]['name']; + return $this->cache[$cacheKey]['name'] ?? null; } /** diff --git a/phpwf/plugins/class.wfmonitor.php b/phpwf/plugins/class.wfmonitor.php deleted file mode 100644 index 15c7095a5..000000000 --- a/phpwf/plugins/class.wfmonitor.php +++ /dev/null @@ -1,44 +0,0 @@ - -app = &$app; - } - - - function Error($msg) - { - $this->ErrorBox($msg); - } - - - - function ErrorBox($content) - { - $box .=" - - -
phpWebFrame Error: $content
"; - - echo $box; - } -} -?> diff --git a/phpwf/types/class.simplelist.php b/phpwf/types/class.simplelist.php index bf4f86922..735c4eb08 100644 --- a/phpwf/types/class.simplelist.php +++ b/phpwf/types/class.simplelist.php @@ -1,4 +1,4 @@ - +*/ +?> actual >=0 && $this->actual < $this->items) return $this->List[$this->actual]; - return FALSE; + $return = false; + return $return; } diff --git a/phpwf/widgets/childtable.php b/phpwf/widgets/childtable.php deleted file mode 100644 index 25f2b3f95..000000000 --- a/phpwf/widgets/childtable.php +++ /dev/null @@ -1,249 +0,0 @@ - - - * @author coma ag - * @author *105 - Multimediabüro - * @version 1.0 - * @since PHP 4.x - */ -class ChildTable { - - /** - * Target template to wich the table will be parsed. [Default: PAGE] - * @type string - */ - var $parsetarget; - - /** - * HTMLTable. Apply format changes to this object. - * @type Object - * @access public - */ - var $table; - - var $editdate; - var $datasetssql; - - - var $arrayuse; - - /** - * Constructor method - * - * @param $app Default application class - * - * @return Generated object ($this) - * @access public - */ - function __construct(&$app, $name, $parsetarget="PAGE",$editdate=false) { - $this->app = &$app; - $this->parsetarget=$parsetarget; - $this->name=$name; - $this->editdate = $editdate; - } // end of constructor - - - // defines all datasets - function DataSets($sql) { - $this->datasetssql = $sql; - } // end of function - - function Register($pointer, $event, $function) { - $this->events[$event] = $function; - $this->pointer = $pointer; - } // end of function - - function CatchEvents() { - $event=$this->app->Secure->GetPOST("{$this->name}_event"); - - if(is_array($event)){ - $function = $this->events[key($event)]; - $this->pointer->$function($event[key($event)]); - } // end of if - } // end of function - - - function MarkLineIfColHasValue($col,$value,$replace,$exclude) - { - $this->mark_col = $col; - $this->mark_value = $value; - $this->mark_replace = $replace; - $this->mark_exclude = $exclude; - - $this->mark = true; - } - - /* Diese Funktion dient fuer tabellen in denen die sipchildtables zeilen verschiedene bedeutungen haben - */ - - function ShowMultiRow($contentArr){ - $this->arrayuse = true; - - //$this->app->Table->CreateTable($this->datasetssql, $this->parsetarget, 400); - //$contentArr = $this->app->DB->SelectArr( $this->datasetssql ); - $this->app->Table->CreateTableFromArray($contentArr, $this->parsetarget, 450); - //$this->app->Table->FormatCondition(1, "", "%value%", array(5,6)); - - $this->Show(); - } - - function Show() { - $this->CatchEvents(); - if(!$this->arrayuse) - $this->app->Table->CreateTable($this->datasetssql, $this->parsetarget, 400); - - - $numberofdatasets = count($this->app->DB->SelectArr($this->datasetssql)); - $module = $this->app->Secure->GetGET("module"); - $id = $this->app->Secure->GetGET("id"); - - $delbutton = "name}_event[delete]\" value=\"%value%\">"; - // $editbutton = "name}_event[editdate]\" value=\"%value%\">"; - $editbutton = "name}'\" - class=\"bu_edit\" title=\"Datum bearbeiten\">"; - $downbutton = "name}_event[down]\" value=\"%value%\">"; - $upbutton = "name}_event[up]\" value=\"%value%\">"; - $addbutton = "name}'\" - class=\"bu_add\" title=\"Nach diesem Eintrag einfügen\">"; - $addfbutton = "name}'\" - class=\"bu_addf\" title=\"Nach diesem Eintrag einfügen\">"; - - - $menunew = $addbutton; - $menusingle = $delbutton.$addbutton.$addfbutton; - $menufirst = $delbutton.$addbutton.$addfbutton.$downbutton; - $menu = $delbutton.$addbutton.$addfbutton.$downbutton.$upbutton; - $menulast = $delbutton.$addbutton.$addfbutton.$upbutton; - - // falls zeit relation berarbeitet werden soll - if($this->editdate) - { - $menulast .= $editbutton; - $menu .= $editbutton; - $menufirst .= $editbutton; - $menusingle .= $editbutton; - - $header = ' - - - Nr. - Name - ID - Gültig von - bis - '; - } - else { - $header = ' - - - Nr. - Name - ID - '; - } - - - if(count($this->events)>0) - $header .= 'Aktion'; - - $header .= ' - - '; - - $this->app->Table->HeadingTop($header); - - - if($this->editdate){ - $arr = array(1, 2, 3, 4,6); - } - else{ - $arr = array(1, 2, 3, 5); - } - - // erstellen der richtigen menues - for($i=1;$i<=$numberofdatasets;$i++) { - if($numberofdatasets==1) - $this->app->Table->FormatCondition(1, 1, $menusingle, $arr); - else if($i==1) - $this->app->Table->FormatCondition(1, 1, $menufirst, $arr); - else if($i == $numberofdatasets) - $this->app->Table->FormatCondition(1, $numberofdatasets, $menulast, $arr); - else - $this->app->Table->FormatCondition(1, $i, $menu, $arr); - } // end of for - - - if(count($this->events)==0) { - if($this->editdate){ - $this->app->Table->FormatCondition(6, 0, "%value%", array(5,6)); - $this->app->Table->HideCol(6); - } - else { - $this->app->Table->FormatCondition(5, 0, "%value%", array(4, 5)); - $this->app->Table->HideCol(5); - $this->app->Table->HideCol(4); // menu ausblenden falls keine events registriert sind - } - } else { - // inaktiv zeile - if($this->editdate){ - $this->app->Table->FormatCondition(6, 0, "%value%", array(5, 6)); - $this->app->Table->HideCol(6); - } - else { - $this->app->Table->FormatCondition(5, 0, "%value%", array(4, 5)); - $this->app->Table->HideCol(5); - } - } // end of if/else - - - - if($this->mark && count($this->events)!=0) { - $this->app->Table->FormatCondition($this->mark_col, $this->mark_value, $this->mark_replace,$this->mark_exclude); - $this->app->Table->HideCol(6); - } - - - if ($numberofdatasets > 0) - $this->app->Table->Show(); - else { - $table = ' - - [TABLEHEADER] - - - - '; - - if(count($this->events)!=0) - $table .= ''; - - $table .= '
keine Elemente vorhanden'.$menunew.'
'; - //$this->app->Tpl->Set(TABLEHEADER,$header); - $this->app->Tpl->Set($this->parsetarget,$table, array('TABLEHEADER')); - } // end of if - } // end of function - -} // end of class -?> \ No newline at end of file diff --git a/phpwf/widgets/grouptable.php b/phpwf/widgets/grouptable.php index a6bc524d8..d2faecc5c 100644 --- a/phpwf/widgets/grouptable.php +++ b/phpwf/widgets/grouptable.php @@ -1,4 +1,4 @@ - +*/ +?> app->Secure->GetGET("event"); $eventid = $this->app->Secure->GetGET("eventid"); diff --git a/phpwf/widgets/table.php b/phpwf/widgets/table.php deleted file mode 100644 index a53d6049c..000000000 --- a/phpwf/widgets/table.php +++ /dev/null @@ -1,774 +0,0 @@ - - - * @author coma ag - * @author *105 - Multimediabüro - * @version 1.0 - * @since PHP 4.x - */ -class Table { - - /** - * Target template to wich the table will be parsed. [Default: PAGE] - * @type string - */ - var $parsetarget; - - /** - * HTMLTable. Apply format changes to this object. - * @type Object - * @access public - */ - var $table; - - /** - * SQL statement to fill table content. Altrnatively use CreateTableFromArray(). - * @type string - * @access private - */ - var $sql; - - /** - * Data array to fill table content. Altrnatively use CreateTableFromSQL(). - * @type string - * @access private - */ - var $contentArr; - - /** - * Indicates whether data is gathered from SQL statement od provided array - * @type bool - * @access private - */ - var $fromSQL = true; - - var $searchform=false; // normally true - var $sortheading=true; - var $html; - var $menu; - var $rowlimit=0; - - - /** - * Constructor method - * - * @param $app Default application class - * - * @return Generated object ($this) - * @access public - */ - function __construct($app) { - $this->app = $app; - $this->app->Tpl->Set('TABLEHEADER', ""); - $this->app->Tpl->Set('TABLEFOOTER', ""); - } // end of constructor - - /** - * Standard method to create a table. The data is gathered - * from provided sql statement and formatted, finally printed - * to screen. - * - *

- * NOTE: Method is deprecated. Use CreateTableFromArray() or - * CreateTableFromSQL() instead! - * - * - * @param $sql SQL stemenet (Select) to fill the table content - * @param $parsetarget Target template to where the content is parsed [Default: PAGE] - * - * @access public - */ - function CreateTable($sql, $parsetarget='PAGE',$size="") { - $this->CreateTableFromSQL($sql, $parsetarget,$size); - } // end of function - - /** - * Standard method to create a table: The data is gathered - * from provided sql statement and formatted, finally printed - * to screen. - * - * @param $sql SQL stemenet (Select) to fill the table content - * @param $parsetarget Target template to where the content is parsed [Default: PAGE] - * - * @access public - */ - function CreateTableFromSQL($sql, $parsetarget='PAGE', $size="") - { - $order=$this->app->Secure->GetGET("order"); - if($order!="") - $sql = $sql." ORDER By $order"; - - $this->parsetarget = $parsetarget; - $this->sql = $sql; - $this->contentArr = $this->app->DB->SelectArr($this->sql); - $this->html = ""; - $this->fromSQL = true; - $this->InitTable($size); - } // end of function - - /** - * Alternative method to create a table: The data is gathered - * from provided data array, then formatted and finally printed - * to screen. - * - * @param $contentArr SQL stemenet (Select) to fill the table content - * @param $parsetarget Target template to where the content is parsed [Default: PAGE] - * - * @access public - */ - function CreateTableFromArray($contentArr, $parsetarget=PAGE, $size="") - { - /* - echo "
";
-	print_r($contentArr[0]);
-  	echo "
"; - */ - - - $order=$this->app->Secure->GetGET("order"); - if($order!="") - $contentArr = $this->SortTableArray($contentArr,$order); - - $this->parsetarget = $parsetarget; - $this->contentArr = $contentArr; - $this->fromSQL = false; - $this->InitTable($size); - } // end of function - - - function SortTableArray($data,$order) - { - - // to be sure, that we have a numeric array - for ($i=0; $i$value) - { - $numarr[$i][]=$value; - } - } - $data = $numarr; - - // Obtain a list of columns - // We have an array of rows, but array_multisort() requires an array of columns, - // so we use the below code to obtain the columns, then perform the sorting. - if(count($data)>0) - foreach ($data as $key => $row) { - for($i=0;$itable = new HTMLTable("0",$size,"","0","0"); - $this->table->SetTDClass("divider"); - $this->table->ChangingRowColors('#F5F5F5', ''); - $this->Generate(); - } // end of function - - /** - * Use Array $contentArr to fill table with data - * - * @access private - */ - function Generate($fromSQL=true) { - // Check for empty array - if (count($this->contentArr) < 1) - return; - - // Build table - while (list($key, $row) = @each($this->contentArr)) { - - $this->table->NewRow(); - while (list($col, $val) = @each($row)) { - - if(count($this->cols)==0) { - $this->table->AddCol($val); - } else { - if(isset($this->cols[$col])) - $this->table->AddCol($val); - } // end of if - } // end of inner while - } // end of outer while - } // end of function - - - function DeleteAsk($colnumber,$msg,$module,$action){ - $link = " - loeschen"; - - $this->table->ReplaceCol($colnumber,$link); - } // end of function - - - function ReplaceCol($colnumber,$link) { - $this->table->ReplaceCol($colnumber,$link); - } // end of function - - - function RowMenu($col, $menu) { - $this->menu = $menu; - - switch($menu) { - case 'special': - // $this->RowMenuSpecial($col, "personenform"); - break; - - case 'personen': - $this->RowMenuGeneric($col, "personenform", true, true); - break; - - case 'formel': - $this->RowMenuGeneric($col, "formelform", false, true); - break; - - case 'produkt': - $this->RowMenuGeneric($col, "produktform", true, true); - break; - - case 'hut': - $this->RowMenuHut($col, "hutform", true, true); - break; - - case 'statistikauswertung_ordner': - $this->RowMenuAuswertung($col, "statistikauswerten"); - break; - - case 'statistikverwaltung_ordner': - $this->RowMenuVerwaltungOrdner($col, "statistikverwalten"); - break; - - case 'statistikverwaltung_formeln': - $this->RowMenuVerwaltungFormeln($col, "statistikverwaltenformel"); - break; - - default: - $this->RowMenuGeneric($col, $menu."form", true); - } // end of switch - - } // end of function - - /* spalten nummer ( von 1 gezaehlt), dann der if wert also wenn value gleich - dem aktuellen Wert in der Zelle ist, dann wird der text in der - Zeile durch replacestring ersetzt. Im replacestring muss - sich %value% befinden, an der Stelle wird der alte Wert eingefuegt. - - Falls bestimmte Spalten nicht ersetzt werden sollen, koennen diese - im array dontreplacecols angegeben werden. - */ - - function FormatCondition($col, $value, $replacestring, $dontreplacecols=array()) { - $rows = count($this->table->Table); - for($i=0;$i<$rows;$i++) { - - // check ob der wert in der spalte mit dem $value uebereinstimmt - // wenn ja ersetze jede zeile auser die aus dem array dontreplacecols - if($this->table->Table[$i][$col-1]==$value) { - - // ersetze spalten auser die in dontreplacecols - $cols = count($this->table->Table[$i]); - - for($j=0;$j<$cols;$j++) { - if(!in_array($j+1,$dontreplacecols)) { - $content = $this->table->Table[$i][$j]; - $this->table->Table[$i][$j] = str_replace("%value%", $content, $replacestring); - } // end of if - } // end of for - } // end of if - } // end of for - } // end of function - - /** - * Formats a table coolumn with SIP specific format options. - * Available options are listed below: - *
    - *
  • numeric: aligns right
  • - *
- * - * @param Int $col Column number for menu - * @param String $sipStyle use options from available list (see above) - * - * @access public - */ - function FormatColumn($col, $sipStyle) { - switch ($sipStyle){ - case "numeric": - $cssStyle = "divider alignRight"; - break; - - case "currency": - $cssStyle = "divider alignRight number"; - break; - - default: - $cssStyle = "divider"; - } // end of switch - - $this->table->FormatCol($col, $cssStyle); - } // end of function - - /** - * Creates a generic menu for each table row. - * Presets for this generic menu are: - *
    - *
  • the menu column contains the data records id (primary key)
  • - *
  • 1st column contains the same id as above
  • - *
  • 2nd column contains 0 or 1 as relevant value for activate and deactivate (zustand / active) if param $showActivate is set to true
  • - *
  • 3rd column contains 0 or 1 as relevant value for delete (deletable or not) if param $showDelete is set to true
  • - *
- * - * @param Int $col Column number for menu - * @param String $module Modulename used to build links (e.g. personenform, hutform, etc.) - * @param Bool $showActivate Show active/deactivate buttons depending on value in 2nd column - * @param Bool $showDelete Show delete button if value indicates that (value in 3rd column) - * - * @access public - */ - function RowMenuGeneric($col, $module, $showActivate=true, $showDelete=false) { - $rows = count($this->table->Table); - - for($i=0;$i<$rows;$i++) { - $cols = count($this->table->Table[$i]); - - for($j=0;$j<$cols;$j++) { - - if($j==($col-1)){ - $id = $this->table->Table[$i][$j]; - $menu = ""; - //historie - $menu .= ""; - $menu .= "\"Historie\""; - $menu .= " "; - - // bearbeiten wenn aktiv - if ($this->table->Table[$i][1] != 0) { - $menu .= ""; - $menu .= "\"bearbeiten\""; - $menu .= " "; - } // end of if - - // aktivieren wenn inaktiv, sonst deaktivieren - if (($this->table->Table[$i][1] == 0) && ($showActivate)){ - $menu .= ""; - $menu .= "\"reaktivieren\""; - $menu .= " "; - } else { - if($showActivate) { - $menu .= ""; - $menu .= "\"deaktivieren\""; - $menu .= " "; - } // end of if - } // end of if - anzeige von deaktivieren ODER aktivieren - - // l�sch button einblenden wenn delete kriterium 1 - if ($showDelete) { - // print_r($this->table->Table); - if ($this->table->Table[$i][2] == 1) { - $menu .= ""; - $menu .= "\"löschen\""; - $menu .= " "; - } // end of if - anzeige des l�schen buttons oder nicht nach wert - } // end of if - anzeige von l�schen oder nicht nach funktionsparmeter - - // wenn noch nicht verlinkt - $this->table->Table[$i][$j] = $menu; - - } // end of outer if - } // end of inner for - } // end pof outer for - } // end of function - - - - - /** - * Creates a specific form for Hut - * - * @param Int $col Column number for menu - * @param String $module Modulename used to build links (e.g. personenform, hutform, etc.) - * - * @access public - */ - function RowMenuHut($col, $module, $showActivate=true, $showDelete=false) { - $rows = count($this->table->Table); - - for($i=0;$i<$rows;$i++) { - $cols = count($this->table->Table[$i]); - - for($j=0;$j<$cols;$j++) { - - if($j==($col-1)){ - $id = $this->table->Table[$i][$j]; - $menu = ""; - //historie - $menu .= ""; - $menu .= "\"Historie\""; - $menu .= " "; - - // bearbeiten wenn aktiv - if ($this->table->Table[$i][1] != 0) { - $menu .= ""; - $menu .= "\"bearbeiten\""; - $menu .= " "; - } // end of if - - // aktivieren wenn inaktiv, sonst deaktivieren - if (($this->table->Table[$i][1] == 0) && ($showActivate)){ - $menu .= ""; - $menu .= "\"reaktivieren\""; - $menu .= " "; - } else { - if($showActivate) { - if (strlen($this->table->Table[$i][8]) == 51) { - $menu .= ""; - $menu .= "\"deaktivieren\""; - $menu .= " "; - } // end of if - } // end of if - } // end of if - anzeige von deaktivieren ODER aktivieren - - // l�sch button einblenden wenn delete kriterium 1 - if ($showDelete) { - // print_r($this->table->Table); - if ($this->table->Table[$i][2] == 1) { - $menu .= ""; - $menu .= "\"löschen\""; - $menu .= " "; - } // end of if - anzeige des l�schen buttons oder nicht nach wert - } // end of if - anzeige von l�schen oder nicht nach funktionsparmeter - - // wenn noch nicht verlinkt - $this->table->Table[$i][$j] = $menu; - - } // end of outer if - } // end of inner for - } // end pof outer for - } // end of function - - -/** - * Creates a specific form for OIC Module Statistik Auswertung / Ordner�bersicht - * - * @param Int $col Column number for menu - * @param String $module Modulename used to build links (e.g. personenform, hutform, etc.) - * - * @access public - */ - function RowMenuAuswertung($col, $module) { - $rows = count($this->table->Table); - - for($i=0;$i<$rows;$i++) { - $cols = count($this->table->Table[$i]); - - for($j=0;$j<$cols;$j++) { - - if($j==($col-1)){ - $id = $this->table->Table[$i][$j]; - $menu = ""; - - if ($this->table->Table[$i][3] != 0) { - // Detailansicht - $menu .= ""; - $menu .= "\"Detailansicht\""; - $menu .= " "; - - // Graph - $menu .= ""; - $menu .= "\"Graph\""; - $menu .= " "; - - } else { - $menu .= "keine Formeln vorhanden"; - } // end of if - nicht anzeigen wenn keine Formeln im Ordner sind - - // wenn noch nicht verlinkt - $this->table->Table[$i][$j] = $menu; - - } // end of outer if - } // end of inner for - } // end pof outer for - } // end of function - - -/** - * Creates a specific form for OIC Module Statistik Verwaltung / Ordner�bersicht - * - * @param Int $col Column number for menu - * @param String $module Modulename used to build links (e.g. personenform, hutform, etc.) - * - * @access public - */ - function RowMenuVerwaltungOrdner($col, $module) { - $rows = count($this->table->Table); - - for($i=0; $i<$rows; $i++) { - $cols = count($this->table->Table[$i]); - - for($j=0; $j<$cols; $j++) { - - if($j==($col-1)){ - $id = $this->table->Table[$i][$j]; - $menu = ""; - - // Edit - $menu .= ""; - $menu .= "\"Ordner"; - $menu .= " "; - - // Formeln bearbeiten - $menu .= ""; - $menu .= "\"Formeln"; - $menu .= " "; - - // Nach unten (wenn nicht letztes in Liste) - if ($i != $rows-1) { - $menu .= ""; - $menu .= "\"Nach"; - $menu .= " "; - } // end of if - - // Nach oben (wenn nicht erstes in Liste) - if ($i != 0) { - $menu .= ""; - $menu .= "\"Nach"; - $menu .= " "; - } // end of if - - // Delete - Wenn in Spalte 3 eine 0 steht (keine Formeln mehr im Ordner) - if ($this->table->Table[$i][3] == 0) { - $menu .= ""; - $menu .= "\"löschen\""; - $menu .= " "; - } // end of if - anzeige des l�schen buttons oder nicht nach wert - - // wenn noch nicht verlinkt - $this->table->Table[$i][$j] = $menu; - - } // end of outer if - } // end of inner for - } // end pof outer for - } // end of function - -/** - * Creates a specific form for OIC Module Statistik Verwaltung / Formel�bersicht innerhalb eines Ordners - * - * @param Int $col Column number for menu - * @param String $module Modulename used to build links (e.g. personenform, hutform, etc.) - * - * @access public - */ - function RowMenuVerwaltungFormeln($col, $module) { - $rows = count($this->table->Table); - - if ($rows == 0) { - $this->table->Table[] = Array("", "", "", "Bisher existiert kein Eintrag in dieser Liste.", "", "", "", "-1"); - $rows = count($this->table->Table); - } // end of if - - for($i=0; $i<$rows; $i++) { - $cols = count($this->table->Table[$i]); - - for($j=0; $j<$cols; $j++) { - - if($j==($col-1)){ - $id = $this->table->Table[$i][$j]; - $menu = ""; - - // Ansicht (1 oder 1/4) - if ($this->table->Table[$i][1] == 4 && $id != -1) { - $menu .= ""; - $menu .= "\"Ansicht"; - $menu .= " "; - } else if ($this->table->Table[$i][0] != "") { - $menu .= ""; - $menu .= "\"Ansicht"; - $menu .= " "; - } // end of if - Ansicht 1 oder 1/4 - - // Delete - Wenn in Spalte 3 eine 0 steht (keine Formeln mehr im Ordner) - //echo $this->table->Table[$i][1]."
"; - //if ($this->table->Table[$i][1] == 0 && $id != -1) { - if ($id != -1) { - $menu .= ""; - $menu .= "\"löschen\""; - $menu .= " "; - } // end of if - anzeige des l�schen buttons oder nicht nach wert - - // Formeln hinzuf�gen - if ($id != -1) { - $menu .= ""; - $menu .= "\"Nach"; - $menu .= " "; - } else { - $menu .= ""; - $menu .= "\"Formel"; - $menu .= " "; - } // end of if - - // Nach unten (wenn nicht letztes in Liste) - if ($i != $rows-1 && $id != -1) { - $menu .= ""; - $menu .= "\"Nach"; - $menu .= " "; - } // end of if - - // Nach oben (wenn nicht erstes in Liste) - if ($i != 0 && $id != -1) { - $menu .= ""; - $menu .= "\"Nach"; - $menu .= " "; - } // end of if - - // wenn noch nicht verlinkt - $this->table->Table[$i][$j] = $menu; - - } // end of outer if - } // end of inner for - } // end pof outer for - -/* - - 1 - Abgeschlossene Verträge - F3 - Pkt/Stk - 1 - Ansicht 1/4 löschen nach dieser hinzufügen nach unten - -*/ - - } // end of function - - - /** - * Shows the siptable - * - * @access public - */ - function Show() { - $this->html = ""; - if($this->searchform) - $this->html .= $this->SortAndSearchForm(); - - //$this->html .= $this->table->Get(" ",""); - $this->html .= $this->table->Get(" ",$this->headingtop); - $this->app->Tpl->Add($this->parsetarget, $this->html); - } // end of function - - - function RowLimit($number) { - $this->rowlimit=$number; - } - - - function Cols($fields) - { - $this->cols=array_flip($fields); - } - - function HideCol($number) - { - $this->table->HideCol($number); - } - - function HeadingTop($value) - { - $this->headingtop=$value; - - } - - function Headings($descriptions) - { - $this->table->AddRowAsHeading($descriptions); - $this->descriptions=$descriptions; - } - - function SetSortAndSearchForm($bool) - { - $this->searchform=$bool; - } - - function SetSortHeading($bool) - { - $this->sortheading=$bool; - } - - - function SortAndSearchForm() - { - $select = new HTMLSelect("sort",1); - if(count($this->cols)==0) - { - - } - else - { - while (list($col, $val) = @each($this->cols)) - { - if($this->descriptions[$col]!="") - $select->AddOption("Nach {$this->descriptions[$col]} Sortieren",$col); - else - $select->AddOption("Nach $col Sortieren",$col); - - } - } - $html = $select->Get(); - - $search = new HTMLInput("search","text","",20); - $html .= $search->Get(); - - $html .=""; - - $html .="
"; - - $alphabet = range('A', 'Z'); - $html .=""; - foreach ($alphabet as $letter) - $html .= ""; - - $html .="
$letter
"; - - - return $html; - } - -} // end of class - -?> diff --git a/refreshFileCache.php b/refreshFileCache.php index ce4e47d4c..84c265805 100644 --- a/refreshFileCache.php +++ b/refreshFileCache.php @@ -8,9 +8,7 @@ error_reporting(E_ERROR | E_COMPILE_ERROR | E_CORE_ERROR | E_RECOVERABLE_ERROR | E_USER_ERROR | E_PARSE); -if(file_exists(__DIR__.'/xentral_autoloader.php')){ - include_once (__DIR__.'/xentral_autoloader.php'); -} +require_once __DIR__ . '/vendor/autoload.php'; $config = new Config(); $installerCacheConfig = new InstallerCacheConfig($config->WFuserdata . '/tmp/' . $config->WFdbname); diff --git a/upgrade/data/db_schema.json b/upgrade/data/db_schema.json index dcfd7c0b7..1d835c9e9 100644 --- a/upgrade/data/db_schema.json +++ b/upgrade/data/db_schema.json @@ -59463,111 +59463,6 @@ } ] }, - { - "name": "logfile", - "collation": "utf8mb3_general_ci", - "type": "BASE TABLE", - "columns": [ - { - "Field": "id", - "Type": "int(11)", - "Collation": null, - "Null": "NO", - "Key": "PRI", - "Default": null, - "Extra": "auto_increment", - "Privileges": "select,insert,update,references", - "Comment": "" - }, - { - "Field": "meldung", - "Type": "text", - "Collation": "utf8mb3_general_ci", - "Null": "NO", - "Key": "", - "Default": null, - "Extra": "", - "Privileges": "select,insert,update,references", - "Comment": "" - }, - { - "Field": "dump", - "Type": "text", - "Collation": "utf8mb3_general_ci", - "Null": "NO", - "Key": "", - "Default": null, - "Extra": "", - "Privileges": "select,insert,update,references", - "Comment": "" - }, - { - "Field": "module", - "Type": "varchar(64)", - "Collation": "utf8mb3_general_ci", - "Null": "NO", - "Key": "", - "Default": null, - "Extra": "", - "Privileges": "select,insert,update,references", - "Comment": "" - }, - { - "Field": "action", - "Type": "varchar(64)", - "Collation": "utf8mb3_general_ci", - "Null": "NO", - "Key": "", - "Default": null, - "Extra": "", - "Privileges": "select,insert,update,references", - "Comment": "" - }, - { - "Field": "bearbeiter", - "Type": "varchar(64)", - "Collation": "utf8mb3_general_ci", - "Null": "NO", - "Key": "", - "Default": null, - "Extra": "", - "Privileges": "select,insert,update,references", - "Comment": "" - }, - { - "Field": "funktionsname", - "Type": "varchar(64)", - "Collation": "utf8mb3_general_ci", - "Null": "NO", - "Key": "", - "Default": null, - "Extra": "", - "Privileges": "select,insert,update,references", - "Comment": "" - }, - { - "Field": "datum", - "Type": "datetime", - "Collation": null, - "Null": "YES", - "Key": "", - "Default": null, - "Extra": "", - "Privileges": "select,insert,update,references", - "Comment": "" - } - ], - "keys": [ - { - "Key_name": "PRIMARY", - "Index_type": "BTREE", - "columns": [ - "id" - ], - "Non_unique": "" - } - ] - }, { "name": "magento2_extended_mapping", "collation": "utf8mb3_general_ci", diff --git a/vendor/aura/sqlquery/.scrutinizer.yml b/vendor/aura/sqlquery/.scrutinizer.yml new file mode 100644 index 000000000..7c7c84543 --- /dev/null +++ b/vendor/aura/sqlquery/.scrutinizer.yml @@ -0,0 +1,10 @@ +filter: + paths: ["src/*"] +tools: + external_code_coverage: true + php_code_coverage: true + php_sim: true + php_mess_detector: true + php_pdepend: true + php_analyzer: true + php_cpd: true diff --git a/vendor/aura/sqlquery/.travis.yml b/vendor/aura/sqlquery/.travis.yml new file mode 100644 index 000000000..7dbe61466 --- /dev/null +++ b/vendor/aura/sqlquery/.travis.yml @@ -0,0 +1,14 @@ +sudo: false +language: php +php: + - 5.3 + - 5.4 + - 5.5 + - 5.6 + - hhvm + - 7 +script: + - phpunit --coverage-clover=coverage.clover +after_script: + - wget https://scrutinizer-ci.com/ocular.phar + - php ocular.phar code-coverage:upload --format=php-clover coverage.clover diff --git a/vendor/aura/sqlquery/composer.json b/vendor/aura/sqlquery/composer.json new file mode 100644 index 000000000..40c021cc3 --- /dev/null +++ b/vendor/aura/sqlquery/composer.json @@ -0,0 +1,48 @@ +{ + "name": "aura/sqlquery", + "type": "library", + "description": "Object-oriented query builders for MySQL, Postgres, SQLite, and SQLServer; can be used with any database connection library.", + "keywords": [ + "mysql", + "pdo", + "pgsql", + "postgres", + "postgresql", + "sqlite", + "sql server", + "sqlserver", + "query", + "select", + "insert", + "update", + "delete", + "db", + "database", + "sql", + "dml" + ], + "homepage": "https://github.com/auraphp/Aura.SqlQuery", + "license": "BSD-2-Clause", + "authors": [ + { + "name": "Aura.SqlQuery Contributors", + "homepage": "https://github.com/auraphp/Aura.SqlQuery/contributors" + } + ], + "require": { + "php": ">=5.3.9" + }, + "autoload": { + "psr-4": { + "Aura\\SqlQuery\\": "src/" + } + }, + "extra": { + "aura": { + "type": "library" + } + }, + "suggest": { + "aura/sql": "Provides an extension to the native PDO along with a profiler and connection locator. Use version 2.*." + } +} diff --git a/vendor/aura/sqlquery/tests/AbstractQueryTest.php b/vendor/aura/sqlquery/tests/AbstractQueryTest.php new file mode 100644 index 000000000..a7eee4c3b --- /dev/null +++ b/vendor/aura/sqlquery/tests/AbstractQueryTest.php @@ -0,0 +1,77 @@ +query_factory = new QueryFactory($this->db_type); + $this->query = $this->newQuery(); + } + + protected function newQuery() + { + $method = 'new' . $this->query_type; + return $this->query_factory->$method(); + } + + protected function assertSameSql($expect, $actual) + { + // remove leading and trailing whitespace per block and line + $expect = trim($expect); + $expect = preg_replace('/^[ \t]*/m', '', $expect); + $expect = preg_replace('/[ \t]*$/m', '', $expect); + + // convert "<<" and ">>" to the correct identifier quotes + $expect = $this->requoteIdentifiers($expect); + + // remove leading and trailing whitespace per block and line + $actual = trim($actual); + $actual = preg_replace('/^[ \t]*/m', '', $actual); + $actual = preg_replace('/[ \t]*$/m', '', $actual); + + // normalize line endings to be sure tests will pass on windows and mac + $expect = preg_replace('/\r\n|\n|\r/', PHP_EOL, $expect); + $actual = preg_replace('/\r\n|\n|\r/', PHP_EOL, $actual); + + // are they the same now? + $this->assertSame($expect, $actual); + } + + protected function requoteIdentifiers($string) + { + $string = str_replace('<<', $this->query->getQuoteNamePrefix(), $string); + $string = str_replace('>>', $this->query->getQuoteNameSuffix(), $string); + return $string; + } + + protected function tearDown() + { + parent::tearDown(); + } + + public function testBindValues() + { + $actual = $this->query->getBindValues(); + $this->assertSame(array(), $actual); + + $expect = array('foo' => 'bar', 'baz' => 'dib'); + $this->query->bindValues($expect); + $actual = $this->query->getBindValues(); + $this->assertSame($expect, $actual); + + $this->query->bindValues(array('zim' => 'gir')); + $expect = array('foo' => 'bar', 'baz' => 'dib', 'zim' => 'gir'); + $actual = $this->query->getBindValues(); + $this->assertSame($expect, $actual); + } +} diff --git a/vendor/aura/sqlquery/tests/Common/DeleteTest.php b/vendor/aura/sqlquery/tests/Common/DeleteTest.php new file mode 100644 index 000000000..94bab9252 --- /dev/null +++ b/vendor/aura/sqlquery/tests/Common/DeleteTest.php @@ -0,0 +1,35 @@ +query->from('t1') + ->where('foo = ?', 'bar') + ->where('baz = ?', 'dib') + ->orWhere('zim = gir'); + + $actual = $this->query->__toString(); + $expect = " + DELETE FROM <> + WHERE + foo = :_1_ + AND baz = :_2_ + OR zim = gir + "; + + $this->assertSameSql($expect, $actual); + + $actual = $this->query->getBindValues(); + $expect = array( + '_1_' => 'bar', + '_2_' => 'dib', + ); + $this->assertSame($expect, $actual); + } +} diff --git a/vendor/aura/sqlquery/tests/Common/InsertTest.php b/vendor/aura/sqlquery/tests/Common/InsertTest.php new file mode 100644 index 000000000..a51b9e7a5 --- /dev/null +++ b/vendor/aura/sqlquery/tests/Common/InsertTest.php @@ -0,0 +1,336 @@ +query_factory->setLastInsertIdNames(array( + 'tablex.colx' => 'tablex_colx_alternative_name', + )); + return parent::newQuery(); + } + + public function testCommon() + { + $this->query->into('t1') + ->cols(array('c1', 'c2')) + ->col('c3') + ->set('c4', 'NOW()') + ->set('c5', null) + ->cols(array('cx' => 'cx_value')); + + $actual = $this->query->__toString(); + $expect = ' + INSERT INTO <> ( + <>, + <>, + <>, + <>, + <>, + <> + ) VALUES ( + :c1, + :c2, + :c3, + NOW(), + NULL, + :cx + ) + '; + + $this->assertSameSql($expect, $actual); + + $actual = $this->query->getBindValues(); + $expect = array('cx' => 'cx_value'); + $this->assertSame($expect, $actual); + } + + public function testGetLastInsertIdName_default() + { + $this->query->into('table'); + $expect = null; + $actual = $this->query->getLastInsertIdName('col'); + $this->assertSame($expect, $actual); + } + + public function testGetLastInsertIdName_alternative() + { + $this->query->into('tablex'); + $expect = 'tablex_colx_alternative_name'; + $actual = $this->query->getLastInsertIdName('colx'); + $this->assertSame($expect, $actual); + } + + public function testBindValues() + { + $this->assertInstanceOf('\Aura\SqlQuery\AbstractQuery', $this->query->bindValues(array('bar', 'bar value'))); + } + + public function testBindValue() + { + $this->assertInstanceOf('\Aura\SqlQuery\AbstractQuery', $this->query->bindValue('bar', 'bar value')); + } + + public function testBulkAddRow() + { + $this->query->into('t1'); + + $this->query->cols(array('c1' => 'v1-0', 'c2' => 'v2-0')); + $this->query->col('c3', 'v3-0'); + $this->query->set('c4', 'NOW() - 0'); + + $this->query->addRow(); + + $this->query->col('c3', 'v3-1'); + $this->query->set('c4', 'NOW() - 1'); + $this->query->cols(array('c2' => 'v2-1', 'c1' => 'v1-1')); + + $this->query->addRow(); + + $this->query->set('c4', 'NOW() - 2'); + $this->query->col('c1', 'v1-2'); + $this->query->cols(array('c2' => 'v2-2', 'c3' => 'v3-2')); + + $actual = $this->query->__toString(); + $expect = ' + INSERT INTO <> + (<>, <>, <>, <>) + VALUES + (:c1_0, :c2_0, :c3_0, NOW() - 0), + (:c1_1, :c2_1, :c3_1, NOW() - 1), + (:c1_2, :c2_2, :c3_2, NOW() - 2) + '; + + $this->assertSameSql($expect, $actual); + + $expect = array ( + 'c1_0' => 'v1-0', + 'c2_0' => 'v2-0', + 'c3_0' => 'v3-0', + 'c1_1' => 'v1-1', + 'c2_1' => 'v2-1', + 'c3_1' => 'v3-1', + 'c1_2' => 'v1-2', + 'c2_2' => 'v2-2', + 'c3_2' => 'v3-2', + ); + $actual = $this->query->getBindValues(); + $this->assertSame($expect, $actual); + } + + public function testBulkMissingCol() + { + $this->query->into('t1'); + + // the needed cols + $this->query->cols(array('c1' => 'v1-0', 'c2' => 'v2-0')); + $this->query->col('c3', 'v3-0'); + $this->query->set('c4', 'NOW() - 0'); + + // add another row + $this->query->addRow(); + $this->query->set('c4', 'NOW() - 1'); + $this->query->cols(array('c2' => 'v2-1', 'c1' => 'v1-1')); + + // failed to add c3, should blow up + + $this->setExpectedException( + 'Aura\SqlQuery\Exception', + $this->requoteIdentifiers("Column <> missing from row 1.") + ); + $this->query->addRow(); + } + + public function testBulkEmptyRow() + { + $this->query->into('t1'); + + $this->query->cols(array('c1' => 'v1-0', 'c2' => 'v2-0')); + $this->query->col('c3', 'v3-0'); + $this->query->set('c4', 'NOW() - 0'); + + $this->query->addRow(); + + $this->query->col('c3', 'v3-1'); + $this->query->set('c4', 'NOW() - 1'); + $this->query->cols(array('c2' => 'v2-1', 'c1' => 'v1-1')); + + $this->query->addRow(); + + $this->query->set('c4', 'NOW() - 2'); + $this->query->col('c1', 'v1-2'); + $this->query->cols(array('c2' => 'v2-2', 'c3' => 'v3-2')); + + // add an empty row + $this->query->addRow(); + + // should be the same as testBulk() + $actual = $this->query->__toString(); + $expect = ' + INSERT INTO <> + (<>, <>, <>, <>) + VALUES + (:c1_0, :c2_0, :c3_0, NOW() - 0), + (:c1_1, :c2_1, :c3_1, NOW() - 1), + (:c1_2, :c2_2, :c3_2, NOW() - 2) + '; + + $this->assertSameSql($expect, $actual); + + $expect = array ( + 'c1_0' => 'v1-0', + 'c2_0' => 'v2-0', + 'c3_0' => 'v3-0', + 'c1_1' => 'v1-1', + 'c2_1' => 'v2-1', + 'c3_1' => 'v3-1', + 'c1_2' => 'v1-2', + 'c2_2' => 'v2-2', + 'c3_2' => 'v3-2', + ); + $actual = $this->query->getBindValues(); + $this->assertSame($expect, $actual); + } + + public function testBulkAddRows() + { + $this->query->into('t1'); + $this->query->addRows(array( + array( + 'c1' => 'v1-0', + 'c2' => 'v2-0', + 'c3' => 'v3-0', + ), + array( + 'c1' => 'v1-1', + 'c2' => 'v2-1', + 'c3' => 'v3-1', + ), + array( + 'c1' => 'v1-2', + 'c2' => 'v2-2', + 'c3' => 'v3-2', + ), + )); + + $actual = $this->query->__toString(); + $expect = ' + INSERT INTO <> + (<>, <>, <>) + VALUES + (:c1_0, :c2_0, :c3_0), + (:c1_1, :c2_1, :c3_1), + (:c1_2, :c2_2, :c3_2) + '; + + $this->assertSameSql($expect, $actual); + + $expect = array ( + 'c1_0' => 'v1-0', + 'c2_0' => 'v2-0', + 'c3_0' => 'v3-0', + 'c1_1' => 'v1-1', + 'c2_1' => 'v2-1', + 'c3_1' => 'v3-1', + 'c1_2' => 'v1-2', + 'c2_2' => 'v2-2', + 'c3_2' => 'v3-2', + ); + $actual = $this->query->getBindValues(); + $this->assertSame($expect, $actual); + } + + public function testIssue60_addRowsWithOnlyOneRow() + { + $this->query->into('t1'); + $this->query->addRows(array( + array( + 'c1' => 'v1-0', + 'c2' => 'v2-0', + 'c3' => 'v3-0', + ), + )); + + $actual = $this->query->__toString(); + $expect = ' + INSERT INTO <> ( + <>, + <>, + <> + ) VALUES ( + :c1, + :c2, + :c3 + ) + '; + + $this->assertSameSql($expect, $actual); + + $expect = array ( + 'c1' => 'v1-0', + 'c2' => 'v2-0', + 'c3' => 'v3-0', + ); + $actual = $this->query->getBindValues(); + $this->assertSame($expect, $actual); + } + + public function testIssue60_repeatedAddRowsWithOnlyOneRow() + { + $this->query->into('t1'); + $this->query->addRows(array( + array( + 'c1' => 'v1-0', + 'c2' => 'v2-0', + 'c3' => 'v3-0', + ), + )); + + $this->query->addRows(array( + array( + 'c1' => 'v1-1', + 'c2' => 'v2-1', + 'c3' => 'v3-1', + ), + )); + + $this->query->addRows(array( + array( + 'c1' => 'v1-2', + 'c2' => 'v2-2', + 'c3' => 'v3-2', + ), + )); + + $actual = $this->query->__toString(); + $expect = ' + INSERT INTO <> + (<>, <>, <>) + VALUES + (:c1_0, :c2_0, :c3_0), + (:c1_1, :c2_1, :c3_1), + (:c1_2, :c2_2, :c3_2) + '; + + $this->assertSameSql($expect, $actual); + + $expect = array ( + 'c1_0' => 'v1-0', + 'c2_0' => 'v2-0', + 'c3_0' => 'v3-0', + 'c1_1' => 'v1-1', + 'c2_1' => 'v2-1', + 'c3_1' => 'v3-1', + 'c1_2' => 'v1-2', + 'c2_2' => 'v2-2', + 'c3_2' => 'v3-2', + ); + $actual = $this->query->getBindValues(); + $this->assertSame($expect, $actual); + } +} diff --git a/vendor/aura/sqlquery/tests/Common/SelectTest.php b/vendor/aura/sqlquery/tests/Common/SelectTest.php new file mode 100644 index 000000000..02e76d7a9 --- /dev/null +++ b/vendor/aura/sqlquery/tests/Common/SelectTest.php @@ -0,0 +1,963 @@ +query->from('t1'); + $this->setExpectedException('Aura\SqlQuery\Exception'); + $this->query->__toString(); + + } + + public function testSetAndGetPaging() + { + $expect = 88; + $this->query->setPaging($expect); + $actual = $this->query->getPaging(); + $this->assertSame($expect, $actual); + } + + public function testDistinct() + { + $this->query->distinct() + ->from('t1') + ->cols(array('t1.c1', 't1.c2', 't1.c3')); + + $actual = $this->query->__toString(); + + $expect = ' + SELECT DISTINCT + <>.<>, + <>.<>, + <>.<> + FROM + <> + '; + $this->assertSameSql($expect, $actual); + } + + public function testDuplicateFlag() + { + $this->query->distinct() + ->distinct() + ->from('t1') + ->cols(array('t1.c1', 't1.c2', 't1.c3')); + + $actual = $this->query->__toString(); + + $expect = ' + SELECT DISTINCT + <>.<>, + <>.<>, + <>.<> + FROM + <> + '; + $this->assertSameSql($expect, $actual); + } + + public function testFlagUnset() + { + $this->query->distinct() + ->distinct(false) + ->from('t1') + ->cols(array('t1.c1', 't1.c2', 't1.c3')); + + $actual = $this->query->__toString(); + + $expect = ' + SELECT + <>.<>, + <>.<>, + <>.<> + FROM + <> + '; + $this->assertSameSql($expect, $actual); + } + + public function testCols() + { + $this->assertFalse($this->query->hasCols()); + + $this->query->cols(array( + 't1.c1', + 'c2' => 'a2', + 'COUNT(t1.c3)' + )); + + $this->assertTrue($this->query->hasCols()); + + $actual = $this->query->__toString(); + $expect = ' + SELECT + <>.<>, + c2 AS <>, + COUNT(<>.<>) + '; + $this->assertSameSql($expect, $actual); + } + + public function testFrom() + { + $this->query->cols(array('*')); + $this->query->from('t1') + ->from('t2'); + + $actual = $this->query->__toString(); + $expect = ' + SELECT + * + FROM + <>, + <> + '; + $this->assertSameSql($expect, $actual); + } + + public function testFromRaw() + { + $this->query->cols(array('*')); + $this->query->fromRaw('t1') + ->fromRaw('t2'); + + $actual = $this->query->__toString(); + $expect = ' + SELECT + * + FROM + t1, + t2 + '; + $this->assertSameSql($expect, $actual); + } + + public function testDuplicateFromTable() + { + $this->query->cols(array('*')); + $this->query->from('t1'); + + $this->setExpectedException( + 'Aura\SqlQuery\Exception', + "Cannot reference 'FROM t1' after 'FROM t1'" + ); + $this->query->from('t1'); + } + + + public function testDuplicateFromAlias() + { + $this->query->cols(array('*')); + $this->query->from('t1'); + + $this->setExpectedException( + 'Aura\SqlQuery\Exception', + "Cannot reference 'FROM t2 AS t1' after 'FROM t1'" + ); + $this->query->from('t2 AS t1'); + } + + public function testFromSubSelect() + { + $sub = 'SELECT * FROM t2'; + $this->query->cols(array('*'))->fromSubSelect($sub, 'a2'); + $expect = ' + SELECT + * + FROM + ( + SELECT * FROM t2 + ) AS <> + '; + $actual = $this->query->__toString(); + $this->assertSameSql($expect, $actual); + } + + public function testDuplicateSubSelectTableRef() + { + $this->query->cols(array('*')); + $this->query->from('t1'); + + $this->setExpectedException( + 'Aura\SqlQuery\Exception', + "Cannot reference 'FROM (SELECT ...) AS t1' after 'FROM t1'" + ); + + $sub = 'SELECT * FROM t2'; + $this->query->fromSubSelect($sub, 't1'); + } + + public function testFromSubSelectObject() + { + $sub = $this->newQuery(); + $sub->cols(array('*')) + ->from('t2') + ->where('foo = ?', 'bar'); + + $this->query->cols(array('*')) + ->fromSubSelect($sub, 'a2') + ->where('a2.baz = ?', 'dib'); + + $expect = ' + SELECT + * + FROM + ( + SELECT + * + FROM + <> + WHERE + foo = :_1_1_ + ) AS <> + WHERE + <>.<> = :_2_ + '; + + $actual = $this->query->__toString(); + $this->assertSameSql($expect, $actual); + } + + public function testJoin() + { + $this->query->cols(array('*')); + $this->query->from('t1'); + $this->query->join('left', 't2', 't1.id = t2.id'); + $this->query->join('inner', 't3 AS a3', 't2.id = a3.id'); + $this->query->from('t4'); + $this->query->join('natural', 't5'); + $expect = ' + SELECT + * + FROM + <> + LEFT JOIN <> ON <>.<> = <>.<> + INNER JOIN <> AS <> ON <>.<> = <>.<>, + <> + NATURAL JOIN <> + '; + $actual = $this->query->__toString(); + $this->assertSameSql($expect, $actual); + } + + public function testJoinBeforeFrom() + { + $this->query->cols(array('*')); + $this->query->join('left', 't2', 't1.id = t2.id'); + $this->query->join('inner', 't3 AS a3', 't2.id = a3.id'); + $this->query->from('t1'); + $this->query->from('t4'); + $this->query->join('natural', 't5'); + $expect = ' + SELECT + * + FROM + <> + LEFT JOIN <> ON <>.<> = <>.<> + INNER JOIN <> AS <> ON <>.<> = <>.<>, + <> + NATURAL JOIN <> + '; + $actual = $this->query->__toString(); + $this->assertSameSql($expect, $actual); + } + + public function testDuplicateJoinRef() + { + $this->query->cols(array('*')); + $this->query->from('t1'); + + $this->setExpectedException( + 'Aura\SqlQuery\Exception', + "Cannot reference 'NATURAL JOIN t1' after 'FROM t1'" + ); + $this->query->join('natural', 't1'); + } + + public function testJoinAndBind() + { + $this->query->cols(array('*')); + $this->query->from('t1'); + $this->query->join( + 'left', + 't2', + 't1.id = t2.id AND t1.foo = ?', + array('bar') + ); + + $expect = ' + SELECT + * + FROM + <> + LEFT JOIN <> ON <>.<> = <>.<> AND <>.<> = :_1_ + '; + $actual = $this->query->__toString(); + $this->assertSameSql($expect, $actual); + + $expect = array('_1_' => 'bar'); + $actual = $this->query->getBindValues(); + $this->assertSame($expect, $actual); + } + + public function testLeftAndInnerJoin() + { + $this->query->cols(array('*')); + $this->query->from('t1'); + $this->query->leftJoin('t2', 't1.id = t2.id'); + $this->query->innerJoin('t3 AS a3', 't2.id = a3.id'); + $this->query->join('natural', 't4'); + $expect = ' + SELECT + * + FROM + <> + LEFT JOIN <> ON <>.<> = <>.<> + INNER JOIN <> AS <> ON <>.<> = <>.<> + NATURAL JOIN <> + '; + $actual = $this->query->__toString(); + $this->assertSameSql($expect, $actual); + } + + public function testLeftAndInnerJoinWithBind() + { + $this->query->cols(array('*')); + $this->query->from('t1'); + $this->query->leftJoin('t2', 't2.id = ?', array('foo')); + $this->query->innerJoin('t3 AS a3', 'a3.id = ?', array('bar')); + $expect = ' + SELECT + * + FROM + <> + LEFT JOIN <> ON <>.<> = :_1_ + INNER JOIN <> AS <> ON <>.<> = :_2_ + '; + $actual = $this->query->__toString(); + $this->assertSameSql($expect, $actual); + + $expect = array('_1_' => 'foo', '_2_' => 'bar'); + $actual = $this->query->getBindValues(); + $this->assertSame($expect, $actual); + } + + public function testJoinSubSelect() + { + $sub1 = 'SELECT * FROM t2'; + $sub2 = 'SELECT * FROM t3'; + $this->query->cols(array('*')); + $this->query->from('t1'); + $this->query->joinSubSelect('left', $sub1, 'a2', 't2.c1 = a3.c1'); + $this->query->joinSubSelect('natural', $sub2, 'a3'); + $expect = ' + SELECT + * + FROM + <> + LEFT JOIN ( + SELECT * FROM t2 + ) AS <> ON <>.<> = <>.<> + NATURAL JOIN ( + SELECT * FROM t3 + ) AS <> + '; + $actual = $this->query->__toString(); + $this->assertSameSql($expect, $actual); + } + + public function testJoinSubSelectBeforeFrom() + { + $sub1 = 'SELECT * FROM t2'; + $sub2 = 'SELECT * FROM t3'; + $this->query->cols(array('*')); + $this->query->joinSubSelect('left', $sub1, 'a2', 't2.c1 = a3.c1'); + $this->query->joinSubSelect('natural', $sub2, 'a3'); + $this->query->from('t1'); + $expect = ' + SELECT + * + FROM + <> + LEFT JOIN ( + SELECT * FROM t2 + ) AS <> ON <>.<> = <>.<> + NATURAL JOIN ( + SELECT * FROM t3 + ) AS <> + '; + $actual = $this->query->__toString(); + $this->assertSameSql($expect, $actual); + } + + public function testDuplicateJoinSubSelectRef() + { + $this->query->cols(array('*')); + $this->query->from('t1'); + + $this->setExpectedException( + 'Aura\SqlQuery\Exception', + "Cannot reference 'NATURAL JOIN (SELECT ...) AS t1' after 'FROM t1'" + ); + + $sub2 = 'SELECT * FROM t3'; + $this->query->joinSubSelect('natural', $sub2, 't1'); + } + + public function testJoinSubSelectObject() + { + $sub = $this->newQuery(); + $sub->cols(array('*'))->from('t2')->where('foo = ?', 'bar'); + + $this->query->cols(array('*')); + $this->query->from('t1'); + $this->query->joinSubSelect('left', $sub, 'a3', 't2.c1 = a3.c1'); + $this->query->where('baz = ?', 'dib'); + + $expect = ' + SELECT + * + FROM + <> + LEFT JOIN ( + SELECT + * + FROM + <> + WHERE + foo = :_1_1_ + ) AS <> ON <>.<> = <>.<> + WHERE + baz = :_2_ + '; + $actual = $this->query->__toString(); + $this->assertSameSql($expect, $actual); + } + + public function testJoinOrder() + { + $this->query->cols(array('*')); + $this->query + ->from('t1') + ->join('inner', 't2', 't2.id = t1.id') + ->join('left', 't3', 't3.id = t2.id') + ->from('t4') + ->join('inner', 't5', 't5.id = t4.id'); + $expect = ' + SELECT + * + FROM + <> + INNER JOIN <> ON <>.<> = <>.<> + LEFT JOIN <> ON <>.<> = <>.<>, + <> + INNER JOIN <> ON <>.<> = <>.<> + '; + $actual = $this->query->__toString(); + $this->assertSameSql($expect, $actual); + } + + public function testJoinOnAndUsing() + { + $this->query->cols(array('*')); + $this->query + ->from('t1') + ->join('inner', 't2', 'ON t2.id = t1.id') + ->join('left', 't3', 'USING (id)'); + $expect = ' + SELECT + * + FROM + <> + INNER JOIN <> ON <>.<> = <>.<> + LEFT JOIN <> USING (id) + '; + $actual = $this->query->__toString(); + $this->assertSameSql($expect, $actual); + } + + public function testWhere() + { + $this->query->cols(array('*')); + $this->query->where('c1 = c2') + ->where('c3 = ?', 'foo'); + $expect = ' + SELECT + * + WHERE + c1 = c2 + AND c3 = :_1_ + '; + + $actual = $this->query->__toString(); + $this->assertSameSql($expect, $actual); + + $actual = $this->query->getBindValues(); + $expect = array('_1_' => 'foo'); + $this->assertSame($expect, $actual); + } + + public function testOrWhere() + { + $this->query->cols(array('*')); + $this->query->orWhere('c1 = c2') + ->orWhere('c3 = ?', 'foo'); + + $expect = ' + SELECT + * + WHERE + c1 = c2 + OR c3 = :_1_ + '; + + $actual = $this->query->__toString(); + $this->assertSameSql($expect, $actual); + + $actual = $this->query->getBindValues(); + $expect = array('_1_' => 'foo'); + $this->assertSame($expect, $actual); + } + + public function testGroupBy() + { + $this->query->cols(array('*')); + $this->query->groupBy(array('c1', 't2.c2')); + $expect = ' + SELECT + * + GROUP BY + c1, + <>.<> + '; + + $actual = $this->query->__toString(); + $this->assertSameSql($expect, $actual); + } + + public function testHaving() + { + $this->query->cols(array('*')); + $this->query->having('c1 = c2') + ->having('c3 = ?', 'foo'); + $expect = ' + SELECT + * + HAVING + c1 = c2 + AND c3 = :_1_ + '; + + $actual = $this->query->__toString(); + $this->assertSameSql($expect, $actual); + + $actual = $this->query->getBindValues(); + $expect = array('_1_' => 'foo'); + $this->assertSame($expect, $actual); + } + + public function testOrHaving() + { + $this->query->cols(array('*')); + $this->query->orHaving('c1 = c2') + ->orHaving('c3 = ?', 'foo'); + $expect = ' + SELECT + * + HAVING + c1 = c2 + OR c3 = :_1_ + '; + + $actual = $this->query->__toString(); + $this->assertSameSql($expect, $actual); + + $actual = $this->query->getBindValues(); + $expect = array('_1_' => 'foo'); + $this->assertSame($expect, $actual); + } + + public function testOrderBy() + { + $this->query->cols(array('*')); + $this->query->orderBy(array('c1', 'UPPER(t2.c2)', )); + $expect = ' + SELECT + * + ORDER BY + c1, + UPPER(<>.<>) + '; + + $actual = $this->query->__toString(); + $this->assertSameSql($expect, $actual); + } + + public function testGetterOnLimitAndOffset() + { + $this->query->cols(array('*')); + $this->query->limit(10); + $this->query->offset(50); + + $this->assertSame(10, $this->query->getLimit()); + $this->assertSame(50, $this->query->getOffset()); + } + + public function testLimitOffset() + { + $this->query->cols(array('*')); + $this->query->limit(10); + $expect = ' + SELECT + * + LIMIT 10 + '; + $actual = $this->query->__toString(); + $this->assertSameSql($expect, $actual); + + $this->query->offset(40); + $expect = ' + SELECT + * + LIMIT 10 OFFSET 40 + '; + $actual = $this->query->__toString(); + $this->assertSameSql($expect, $actual); + } + + public function testPage() + { + $this->query->cols(array('*')); + $this->query->page(5); + $expect = ' + SELECT + * + LIMIT 10 OFFSET 40 + '; + $actual = $this->query->__toString(); + $this->assertSameSql($expect, $actual); + } + + public function testForUpdate() + { + $this->query->cols(array('*')); + $this->query->forUpdate(); + $expect = ' + SELECT + * + FOR UPDATE + '; + $actual = $this->query->__toString(); + $this->assertSameSql($expect, $actual); + } + + public function testUnion() + { + $this->query->cols(array('c1')) + ->from('t1') + ->union() + ->cols(array('c2')) + ->from('t2'); + $expect = ' + SELECT + c1 + FROM + <> + UNION + SELECT + c2 + FROM + <> + '; + + $actual = $this->query->__toString(); + $this->assertSameSql($expect, $actual); + } + + public function testUnionAll() + { + $this->query->cols(array('c1')) + ->from('t1') + ->unionAll() + ->cols(array('c2')) + ->from('t2'); + $expect = ' + SELECT + c1 + FROM + <> + UNION ALL + SELECT + c2 + FROM + <> + '; + + $actual = $this->query->__toString(); + $this->assertSameSql($expect, $actual); + } + + public function testAutobind() + { + // do these out of order + $this->query->having('baz IN (?)', array('dib', 'zim', 'gir')); + $this->query->where('foo = ?', 'bar'); + $this->query->cols(array('*')); + + $expect = ' + SELECT + * + WHERE + foo = :_2_ + HAVING + baz IN (:_1_) + '; + $actual = $this->query->__toString(); + $this->assertSameSql($expect, $actual); + + $expect = array( + '_1_' => array('dib', 'zim', 'gir'), + '_2_' => 'bar', + ); + $actual = $this->query->getBindValues(); + $this->assertSame($expect, $actual); + } + + public function testAddColWithAlias() + { + $this->query->cols(array( + 'foo', + 'bar', + 'table.noalias', + 'col1 as alias1', + 'col2 alias2', + 'table.proper' => 'alias_proper', + 'legacy invalid as alias still works', + 'overwrite as alias1', + )); + + // add separately to make sure we don't overwrite sequential keys + $this->query->cols(array( + 'baz', + 'dib', + )); + + $actual = $this->query->__toString(); + + $expect = ' + SELECT + foo, + bar, + <>.<>, + overwrite AS <>, + col2 AS <>, + <
>.<> AS <>, + legacy invalid AS <>, + baz, + dib + '; + $this->assertSameSql($expect, $actual); + } + + public function testGetCols() + { + $this->query->cols(array('valueBar' => 'aliasFoo')); + + $cols = $this->query->getCols(); + + $this->assertTrue(is_array($cols)); + $this->assertTrue(count($cols) === 1); + $this->assertArrayHasKey('aliasFoo', $cols); + } + + public function testRemoveColsAlias() + { + $this->query->cols(array('valueBar' => 'aliasFoo', 'valueBaz' => 'aliasBaz')); + + $this->assertTrue($this->query->removeCol('aliasFoo')); + $cols = $this->query->getCols(); + + $this->assertTrue(is_array($cols)); + $this->assertTrue(count($cols) === 1); + $this->assertArrayNotHasKey('aliasFoo', $cols); + } + + public function testRemoveColsName() + { + $this->query->cols(array('valueBar', 'valueBaz' => 'aliasBaz')); + + $this->assertTrue($this->query->removeCol('valueBar')); + $cols = $this->query->getCols(); + + $this->assertTrue(is_array($cols)); + $this->assertTrue(count($cols) === 1); + $this->assertNotContains('valueBar', $cols); + } + + public function testRemoveColsNotFound() + { + $this->assertFalse($this->query->removeCol('valueBar')); + } + + public function testIssue47() + { + // sub select + $sub = $this->newQuery() + ->cols(array('*')) + ->from('table1 AS t1'); + $expect = ' + SELECT + * + FROM + <> AS <> + '; + $actual = $sub->__toString(); + $this->assertSameSql($expect, $actual); + + // main select + $select = $this->newQuery() + ->cols(array('*')) + ->from('table2 AS t2') + ->where("field IN (?)", $sub); + + $expect = ' + SELECT + * + FROM + <> AS <> + WHERE + field IN (SELECT + * + FROM + <> AS <>) + '; + $actual = $select->__toString(); + $this->assertSameSql($expect, $actual); + } + + public function testIssue49() + { + $this->assertSame(0, $this->query->getPage()); + $this->assertSame(10, $this->query->getPaging()); + $this->assertSame(0, $this->query->getLimit()); + $this->assertSame(0, $this->query->getOffset()); + + $this->query->page(3); + $this->assertSame(3, $this->query->getPage()); + $this->assertSame(10, $this->query->getPaging()); + $this->assertSame(10, $this->query->getLimit()); + $this->assertSame(20, $this->query->getOffset()); + + $this->query->limit(10); + $this->assertSame(0, $this->query->getPage()); + $this->assertSame(10, $this->query->getPaging()); + $this->assertSame(10, $this->query->getLimit()); + $this->assertSame(0, $this->query->getOffset()); + + $this->query->page(3); + $this->query->setPaging(50); + $this->assertSame(3, $this->query->getPage()); + $this->assertSame(50, $this->query->getPaging()); + $this->assertSame(50, $this->query->getLimit()); + $this->assertSame(100, $this->query->getOffset()); + + $this->query->offset(10); + $this->assertSame(0, $this->query->getPage()); + $this->assertSame(50, $this->query->getPaging()); + $this->assertSame(0, $this->query->getLimit()); + $this->assertSame(10, $this->query->getOffset()); + } + + public function testWhereSubSelectImportsBoundValues() + { + // sub select + $sub = $this->newQuery() + ->cols(array('*')) + ->from('table1 AS t1') + ->where('t1.foo = ?', 'bar'); + + $expect = ' + SELECT + * + FROM + <> AS <> + WHERE + <>.<> = :_1_1_ + '; + $actual = $sub->getStatement(); + $this->assertSameSql($expect, $actual); + + // main select + $select = $this->newQuery() + ->cols(array('*')) + ->from('table2 AS t2') + ->where("field IN (?)", $sub) + ->where("t2.baz = ?", 'dib'); + + $expect = ' + SELECT + * + FROM + <> AS <> + WHERE + field IN (SELECT + * + FROM + <> AS <> + WHERE + <>.<> = :_1_1_) + AND <>.<> = :_2_2_ + '; + + // B.b.: The _2_2_ means "2nd query, 2nd sequential bound value". It's + // the 2nd bound value because the 1st one is imported fromt the 1st + // query (the subselect). + + $actual = $select->getStatement(); + $this->assertSameSql($expect, $actual); + + $expect = array( + '_1_1_' => 'bar', + '_2_2_' => 'dib', + ); + $actual = $select->getBindValues(); + $this->assertSame($expect, $actual); + } + + public function testUnionSelectCanHaveSameAliasesInDifferentSelects() + { + $select = $this->query + ->cols(array( + '...' + )) + ->from('a') + ->join('INNER', 'c', 'a_cid = c_id') + ->union() + ->cols(array( + '...' + )) + ->from('b') + ->join('INNER', 'c', 'b_cid = c_id'); + + $expected = 'SELECT + ... + FROM + <> + INNER JOIN <> ON a_cid = c_id + UNION + SELECT + ... + FROM + <> + INNER JOIN <> ON b_cid = c_id'; + + $actual = (string) $select->getStatement(); + $this->assertSameSql($expected, $actual); + } +} diff --git a/vendor/aura/sqlquery/tests/Common/UpdateTest.php b/vendor/aura/sqlquery/tests/Common/UpdateTest.php new file mode 100644 index 000000000..de4996dae --- /dev/null +++ b/vendor/aura/sqlquery/tests/Common/UpdateTest.php @@ -0,0 +1,45 @@ +query->table('t1') + ->cols(array('c1', 'c2')) + ->col('c3') + ->set('c4', null) + ->set('c5', 'NOW()') + ->where('foo = ?', 'bar') + ->where('baz = ?', 'dib') + ->orWhere('zim = gir'); + + $actual = $this->query->__toString(); + $expect = " + UPDATE <> + SET + <> = :c1, + <> = :c2, + <> = :c3, + <> = NULL, + <> = NOW() + WHERE + foo = :_1_ + AND baz = :_2_ + OR zim = gir + "; + + $this->assertSameSql($expect, $actual); + + $actual = $this->query->getBindValues(); + $expect = array( + '_1_' => 'bar', + '_2_' => 'dib', + ); + $this->assertSame($expect, $actual); + } +} diff --git a/vendor/aura/sqlquery/tests/FakeQuery.php b/vendor/aura/sqlquery/tests/FakeQuery.php new file mode 100644 index 000000000..cc179ccec --- /dev/null +++ b/vendor/aura/sqlquery/tests/FakeQuery.php @@ -0,0 +1,20 @@ +> + WHERE + foo = :_1_ + AND baz = :_2_ + OR zim = gir + "; + + public function testOrderByLimit() + { + $this->query->from('t1') + ->orderBy(array('c1', 'c2')) + ->limit(10); + + $actual = $this->query->__toString(); + $expect = ' + DELETE FROM <> + ORDER BY + c1, + c2 + LIMIT 10 + '; + $this->assertSameSql($expect, $actual); + } + + public function testLowPriority() + { + $this->query->lowPriority() + ->from('t1') + ->where('foo = ?', 'bar') + ->where('baz = ?', 'dib') + ->orWhere('zim = gir'); + + $actual = $this->query->__toString(); + $expect = sprintf($this->expected_sql_with_flag, 'LOW_PRIORITY'); + $this->assertSameSql($expect, $actual); + + $actual = $this->query->getBindValues(); + $expect = array( + '_1_' => 'bar', + '_2_' => 'dib', + ); + $this->assertSame($expect, $actual); + } + + public function testQuick() + { + $this->query->quick() + ->from('t1') + ->where('foo = ?', 'bar') + ->where('baz = ?', 'dib') + ->orWhere('zim = gir'); + + $actual = $this->query->__toString(); + $expect = sprintf($this->expected_sql_with_flag, 'QUICK'); + $this->assertSameSql($expect, $actual); + + $actual = $this->query->getBindValues(); + $expect = array( + '_1_' => 'bar', + '_2_' => 'dib', + ); + $this->assertSame($expect, $actual); + } + + public function testIgnore() + { + $this->query->ignore() + ->from('t1') + ->where('foo = ?', 'bar') + ->where('baz = ?', 'dib') + ->orWhere('zim = gir'); + + $actual = $this->query->__toString(); + $expect = sprintf($this->expected_sql_with_flag, 'IGNORE'); + $this->assertSameSql($expect, $actual); + + $actual = $this->query->getBindValues(); + $expect = array( + '_1_' => 'bar', + '_2_' => 'dib', + ); + $this->assertSame($expect, $actual); + } + + public function testGetterOnLimitAndOffset() + { + $this->query->from('t1') + ->limit(5); + + $this->assertSame(5, $this->query->getLimit()); + + } +} diff --git a/vendor/aura/sqlquery/tests/Mysql/InsertTest.php b/vendor/aura/sqlquery/tests/Mysql/InsertTest.php new file mode 100644 index 000000000..0b429007e --- /dev/null +++ b/vendor/aura/sqlquery/tests/Mysql/InsertTest.php @@ -0,0 +1,125 @@ +> ( + <>, + <>, + <>, + <>, + <> + ) VALUES ( + :c1, + :c2, + :c3, + NOW(), + NULL + ) + "; + + protected $expected_sql_on_duplicate_key_update = " + INSERT INTO <> ( + <>, + <>, + <>, + <>, + <> + ) VALUES ( + :c1, + :c2, + :c3, + NOW(), + NULL + ) ON DUPLICATE KEY UPDATE + <> = :c1__on_duplicate_key, + <> = :c2__on_duplicate_key, + <> = :c3__on_duplicate_key, + <> = NULL, + <> = :c5__on_duplicate_key + "; + + public function testHighPriority() + { + $this->query->highPriority() + ->into('t1') + ->cols(array('c1', 'c2', 'c3')) + ->set('c4', 'NOW()') + ->set('c5', null); + + $actual = $this->query->__toString(); + $expect = sprintf($this->expected_sql_with_flag, 'HIGH_PRIORITY'); + + $this->assertSameSql($expect, $actual); + } + + public function testLowPriority() + { + $this->query->lowPriority() + ->into('t1') + ->cols(array('c1', 'c2', 'c3')) + ->set('c4', 'NOW()') + ->set('c5', null); + + $actual = $this->query->__toString(); + $expect = sprintf($this->expected_sql_with_flag, 'LOW_PRIORITY'); + + $this->assertSameSql($expect, $actual); + } + + public function testDelayed() + { + $this->query->delayed() + ->into('t1') + ->cols(array('c1', 'c2', 'c3')) + ->set('c4', 'NOW()') + ->set('c5', null); + + $actual = $this->query->__toString(); + $expect = sprintf($this->expected_sql_with_flag, 'DELAYED'); + + $this->assertSameSql($expect, $actual); + } + + public function testIgnore() + { + $this->query->ignore() + ->into('t1') + ->cols(array('c1', 'c2', 'c3')) + ->set('c4', 'NOW()') + ->set('c5', null); + + $actual = $this->query->__toString(); + $expect = sprintf($this->expected_sql_with_flag, 'IGNORE'); + + $this->assertSameSql($expect, $actual); + } + + public function testOnDuplicateKeyUpdate() + { + $this->query->into('t1') + ->cols(array('c1', 'c2' => 'c2-inserted', 'c3')) + ->set('c4', 'NOW()') + ->set('c5', null) + ->onDuplicateKeyUpdateCols(array('c1', 'c2' => 'c2-updated', 'c3')) + ->onDuplicateKeyUpdate('c4', null) + ->onDuplicateKeyUpdateCol('c5', 'c5-updated'); + + $actual = $this->query->__toString(); + $expect = $this->expected_sql_on_duplicate_key_update; + $this->assertSameSql($expect, $actual); + + $expect = array ( + 'c2' => 'c2-inserted', + 'c2__on_duplicate_key' => 'c2-updated', + 'c5__on_duplicate_key' => 'c5-updated', + ); + $actual = $this->query->getBindValues(); + $this->assertSame($expect, $actual); + } +} diff --git a/vendor/aura/sqlquery/tests/Mysql/SelectTest.php b/vendor/aura/sqlquery/tests/Mysql/SelectTest.php new file mode 100644 index 000000000..95d8605b2 --- /dev/null +++ b/vendor/aura/sqlquery/tests/Mysql/SelectTest.php @@ -0,0 +1,128 @@ +>.<>, + <>.<>, + <>.<> + FROM + <> + '; + + public function testMultiFlags() + { + $this->query->calcFoundRows() + ->distinct() + ->noCache() + ->from('t1') + ->cols(array('t1.c1', 't1.c2', 't1.c3')); + + $actual = $this->query->__toString(); + + $expect = sprintf($this->expected_sql_with_flag, 'SQL_CALC_FOUND_ROWS DISTINCT SQL_NO_CACHE'); + $this->assertSameSql($expect, $actual); + } + + public function testCalcFoundRows() + { + $this->query->calcFoundRows() + ->from('t1') + ->cols(array('t1.c1', 't1.c2', 't1.c3')); + + $actual = $this->query->__toString(); + + $expect = sprintf($this->expected_sql_with_flag, 'SQL_CALC_FOUND_ROWS'); + $this->assertSameSql($expect, $actual); + } + + public function testCache() + { + $this->query->cache() + ->from('t1') + ->cols(array('t1.c1', 't1.c2', 't1.c3')); + + $actual = $this->query->__toString(); + + $expect = sprintf($this->expected_sql_with_flag, 'SQL_CACHE'); + $this->assertSameSql($expect, $actual); + } + + public function testNoCache() + { + $this->query->noCache() + ->from('t1') + ->cols(array('t1.c1', 't1.c2', 't1.c3')); + + $actual = $this->query->__toString(); + + $expect = sprintf($this->expected_sql_with_flag, 'SQL_NO_CACHE'); + $this->assertSameSql($expect, $actual); + } + + public function testStraightJoin() + { + $this->query->straightJoin() + ->from('t1') + ->cols(array('t1.c1', 't1.c2', 't1.c3')); + + $actual = $this->query->__toString(); + + $expect = sprintf($this->expected_sql_with_flag, 'STRAIGHT_JOIN'); + $this->assertSameSql($expect, $actual); + } + + public function testHighPriority() + { + $this->query->highPriority() + ->from('t1') + ->cols(array('t1.c1', 't1.c2', 't1.c3')); + + $actual = $this->query->__toString(); + + $expect = sprintf($this->expected_sql_with_flag, 'HIGH_PRIORITY'); + $this->assertSameSql($expect, $actual); + } + + public function testSmallResult() + { + $this->query->smallResult() + ->from('t1') + ->cols(array('t1.c1', 't1.c2', 't1.c3')); + + $actual = $this->query->__toString(); + + $expect = sprintf($this->expected_sql_with_flag, 'SQL_SMALL_RESULT'); + $this->assertSameSql($expect, $actual); + } + + public function testBigResult() + { + $this->query->bigResult() + ->from('t1') + ->cols(array('t1.c1', 't1.c2', 't1.c3')); + + $actual = $this->query->__toString(); + + $expect = sprintf($this->expected_sql_with_flag, 'SQL_BIG_RESULT'); + $this->assertSameSql($expect, $actual); + } + + public function testBufferResult() + { + $this->query->bufferResult() + ->from('t1') + ->cols(array('t1.c1', 't1.c2', 't1.c3')); + + $actual = $this->query->__toString(); + + $expect = sprintf($this->expected_sql_with_flag, 'SQL_BUFFER_RESULT'); + $this->assertSameSql($expect, $actual); + } +} diff --git a/vendor/aura/sqlquery/tests/Mysql/UpdateTest.php b/vendor/aura/sqlquery/tests/Mysql/UpdateTest.php new file mode 100644 index 000000000..d8cb7f2ec --- /dev/null +++ b/vendor/aura/sqlquery/tests/Mysql/UpdateTest.php @@ -0,0 +1,100 @@ +> + SET + <> = :c1, + <> = :c2, + <> = :c3, + <> = NULL, + <> = NOW() + WHERE + foo = :_1_ + AND baz = :_2_ + OR zim = gir + LIMIT 5 + "; + + public function testOrderByLimit() + { + $this->query->table('t1') + ->col('c1') + ->orderBy(array('c2')) + ->limit(10); + + $actual = $this->query->__toString(); + $expect = ' + UPDATE <> + SET + <> = :c1 + ORDER BY + c2 + LIMIT 10 + '; + + $this->assertSameSql($expect, $actual); + } + + public function testLowPriority() + { + $this->query->lowPriority() + ->table('t1') + ->cols(array('c1', 'c2', 'c3')) + ->set('c4', null) + ->set('c5', 'NOW()') + ->where('foo = ?', 'bar') + ->where('baz = ?', 'dib') + ->orWhere('zim = gir') + ->limit(5); + + $actual = $this->query->__toString(); + $expect = sprintf($this->expected_sql_with_flag, ' LOW_PRIORITY'); + $this->assertSameSql($expect, $actual); + + $actual = $this->query->getBindValues(); + $expect = array( + '_1_' => 'bar', + '_2_' => 'dib', + ); + $this->assertSame($expect, $actual); + } + + public function testIgnore() + { + $this->query->ignore() + ->table('t1') + ->cols(array('c1', 'c2', 'c3')) + ->set('c4', null) + ->set('c5', 'NOW()') + ->where('foo = ?', 'bar') + ->where('baz = ?', 'dib') + ->orWhere('zim = gir') + ->limit(5); + + $actual = $this->query->__toString(); + $expect = sprintf($this->expected_sql_with_flag, ' IGNORE'); + $this->assertSameSql($expect, $actual); + + $actual = $this->query->getBindValues(); + $expect = array( + '_1_' => 'bar', + '_2_' => 'dib', + ); + $this->assertSame($expect, $actual); + } + + public function testGetterOnLimitAndOffset() + { + $this->query->table('t1') + ->limit(5); + + $this->assertSame(5, $this->query->getLimit()); + } +} diff --git a/vendor/aura/sqlquery/tests/Pgsql/DeleteTest.php b/vendor/aura/sqlquery/tests/Pgsql/DeleteTest.php new file mode 100644 index 000000000..19f1cd3ec --- /dev/null +++ b/vendor/aura/sqlquery/tests/Pgsql/DeleteTest.php @@ -0,0 +1,39 @@ +query->from('t1') + ->where('foo = ?', 'bar') + ->where('baz = ?', 'dib') + ->orWhere('zim = gir') + ->returning(array('foo', 'baz', 'zim')); + + $actual = $this->query->__toString(); + $expect = " + DELETE FROM <> + WHERE + foo = :_1_ + AND baz = :_2_ + OR zim = gir + RETURNING + foo, + baz, + zim + "; + $this->assertSameSql($expect, $actual); + + $actual = $this->query->getBindValues(); + $expect = array( + '_1_' => 'bar', + '_2_' => 'dib', + ); + $this->assertSame($expect, $actual); + } +} diff --git a/vendor/aura/sqlquery/tests/Pgsql/InsertTest.php b/vendor/aura/sqlquery/tests/Pgsql/InsertTest.php new file mode 100644 index 000000000..c5ed19614 --- /dev/null +++ b/vendor/aura/sqlquery/tests/Pgsql/InsertTest.php @@ -0,0 +1,50 @@ +query->into('t1') + ->cols(array('c1', 'c2', 'c3')) + ->set('c4', 'NOW()') + ->set('c5', null) + ->returning(array('c1', 'c2')) + ->returning(array('c3')); + + $actual = $this->query->__toString(); + $expect = " + INSERT INTO <> ( + <>, + <>, + <>, + <>, + <> + ) VALUES ( + :c1, + :c2, + :c3, + NOW(), + NULL + ) + RETURNING + c1, + c2, + c3 + "; + + $this->assertSameSql($expect, $actual); + } + + public function testGetLastInsertIdName_default() + { + $this->query->into('table'); + $actual = $this->query->getLastInsertIdName('col'); + $expect = 'table_col_seq'; + $this->assertSame($expect, $actual); + } +} diff --git a/vendor/aura/sqlquery/tests/Pgsql/SelectTest.php b/vendor/aura/sqlquery/tests/Pgsql/SelectTest.php new file mode 100644 index 000000000..3df0ea8d7 --- /dev/null +++ b/vendor/aura/sqlquery/tests/Pgsql/SelectTest.php @@ -0,0 +1,9 @@ +query->table('t1') + ->cols(array('c1', 'c2', 'c3')) + ->set('c4', null) + ->set('c5', 'NOW()') + ->where('foo = ?', 'bar') + ->where('baz = ?', 'dib') + ->orWhere('zim = gir') + ->returning(array('c1', 'c2')) + ->returning(array('c3')); + + $actual = $this->query->__toString(); + $expect = " + UPDATE <> + SET + <> = :c1, + <> = :c2, + <> = :c3, + <> = NULL, + <> = NOW() + WHERE + foo = :_1_ + AND baz = :_2_ + OR zim = gir + RETURNING + c1, + c2, + c3 + "; + $this->assertSameSql($expect, $actual); + + $actual = $this->query->getBindValues(); + $expect = array( + '_1_' => 'bar', + '_2_' => 'dib', + ); + $this->assertSame($expect, $actual); + } +} diff --git a/vendor/aura/sqlquery/tests/QueryFactoryTest.php b/vendor/aura/sqlquery/tests/QueryFactoryTest.php new file mode 100644 index 000000000..a5ca3cbac --- /dev/null +++ b/vendor/aura/sqlquery/tests/QueryFactoryTest.php @@ -0,0 +1,76 @@ +$method(); + $this->assertInstanceOf($expect, $actual); + } + + public function provider() + { + return array( + // db-specific + array('Common', false, 'Select', 'Aura\SqlQuery\Common\Select'), + array('Common', false, 'Insert', 'Aura\SqlQuery\Common\Insert'), + array('Common', false, 'Update', 'Aura\SqlQuery\Common\Update'), + array('Common', false, 'Delete', 'Aura\SqlQuery\Common\Delete'), + array('Mysql', false, 'Select', 'Aura\SqlQuery\Mysql\Select'), + array('Mysql', false, 'Insert', 'Aura\SqlQuery\Mysql\Insert'), + array('Mysql', false, 'Update', 'Aura\SqlQuery\Mysql\Update'), + array('Mysql', false, 'Delete', 'Aura\SqlQuery\Mysql\Delete'), + array('Pgsql', false, 'Select', 'Aura\SqlQuery\Pgsql\Select'), + array('Pgsql', false, 'Insert', 'Aura\SqlQuery\Pgsql\Insert'), + array('Pgsql', false, 'Update', 'Aura\SqlQuery\Pgsql\Update'), + array('Pgsql', false, 'Delete', 'Aura\SqlQuery\Pgsql\Delete'), + array('Sqlite', false, 'Select', 'Aura\SqlQuery\Sqlite\Select'), + array('Sqlite', false, 'Insert', 'Aura\SqlQuery\Sqlite\Insert'), + array('Sqlite', false, 'Update', 'Aura\SqlQuery\Sqlite\Update'), + array('Sqlite', false, 'Delete', 'Aura\SqlQuery\Sqlite\Delete'), + array('Sqlsrv', false, 'Select', 'Aura\SqlQuery\Sqlsrv\Select'), + array('Sqlsrv', false, 'Insert', 'Aura\SqlQuery\Sqlsrv\Insert'), + array('Sqlsrv', false, 'Update', 'Aura\SqlQuery\Sqlsrv\Update'), + array('Sqlsrv', false, 'Delete', 'Aura\SqlQuery\Sqlsrv\Delete'), + + // force common + array('Common', QueryFactory::COMMON, 'Select', 'Aura\SqlQuery\Common\Select'), + array('Common', QueryFactory::COMMON, 'Insert', 'Aura\SqlQuery\Common\Insert'), + array('Common', QueryFactory::COMMON, 'Update', 'Aura\SqlQuery\Common\Update'), + array('Common', QueryFactory::COMMON, 'Delete', 'Aura\SqlQuery\Common\Delete'), + array('Mysql', QueryFactory::COMMON, 'Select', 'Aura\SqlQuery\Common\Select'), + array('Mysql', QueryFactory::COMMON, 'Insert', 'Aura\SqlQuery\Common\Insert'), + array('Mysql', QueryFactory::COMMON, 'Update', 'Aura\SqlQuery\Common\Update'), + array('Mysql', QueryFactory::COMMON, 'Delete', 'Aura\SqlQuery\Common\Delete'), + array('Pgsql', QueryFactory::COMMON, 'Select', 'Aura\SqlQuery\Common\Select'), + array('Pgsql', QueryFactory::COMMON, 'Insert', 'Aura\SqlQuery\Common\Insert'), + array('Pgsql', QueryFactory::COMMON, 'Update', 'Aura\SqlQuery\Common\Update'), + array('Pgsql', QueryFactory::COMMON, 'Delete', 'Aura\SqlQuery\Common\Delete'), + array('Sqlite', QueryFactory::COMMON, 'Select', 'Aura\SqlQuery\Common\Select'), + array('Sqlite', QueryFactory::COMMON, 'Insert', 'Aura\SqlQuery\Common\Insert'), + array('Sqlite', QueryFactory::COMMON, 'Update', 'Aura\SqlQuery\Common\Update'), + array('Sqlite', QueryFactory::COMMON, 'Delete', 'Aura\SqlQuery\Common\Delete'), + array('Sqlsrv', QueryFactory::COMMON, 'Select', 'Aura\SqlQuery\Common\Select'), + array('Sqlsrv', QueryFactory::COMMON, 'Insert', 'Aura\SqlQuery\Common\Insert'), + array('Sqlsrv', QueryFactory::COMMON, 'Update', 'Aura\SqlQuery\Common\Update'), + array('Sqlsrv', QueryFactory::COMMON, 'Delete', 'Aura\SqlQuery\Common\Delete'), + ); + } + + public function testSeqBindPrefix() + { + $query_factory = new QueryFactory('sqlite'); + + $first = $query_factory->newSelect(); + $this->assertSame('', $first->getSeqBindPrefix()); + + $again = $query_factory->newSelect(); + $this->assertSame('_1', $again->getSeqBindPrefix()); + } +} diff --git a/vendor/aura/sqlquery/tests/QuoterTest.php b/vendor/aura/sqlquery/tests/QuoterTest.php new file mode 100644 index 000000000..a963ccca0 --- /dev/null +++ b/vendor/aura/sqlquery/tests/QuoterTest.php @@ -0,0 +1,50 @@ +quoter = new Quoter('`', '`'); + } + + public function testQuoteName() + { + // table AS alias + $actual = $this->quoter->quoteName('table AS alias'); + $this->assertSame('`table` AS `alias`', $actual); + + // table.col AS alias + $actual = $this->quoter->quoteName('table.col AS alias'); + $this->assertSame('`table`.`col` AS `alias`', $actual); + + // table alias + $actual = $this->quoter->quoteName('table alias'); + $this->assertSame('`table` `alias`', $actual); + + // table.col alias + $actual = $this->quoter->quoteName('table.col alias'); + $this->assertSame('`table`.`col` `alias`', $actual); + + // plain old identifier + $actual = $this->quoter->quoteName('table'); + $this->assertSame('`table`', $actual); + + // star + $actual = $this->quoter->quoteName('*'); + $this->assertSame('*', $actual); + + // star dot star + $actual = $this->quoter->quoteName('*.*'); + $this->assertSame('*.*', $actual); + } + + public function testQuoteNamesIn() + { + $sql = "*, *.*, f.bar, foo.bar, CONCAT('foo.bar', \"baz.dib\") AS zim"; + $actual = $this->quoter->quoteNamesIn($sql); + $expect = "*, *.*, `f`.`bar`, `foo`.`bar`, CONCAT('foo.bar', \"baz.dib\") AS `zim`"; + $this->assertSame($expect, $actual); + } +} diff --git a/vendor/aura/sqlquery/tests/Sqlite/DeleteTest.php b/vendor/aura/sqlquery/tests/Sqlite/DeleteTest.php new file mode 100644 index 000000000..f66f0665c --- /dev/null +++ b/vendor/aura/sqlquery/tests/Sqlite/DeleteTest.php @@ -0,0 +1,50 @@ +query->from('t1') + ->where('foo = ?', 'bar') + ->where('baz = ?', 'dib') + ->orWhere('zim = gir') + ->orderBy(array('zim DESC')) + ->limit(5) + ->offset(10); + + $actual = $this->query->__toString(); + $expect = " + DELETE FROM <> + WHERE + foo = :_1_ + AND baz = :_2_ + OR zim = gir + ORDER BY + zim DESC + LIMIT 5 OFFSET 10 + "; + $this->assertSameSql($expect, $actual); + + $actual = $this->query->getBindValues(); + $expect = array( + '_1_' => 'bar', + '_2_' => 'dib', + ); + $this->assertSame($expect, $actual); + } + + public function testGetterOnLimitAndOffset() + { + $this->query->from('t1') + ->limit(5) + ->offset(10); + + $this->assertSame(5, $this->query->getLimit()); + $this->assertSame(10, $this->query->getOffset()); + } +} diff --git a/vendor/aura/sqlquery/tests/Sqlite/InsertTest.php b/vendor/aura/sqlquery/tests/Sqlite/InsertTest.php new file mode 100644 index 000000000..689640d60 --- /dev/null +++ b/vendor/aura/sqlquery/tests/Sqlite/InsertTest.php @@ -0,0 +1,95 @@ +> ( + <>, + <>, + <>, + <>, + <> + ) VALUES ( + :c1, + :c2, + :c3, + NOW(), + NULL + ) + "; + + public function testOrAbort() + { + $this->query->orAbort() + ->into('t1') + ->cols(array('c1', 'c2', 'c3')) + ->set('c4', 'NOW()') + ->set('c5', null); + + $actual = $this->query->__toString(); + $expect = sprintf($this->expected_sql_with_flag, 'OR ABORT'); + + $this->assertSameSql($expect, $actual); + } + + public function testOrFail() + { + $this->query->orFail() + ->into('t1') + ->cols(array('c1', 'c2', 'c3')) + ->set('c4', 'NOW()') + ->set('c5', null); + + $actual = $this->query->__toString(); + $expect = sprintf($this->expected_sql_with_flag, 'OR FAIL'); + + $this->assertSameSql($expect, $actual); + } + + public function testOrIgnore() + { + $this->query->orIgnore() + ->into('t1') + ->cols(array('c1', 'c2', 'c3')) + ->set('c4', 'NOW()') + ->set('c5', null); + + $actual = $this->query->__toString(); + $expect = sprintf($this->expected_sql_with_flag, 'OR IGNORE'); + + $this->assertSameSql($expect, $actual); + } + + public function testOrReplace() + { + $this->query->orReplace() + ->into('t1') + ->cols(array('c1', 'c2', 'c3')) + ->set('c4', 'NOW()') + ->set('c5', null); + + $actual = $this->query->__toString(); + $expect = sprintf($this->expected_sql_with_flag, 'OR REPLACE'); + + $this->assertSameSql($expect, $actual); + } + + public function testOrRollback() + { + $this->query->orRollback() + ->into('t1') + ->cols(array('c1', 'c2', 'c3')) + ->set('c4', 'NOW()') + ->set('c5', null); + + $actual = $this->query->__toString(); + $expect = sprintf($this->expected_sql_with_flag, 'OR ROLLBACK'); + + $this->assertSameSql($expect, $actual); + } +} diff --git a/vendor/aura/sqlquery/tests/Sqlite/SelectTest.php b/vendor/aura/sqlquery/tests/Sqlite/SelectTest.php new file mode 100644 index 000000000..374ad4264 --- /dev/null +++ b/vendor/aura/sqlquery/tests/Sqlite/SelectTest.php @@ -0,0 +1,9 @@ +> + SET + <> = :c1, + <> = :c2, + <> = :c3, + <> = NULL, + <> = NOW() + WHERE + foo = :_1_ + AND baz = :_2_ + OR zim = gir + LIMIT 5 + "; + + public function testOrderLimit() + { + $this->query->table('t1') + ->cols(array('c1', 'c2', 'c3')) + ->set('c4', null) + ->set('c5', 'NOW()') + ->where('foo = ?', 'bar') + ->where('baz = ?', 'dib') + ->orWhere('zim = gir') + ->orderBy(array('zim DESC', 'baz ASC')) + ->limit(5) + ->offset(10); + + $actual = $this->query->__toString(); + $expect = " + UPDATE <> + SET + <> = :c1, + <> = :c2, + <> = :c3, + <> = NULL, + <> = NOW() + WHERE + foo = :_1_ + AND baz = :_2_ + OR zim = gir + ORDER BY + zim DESC, + baz ASC + LIMIT 5 OFFSET 10 + "; + $this->assertSameSql($expect, $actual); + + $actual = $this->query->getBindValues(); + $expect = array( + '_1_' => 'bar', + '_2_' => 'dib', + ); + $this->assertSame($expect, $actual); + } + + public function testOrAbort() + { + $this->query->orAbort() + ->table('t1') + ->cols(array('c1', 'c2', 'c3')) + ->set('c4', null) + ->set('c5', 'NOW()') + ->where('foo = ?', 'bar') + ->where('baz = ?', 'dib') + ->orWhere('zim = gir') + ->limit(5); + + $actual = $this->query->__toString(); + $expect = sprintf($this->expected_sql_with_flag, 'OR ABORT'); + $this->assertSameSql($expect, $actual); + + $actual = $this->query->getBindValues(); + $expect = array( + '_1_' => 'bar', + '_2_' => 'dib', + ); + $this->assertSame($expect, $actual); + } + + public function testOrFail() + { + $this->query->orFail() + ->table('t1') + ->cols(array('c1', 'c2', 'c3')) + ->set('c4', null) + ->set('c5', 'NOW()') + ->where('foo = ?', 'bar') + ->where('baz = ?', 'dib') + ->orWhere('zim = gir') + ->limit(5); + + $actual = $this->query->__toString(); + $expect = sprintf($this->expected_sql_with_flag, 'OR FAIL'); + $this->assertSameSql($expect, $actual); + + $actual = $this->query->getBindValues(); + $expect = array( + '_1_' => 'bar', + '_2_' => 'dib', + ); + $this->assertSame($expect, $actual); + } + + public function testOrIgnore() + { + $this->query->orIgnore() + ->table('t1') + ->cols(array('c1', 'c2', 'c3')) + ->set('c4', null) + ->set('c5', 'NOW()') + ->where('foo = ?', 'bar') + ->where('baz = ?', 'dib') + ->orWhere('zim = gir') + ->limit(5); + + $actual = $this->query->__toString(); + $expect = sprintf($this->expected_sql_with_flag, 'OR IGNORE'); + $this->assertSameSql($expect, $actual); + + $actual = $this->query->getBindValues(); + $expect = array( + '_1_' => 'bar', + '_2_' => 'dib', + ); + $this->assertSame($expect, $actual); + } + + public function testOrReplace() + { + $this->query->orReplace() + ->table('t1') + ->cols(array('c1', 'c2', 'c3')) + ->set('c4', null) + ->set('c5', 'NOW()') + ->where('foo = ?', 'bar') + ->where('baz = ?', 'dib') + ->orWhere('zim = gir') + ->limit(5); + + $actual = $this->query->__toString(); + $expect = sprintf($this->expected_sql_with_flag, 'OR REPLACE'); + $this->assertSameSql($expect, $actual); + + $actual = $this->query->getBindValues(); + $expect = array( + '_1_' => 'bar', + '_2_' => 'dib', + ); + $this->assertSame($expect, $actual); + } + + public function testOrRollback() + { + $this->query->orRollback() + ->table('t1') + ->cols(array('c1', 'c2', 'c3')) + ->set('c4', null) + ->set('c5', 'NOW()') + ->where('foo = ?', 'bar') + ->where('baz = ?', 'dib') + ->orWhere('zim = gir') + ->limit(5); + + $actual = $this->query->__toString(); + $expect = sprintf($this->expected_sql_with_flag, 'OR ROLLBACK'); + $this->assertSameSql($expect, $actual); + + $actual = $this->query->getBindValues(); + $expect = array( + '_1_' => 'bar', + '_2_' => 'dib', + ); + $this->assertSame($expect, $actual); + } + + public function testActual() + { + $pdo = new PDO('sqlite::memory:'); + $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); + $pdo->query("CREATE TABLE test ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + name VARCHAR(50) NOT NULL + )"); + + $names = array( + 'Anna', 'Betty', 'Clara', 'Donna', 'Flora', + 'Gina', 'Hanna', 'Ione', 'Julia', 'Kara', + ); + + $stm = "INSERT INTO test (name) VALUES (:name)"; + foreach ($names as $name) { + $sth = $pdo->prepare($stm); + $sth->execute(array('name' => $name)); + } + + $this->query->table('test') + ->cols(array('name')) + ->where('id = ?', 1) + ->bindValues(array('name' => 'Annabelle')); + + $stm = $this->query->__toString(); + $bind = $this->query->getBindValues(); + + $sth = $pdo->prepare($stm); + $count = $sth->execute($bind); + $this->assertEquals(1, $count); + + $sth = $pdo->prepare('SELECT * FROM test WHERE id = 1'); + $sth->execute(); + $row = $sth->fetch(PDO::FETCH_ASSOC); + $this->assertEquals('Annabelle', $row['name']); + } + + public function testGetterOnLimitAndOffset() + { + $this->query->table('t1'); + $this->query->limit(10); + $this->query->offset(5); + + $this->assertSame(10, $this->query->getLimit()); + $this->assertSame(5, $this->query->getOffset()); + } +} diff --git a/vendor/aura/sqlquery/tests/Sqlsrv/DeleteTest.php b/vendor/aura/sqlquery/tests/Sqlsrv/DeleteTest.php new file mode 100644 index 000000000..b3d47f8a5 --- /dev/null +++ b/vendor/aura/sqlquery/tests/Sqlsrv/DeleteTest.php @@ -0,0 +1,9 @@ +query->cols(array('*')); + $this->query->limit(10); + $expect = ' + SELECT TOP 10 + * + '; + $actual = $this->query->__toString(); + $this->assertSameSql($expect, $actual); + + $this->query->offset(40); + $expect = ' + SELECT + * + OFFSET 40 ROWS FETCH NEXT 10 ROWS ONLY + '; + $actual = $this->query->__toString(); + $this->assertSameSql($expect, $actual); + } + + public function testPage() + { + $this->query->cols(array('*')); + $this->query->page(5); + $expect = ' + SELECT + * + OFFSET 40 ROWS FETCH NEXT 10 ROWS ONLY + '; + $actual = $this->query->__toString(); + $this->assertSameSql($expect, $actual); + } +} diff --git a/vendor/aura/sqlquery/tests/Sqlsrv/UpdateTest.php b/vendor/aura/sqlquery/tests/Sqlsrv/UpdateTest.php new file mode 100644 index 000000000..e45ed5606 --- /dev/null +++ b/vendor/aura/sqlquery/tests/Sqlsrv/UpdateTest.php @@ -0,0 +1,9 @@ +=5.5", + "guzzlehttp/guzzle": "^5.3.3|^6.2.1|^7.0", + "guzzlehttp/psr7": "^1.7.0", + "guzzlehttp/promises": "^1.4.0", + "mtdowling/jmespath.php": "^2.6", + "ext-pcre": "*", + "ext-json": "*", + "ext-simplexml": "*" + }, + "require-dev": { + "ext-openssl": "*", + "ext-dom": "*", + "ext-pcntl": "*", + "ext-sockets": "*", + "phpunit/phpunit": "^4.8.35|^5.4.3", + "behat/behat": "~3.0", + "doctrine/cache": "~1.4", + "aws/aws-php-sns-message-validator": "~1.0", + "nette/neon": "^2.3", + "andrewsville/php-token-reflection": "^1.4", + "psr/cache": "^1.0", + "psr/simple-cache": "^1.0", + "paragonie/random_compat": ">= 2", + "sebastian/comparator": "^1.2.3" + }, + "suggest": { + "ext-openssl": "Allows working with CloudFront private distributions and verifying received SNS messages", + "ext-curl": "To send requests using cURL", + "ext-sockets": "To use client-side monitoring", + "doctrine/cache": "To use the DoctrineCacheAdapter", + "aws/aws-php-sns-message-validator": "To validate incoming SNS notifications" + }, + "autoload": { + "psr-4": { + "Aws\\": "src/" + }, + "files": ["src/functions.php"] + }, + "autoload-dev": { + "psr-4": { + "Aws\\Test\\": "tests/" + }, + "classmap": ["build/"] + }, + "extra": { + "branch-alias": { + "dev-master": "3.0-dev" + } + } +} diff --git a/vendor/bin/generate_vcards b/vendor/bin/generate_vcards old mode 100644 new mode 100755 index 4663c3c16..cfea10b99 --- a/vendor/bin/generate_vcards +++ b/vendor/bin/generate_vcards @@ -1,241 +1,119 @@ #!/usr/bin/env php testdata.vcf - -HI; - - fwrite(STDERR, $help); - exit(2); -} - -$count = (int)$argv[1]; -if ($count < 1) { - fwrite(STDERR, "Count must be at least 1\n"); - exit(2); -} - -fwrite(STDERR, "sabre/vobject " . Version::VERSION . "\n"); -fwrite(STDERR, "Generating " . $count . " vcards in vCard 4.0 format\n"); - /** - * The following list is just some random data we compiled from various - * sources online. - * - * Very little thought went into compiling this list, and certainly nothing - * political or ethical. + * Proxy PHP file generated by Composer * - * We would _love_ more additions to this to add more variation to this list. + * This file includes the referenced bin path (../sabre/vobject/bin/generate_vcards) + * using a stream wrapper to prevent the shebang from being output on PHP<8 * - * Send us PR's and don't be shy adding your own first and last name for fun. + * @generated */ -$sets = array( - "nl" => array( - "country" => "Netherlands", - "boys" => array( - "Anno", - "Bram", - "Daan", - "Evert", - "Finn", - "Jayden", - "Jens", - "Jesse", - "Levi", - "Lucas", - "Luuk", - "Milan", - "René", - "Sem", - "Sibrand", - "Willem", - ), - "girls" => array( - "Celia", - "Emma", - "Fenna", - "Geke", - "Inge", - "Julia", - "Lisa", - "Lotte", - "Mila", - "Sara", - "Sophie", - "Tess", - "Zoë", - ), - "last" => array( - "Bakker", - "Bos", - "De Boer", - "De Groot", - "De Jong", - "De Vries", - "Jansen", - "Janssen", - "Meyer", - "Mulder", - "Peters", - "Smit", - "Van Dijk", - "Van den Berg", - "Visser", - "Vos", - ), - ), - "us" => array( - "country" => "United States", - "boys" => array( - "Aiden", - "Alexander", - "Charles", - "David", - "Ethan", - "Jacob", - "James", - "Jayden", - "John", - "Joseph", - "Liam", - "Mason", - "Michael", - "Noah", - "Richard", - "Robert", - "Thomas", - "William", - ), - "girls" => array( - "Ava", - "Barbara", - "Chloe", - "Dorothy", - "Elizabeth", - "Emily", - "Emma", - "Isabella", - "Jennifer", - "Lily", - "Linda", - "Margaret", - "Maria", - "Mary", - "Mia", - "Olivia", - "Patricia", - "Roxy", - "Sophia", - "Susan", - "Zoe", - ), - "last" => array( - "Smith", - "Johnson", - "Williams", - "Jones", - "Brown", - "Davis", - "Miller", - "Wilson", - "Moore", - "Taylor", - "Anderson", - "Thomas", - "Jackson", - "White", - "Harris", - "Martin", - "Thompson", - "Garcia", - "Martinez", - "Robinson", - ), - ), -); - -$current = 0; - -$r = function($arr) { - - return $arr[mt_rand(0,count($arr)-1)]; - -}; - -$bdayStart = strtotime('-85 years'); -$bdayEnd = strtotime('-20 years'); - -while($current < $count) { - - $current++; - fwrite(STDERR, "\033[100D$current/$count"); - - $country = array_rand($sets); - $gender = mt_rand(0,1)?'girls':'boys'; - - $vcard = new Component\VCard(array( - 'VERSION' => '4.0', - 'FN' => $r($sets[$country][$gender]) . ' ' . $r($sets[$country]['last']), - 'UID' => UUIDUtil::getUUID(), - )); - - $bdayRatio = mt_rand(0,9); - - if($bdayRatio < 2) { - // 20% has a birthday property with a full date - $dt = new \DateTime('@' . mt_rand($bdayStart, $bdayEnd)); - $vcard->add('BDAY', $dt->format('Ymd')); - - } elseif ($bdayRatio < 3) { - // 10% we only know the month and date of - $dt = new \DateTime('@' . mt_rand($bdayStart, $bdayEnd)); - $vcard->add('BDAY', '--' . $dt->format('md')); - } - if ($result = $vcard->validate()) { - ob_start(); - echo "\nWe produced an invalid vcard somehow!\n"; - foreach($result as $message) { - echo " " . $message['message'] . "\n"; +namespace Composer; + +$GLOBALS['_composer_bin_dir'] = __DIR__; +$GLOBALS['_composer_autoload_path'] = __DIR__ . '/..'.'/autoload.php'; + +if (PHP_VERSION_ID < 80000) { + if (!class_exists('Composer\BinProxyWrapper')) { + /** + * @internal + */ + final class BinProxyWrapper + { + private $handle; + private $position; + private $realpath; + + public function stream_open($path, $mode, $options, &$opened_path) + { + // get rid of phpvfscomposer:// prefix for __FILE__ & __DIR__ resolution + $opened_path = substr($path, 17); + $this->realpath = realpath($opened_path) ?: $opened_path; + $opened_path = $this->realpath; + $this->handle = fopen($this->realpath, $mode); + $this->position = 0; + + return (bool) $this->handle; + } + + public function stream_read($count) + { + $data = fread($this->handle, $count); + + if ($this->position === 0) { + $data = preg_replace('{^#!.*\r?\n}', '', $data); + } + + $this->position += strlen($data); + + return $data; + } + + public function stream_cast($castAs) + { + return $this->handle; + } + + public function stream_close() + { + fclose($this->handle); + } + + public function stream_lock($operation) + { + return $operation ? flock($this->handle, $operation) : true; + } + + public function stream_seek($offset, $whence) + { + if (0 === fseek($this->handle, $offset, $whence)) { + $this->position = ftell($this->handle); + return true; + } + + return false; + } + + public function stream_tell() + { + return $this->position; + } + + public function stream_eof() + { + return feof($this->handle); + } + + public function stream_stat() + { + return array(); + } + + public function stream_set_option($option, $arg1, $arg2) + { + return true; + } + + public function url_stat($path, $flags) + { + $path = substr($path, 17); + if (file_exists($path)) { + return stat($path); + } + + return false; + } } - fwrite(STDERR, ob_get_clean()); } - echo $vcard->serialize(); + if ( + (function_exists('stream_get_wrappers') && in_array('phpvfscomposer', stream_get_wrappers(), true)) + || (function_exists('stream_wrapper_register') && stream_wrapper_register('phpvfscomposer', 'Composer\BinProxyWrapper')) + ) { + return include("phpvfscomposer://" . __DIR__ . '/..'.'/sabre/vobject/bin/generate_vcards'); + } } -fwrite(STDERR,"\nDone.\n"); +return include __DIR__ . '/..'.'/sabre/vobject/bin/generate_vcards'; diff --git a/vendor/bin/naturalselection b/vendor/bin/naturalselection old mode 100644 new mode 100755 index 7e20439c1..fdb566282 --- a/vendor/bin/naturalselection +++ b/vendor/bin/naturalselection @@ -1,140 +1,37 @@ -#!/usr/bin/env python - -# -# Copyright (c) 2009-2010 Evert Pot -# All rights reserved. -# http://www.rooftopsolutions.nl/ -# -# This utility is distributed along with SabreDAV -# license: http://sabre.io/license/ Modified BSD License - -import os -from optparse import OptionParser -import time - -def getfreespace(path): - stat = os.statvfs(path) - return stat.f_frsize * stat.f_bavail - -def getbytesleft(path,threshold): - return getfreespace(path)-threshold - -def run(cacheDir, threshold, sleep=5, simulate=False, min_erase = 0): - - bytes = getbytesleft(cacheDir,threshold) - if (bytes>0): - print "Bytes to go before we hit threshold:", bytes - else: - print "Threshold exceeded with:", -bytes, "bytes" - dir = os.listdir(cacheDir) - dir2 = [] - for file in dir: - path = cacheDir + '/' + file - dir2.append({ - "path" : path, - "atime": os.stat(path).st_atime, - "size" : os.stat(path).st_size - }) - - dir2.sort(lambda x,y: int(x["atime"]-y["atime"])) - - filesunlinked = 0 - gainedspace = 0 - - # Left is the amount of bytes that need to be freed up - # The default is the 'min_erase setting' - left = min_erase - - # If the min_erase setting is lower than the amount of bytes over - # the threshold, we use that number instead. - if left < -bytes : - left = -bytes - - print "Need to delete at least:", left; - - for file in dir2: - - # Only deleting files if we're not simulating - if not simulate: os.unlink(file["path"]) - left = int(left - file["size"]) - gainedspace = gainedspace + file["size"] - filesunlinked = filesunlinked + 1 - - if(left<0): - break - - print "%d files deleted (%d bytes)" % (filesunlinked, gainedspace) - - - time.sleep(sleep) - - - -def main(): - parser = OptionParser( - version="naturalselection v0.3", - description="Cache directory manager. Deletes cache entries based on accesstime and free space thresholds.\n" + - "This utility is distributed alongside SabreDAV.", - usage="usage: %prog [options] cacheDirectory", - ) - parser.add_option( - '-s', - dest="simulate", - action="store_true", - help="Don't actually make changes, but just simulate the behaviour", - ) - parser.add_option( - '-r','--runs', - help="How many times to check before exiting. -1 is infinite, which is the default", - type="int", - dest="runs", - default=-1 - ) - parser.add_option( - '-n','--interval', - help="Sleep time in seconds (default = 5)", - type="int", - dest="sleep", - default=5 - ) - parser.add_option( - '-l','--threshold', - help="Threshold in bytes (default = 10737418240, which is 10GB)", - type="int", - dest="threshold", - default=10737418240 - ) - parser.add_option( - '-m', '--min-erase', - help="Minimum number of bytes to erase when the threshold is reached. " + - "Setting this option higher will reduce the number of times the cache directory will need to be scanned. " + - "(the default is 1073741824, which is 1GB.)", - type="int", - dest="min_erase", - default=1073741824 - ) - - options,args = parser.parse_args() - if len(args)<1: - parser.error("This utility requires at least 1 argument") - cacheDir = args[0] - - print "Natural Selection" - print "Cache directory:", cacheDir - free = getfreespace(cacheDir); - print "Current free disk space:", free - - runs = options.runs; - while runs!=0 : - run( - cacheDir, - sleep=options.sleep, - simulate=options.simulate, - threshold=options.threshold, - min_erase=options.min_erase - ) - if runs>0: - runs = runs - 1 - -if __name__ == '__main__' : - main() +#!/usr/bin/env sh + +# Support bash to support `source` with fallback on $0 if this does not run with bash +# https://stackoverflow.com/a/35006505/6512 +selfArg="$BASH_SOURCE" +if [ -z "$selfArg" ]; then + selfArg="$0" +fi + +self=$(realpath $selfArg 2> /dev/null) +if [ -z "$self" ]; then + self="$selfArg" +fi + +dir=$(cd "${self%[/\\]*}" > /dev/null; cd '../sabre/dav/bin' && pwd) + +if [ -d /proc/cygdrive ]; then + case $(which php) in + $(readlink -n /proc/cygdrive)/*) + # We are in Cygwin using Windows php, so the path must be translated + dir=$(cygpath -m "$dir"); + ;; + esac +fi + +export COMPOSER_RUNTIME_BIN_DIR="$(cd "${self%[/\\]*}" > /dev/null; pwd)" + +# If bash is sourcing this file, we have to source the target as well +bashSource="$BASH_SOURCE" +if [ -n "$bashSource" ]; then + if [ "$bashSource" != "$0" ]; then + source "${dir}/naturalselection" "$@" + return + fi +fi + +exec "${dir}/naturalselection" "$@" diff --git a/vendor/bin/sabredav b/vendor/bin/sabredav old mode 100644 new mode 100755 index 032371ba8..1caef5d3c --- a/vendor/bin/sabredav +++ b/vendor/bin/sabredav @@ -1,2 +1,37 @@ -#!/bin/sh -php -S 0.0.0.0:8080 `dirname $0`/sabredav.php +#!/usr/bin/env sh + +# Support bash to support `source` with fallback on $0 if this does not run with bash +# https://stackoverflow.com/a/35006505/6512 +selfArg="$BASH_SOURCE" +if [ -z "$selfArg" ]; then + selfArg="$0" +fi + +self=$(realpath $selfArg 2> /dev/null) +if [ -z "$self" ]; then + self="$selfArg" +fi + +dir=$(cd "${self%[/\\]*}" > /dev/null; cd '../sabre/dav/bin' && pwd) + +if [ -d /proc/cygdrive ]; then + case $(which php) in + $(readlink -n /proc/cygdrive)/*) + # We are in Cygwin using Windows php, so the path must be translated + dir=$(cygpath -m "$dir"); + ;; + esac +fi + +export COMPOSER_RUNTIME_BIN_DIR="$(cd "${self%[/\\]*}" > /dev/null; pwd)" + +# If bash is sourcing this file, we have to source the target as well +bashSource="$BASH_SOURCE" +if [ -n "$bashSource" ]; then + if [ "$bashSource" != "$0" ]; then + source "${dir}/sabredav" "$@" + return + fi +fi + +exec "${dir}/sabredav" "$@" diff --git a/vendor/bin/vobject b/vendor/bin/vobject old mode 100644 new mode 100755 index 2aca7e729..2a5007110 --- a/vendor/bin/vobject +++ b/vendor/bin/vobject @@ -1,27 +1,119 @@ #!/usr/bin/env php realpath = realpath($opened_path) ?: $opened_path; + $opened_path = $this->realpath; + $this->handle = fopen($this->realpath, $mode); + $this->position = 0; + + return (bool) $this->handle; + } + + public function stream_read($count) + { + $data = fread($this->handle, $count); + + if ($this->position === 0) { + $data = preg_replace('{^#!.*\r?\n}', '', $data); + } + + $this->position += strlen($data); + + return $data; + } + + public function stream_cast($castAs) + { + return $this->handle; + } + + public function stream_close() + { + fclose($this->handle); + } + + public function stream_lock($operation) + { + return $operation ? flock($this->handle, $operation) : true; + } + + public function stream_seek($offset, $whence) + { + if (0 === fseek($this->handle, $offset, $whence)) { + $this->position = ftell($this->handle); + return true; + } + + return false; + } + + public function stream_tell() + { + return $this->position; + } + + public function stream_eof() + { + return feof($this->handle); + } + + public function stream_stat() + { + return array(); + } + + public function stream_set_option($option, $arg1, $arg2) + { + return true; + } + + public function url_stat($path, $flags) + { + $path = substr($path, 17); + if (file_exists($path)) { + return stat($path); + } + + return false; + } + } } -} -if (!class_exists('Sabre\\VObject\\Version')) { - fwrite(STDERR, "Composer autoloader could not be loaded.\n"); - die(1); + if ( + (function_exists('stream_get_wrappers') && in_array('phpvfscomposer', stream_get_wrappers(), true)) + || (function_exists('stream_wrapper_register') && stream_wrapper_register('phpvfscomposer', 'Composer\BinProxyWrapper')) + ) { + return include("phpvfscomposer://" . __DIR__ . '/..'.'/sabre/vobject/bin/vobject'); + } } -$cli = new Cli(); -exit($cli->main($argv)); - +return include __DIR__ . '/..'.'/sabre/vobject/bin/vobject'; diff --git a/vendor/composer/autoload_classmap.php b/vendor/composer/autoload_classmap.php index c0eb26162..3e84d83ff 100644 --- a/vendor/composer/autoload_classmap.php +++ b/vendor/composer/autoload_classmap.php @@ -6,6 +6,17 @@ $baseDir = dirname($vendorDir); return array( + 'AES' => $baseDir . '/www/lib/class.aes2.php', + 'Acl' => $baseDir . '/phpwf/plugins/class.acl.php', + 'AdressstammblattPDF' => $baseDir . '/www/lib/dokumente/class.adressstammblatt.php', + 'AnfragePDF' => $baseDir . '/www/lib/dokumente/class.anfrage.php', + 'AngebotPDF' => $baseDir . '/www/lib/dokumente/class.angebot.php', + 'Application' => $baseDir . '/phpwf/class.application.php', + 'ApplicationCore' => $baseDir . '/phpwf/class.application_core.php', + 'ArbeitsnachweisPDF' => $baseDir . '/www/lib/dokumente/class.arbeitsnachweis.php', + 'ArbeitszeitnachweisPDF' => $baseDir . '/www/lib/dokumente/class.arbeitszeitnachweis.php', + 'ArtikelTabelle' => $baseDir . '/www/widgets/artikeltable.php', + 'AuftragPDF' => $baseDir . '/www/lib/dokumente/class.auftrag.php', 'Aura\\SqlQuery\\AbstractDmlQuery' => $vendorDir . '/aura/sqlquery/src/AbstractDmlQuery.php', 'Aura\\SqlQuery\\AbstractQuery' => $vendorDir . '/aura/sqlquery/src/AbstractQuery.php', 'Aura\\SqlQuery\\Common\\Delete' => $vendorDir . '/aura/sqlquery/src/Common/Delete.php', @@ -812,7 +823,16 @@ 'Aws\\kendra\\kendraClient' => $vendorDir . '/aws/aws-sdk-php/src/kendra/kendraClient.php', 'Aws\\signer\\Exception\\signerException' => $vendorDir . '/aws/aws-sdk-php/src/signer/Exception/signerException.php', 'Aws\\signer\\signerClient' => $vendorDir . '/aws/aws-sdk-php/src/signer/signerClient.php', + 'BestellungPDF' => $baseDir . '/www/lib/dokumente/class.bestellung.php', + 'BlindField' => $baseDir . '/phpwf/htmltags/class.form.php', + 'BriefPDF' => $baseDir . '/www/lib/dokumente/class.brief.php', + 'Briefpapier' => $baseDir . '/www/lib/dokumente/class.briefpapier.php', + 'BriefpapierCustom' => $baseDir . '/www/lib/dokumente/class.briefpapier_custom.php', + 'CallbackEntry' => $baseDir . '/phpwf/plugins/class.formhandler.php', + 'Chart' => $baseDir . '/phpwf/widgets/chart.php', 'Composer\\InstalledVersions' => $vendorDir . '/composer/InstalledVersions.php', + 'Config' => $baseDir . '/conf/main.conf.php', + 'DB' => $baseDir . '/phpwf/plugins/class.mysql.php', 'Datamatrix' => $vendorDir . '/tecnickcom/tcpdf/include/barcodes/datamatrix.php', 'Datto\\JsonRpc\\Client' => $vendorDir . '/datto/json-rpc/src/Client.php', 'Datto\\JsonRpc\\Evaluator' => $vendorDir . '/datto/json-rpc/src/Evaluator.php', @@ -832,6 +852,18 @@ 'Datto\\JsonRpc\\Responses\\Response' => $vendorDir . '/datto/json-rpc/src/Responses/Response.php', 'Datto\\JsonRpc\\Responses\\ResultResponse' => $vendorDir . '/datto/json-rpc/src/Responses/ResultResponse.php', 'Datto\\JsonRpc\\Server' => $vendorDir . '/datto/json-rpc/src/Server.php', + 'DocscanAuth' => $baseDir . '/www/docscan/classes/DocscanAuth.php', + 'DocscanDir' => $baseDir . '/www/docscan/classes/DocscanDir.php', + 'DocscanFile' => $baseDir . '/www/docscan/classes/DocscanFile.php', + 'DocscanRoot' => $baseDir . '/www/docscan/classes/DocscanRoot.php', + 'DokuArbeitszeit' => $baseDir . '/www/lib/dokumente/class.dokuarbeitszeit.php', + 'Dokumentenvorlage' => $baseDir . '/www/lib/dokumente/class.dokumentenvorlage.php', + 'DownloadSpoolerTable' => $baseDir . '/phpwf/widgets/downloadspoolertable.php', + 'EasyCalendar' => $baseDir . '/phpwf/widgets/easycalendar.php', + 'EasyTable' => $baseDir . '/phpwf/widgets/easytable.php', + 'Etikett' => $baseDir . '/www/lib/dokumente/class.etikett.php', + 'EtikettenPDF' => $baseDir . '/www/lib/dokumente/class.etiketten.php', + 'FPDFWAWISION' => $baseDir . '/www/lib/pdf/fpdf_3.php', 'FastRoute\\BadRouteException' => $vendorDir . '/nikic/fast-route/src/BadRouteException.php', 'FastRoute\\DataGenerator' => $vendorDir . '/nikic/fast-route/src/DataGenerator.php', 'FastRoute\\DataGenerator\\CharCountBased' => $vendorDir . '/nikic/fast-route/src/DataGenerator/CharCountBased.php', @@ -849,6 +881,7 @@ 'FastRoute\\RouteCollector' => $vendorDir . '/nikic/fast-route/src/RouteCollector.php', 'FastRoute\\RouteParser' => $vendorDir . '/nikic/fast-route/src/RouteParser.php', 'FastRoute\\RouteParser\\Std' => $vendorDir . '/nikic/fast-route/src/RouteParser/Std.php', + 'FileTable' => $baseDir . '/phpwf/widgets/filetable.php', 'FiskalyClient\\FiskalyClient' => $vendorDir . '/fiskaly/fiskaly-sdk-php/src/FiskalyClient.php', 'FiskalyClient\\errors\\FiskalyErrorHandler' => $vendorDir . '/fiskaly/fiskaly-sdk-php/src/errors/FiskalyErrorHandler.php', 'FiskalyClient\\errors\\exceptions\\FiskalyClientException' => $vendorDir . '/fiskaly/fiskaly-sdk-php/src/errors/exceptions/FiskalyClientException.php', @@ -859,6 +892,12 @@ 'FiskalyClient\\responses\\RequestResponse' => $vendorDir . '/fiskaly/fiskaly-sdk-php/src/responses/RequestResponse.php', 'FiskalyClient\\responses\\SelfTestResponse' => $vendorDir . '/fiskaly/fiskaly-sdk-php/src/responses/SelfTestResponse.php', 'FiskalyClient\\responses\\VersionResponse' => $vendorDir . '/fiskaly/fiskaly-sdk-php/src/responses/VersionResponse.php', + 'FormActionHandler' => $baseDir . '/phpwf/plugins/class.formhandler.php', + 'FormHandler' => $baseDir . '/phpwf/plugins/class.formhandler.php', + 'FormHandlerField' => $baseDir . '/phpwf/plugins/class.formhandler.php', + 'Geschaeftsbrief' => $baseDir . '/www/lib/dokumente/class.geschaeftsbrief.php', + 'GroupTable' => $baseDir . '/phpwf/widgets/grouptable.php', + 'GutschriftPDF' => $baseDir . '/www/lib/dokumente/class.gutschrift.php', 'GuzzleHttp\\Client' => $vendorDir . '/guzzlehttp/guzzle/src/Client.php', 'GuzzleHttp\\ClientInterface' => $vendorDir . '/guzzlehttp/guzzle/src/ClientInterface.php', 'GuzzleHttp\\Cookie\\CookieJar' => $vendorDir . '/guzzlehttp/guzzle/src/Cookie/CookieJar.php', @@ -940,6 +979,10 @@ 'GuzzleHttp\\TransferStats' => $vendorDir . '/guzzlehttp/guzzle/src/TransferStats.php', 'GuzzleHttp\\UriTemplate' => $vendorDir . '/guzzlehttp/guzzle/src/UriTemplate.php', 'GuzzleHttp\\Utils' => $vendorDir . '/guzzlehttp/guzzle/src/Utils.php', + 'HTMLCheckbox' => $baseDir . '/phpwf/htmltags/class.form.php', + 'HTMLForm' => $baseDir . '/phpwf/htmltags/class.form.php', + 'HTMLInput' => $baseDir . '/phpwf/htmltags/class.form.php', + 'HTMLListEntry' => $baseDir . '/phpwf/plugins/class.formhandler.php', 'HTMLPurifier' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier.php', 'HTMLPurifier_Arborize' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/Arborize.php', 'HTMLPurifier_AttrCollections' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/AttrCollections.php', @@ -1170,6 +1213,14 @@ 'HTMLPurifier_VarParser_Flexible' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/VarParser/Flexible.php', 'HTMLPurifier_VarParser_Native' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/VarParser/Native.php', 'HTMLPurifier_Zipper' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/Zipper.php', + 'HTMLSelect' => $baseDir . '/phpwf/htmltags/class.form.php', + 'HTMLTable' => $baseDir . '/phpwf/htmltags/class.table.php', + 'HTMLTextarea' => $baseDir . '/phpwf/htmltags/class.form.php', + 'HttpClient' => $baseDir . '/www/lib/class.httpclient.php', + 'ICS' => $baseDir . '/www/plugins/class.ics.php', + 'IMAP' => $baseDir . '/www/lib/imap.inc.php', + 'ImageManipulator' => $baseDir . '/www/lib/class.image.php', + 'IndexPoint' => $baseDir . '/www/plugins/class.wikiparser.php', 'JmesPath\\AstRuntime' => $vendorDir . '/mtdowling/jmespath.php/src/AstRuntime.php', 'JmesPath\\CompilerRuntime' => $vendorDir . '/mtdowling/jmespath.php/src/CompilerRuntime.php', 'JmesPath\\DebugRuntime' => $vendorDir . '/mtdowling/jmespath.php/src/DebugRuntime.php', @@ -1181,6 +1232,11 @@ 'JmesPath\\TreeCompiler' => $vendorDir . '/mtdowling/jmespath.php/src/TreeCompiler.php', 'JmesPath\\TreeInterpreter' => $vendorDir . '/mtdowling/jmespath.php/src/TreeInterpreter.php', 'JmesPath\\Utils' => $vendorDir . '/mtdowling/jmespath.php/src/Utils.php', + 'KalkulationPDF' => $baseDir . '/www/lib/dokumente/class.kalkulation.php', + 'KatalogPDF' => $baseDir . '/www/lib/dokumente/class.katalog.php', + 'KommissionierungPDF' => $baseDir . '/www/lib/dokumente/class.kommissionierung.php', + 'KorrespondenzPDF' => $baseDir . '/www/lib/dokumente/class.korrespondenz.php', + 'LagermindestmengenPDF' => $baseDir . '/www/lib/dokumente/class.lagermindestmengen.php', 'Laminas\\Loader\\AutoloaderFactory' => $vendorDir . '/laminas/laminas-loader/src/AutoloaderFactory.php', 'Laminas\\Loader\\ClassMapAutoloader' => $vendorDir . '/laminas/laminas-loader/src/ClassMapAutoloader.php', 'Laminas\\Loader\\Exception\\BadMethodCallException' => $vendorDir . '/laminas/laminas-loader/src/Exception/BadMethodCallException.php', @@ -1505,6 +1561,7 @@ 'Laminas\\Validator\\ValidatorPluginManagerAwareInterface' => $vendorDir . '/laminas/laminas-validator/src/ValidatorPluginManagerAwareInterface.php', 'Laminas\\Validator\\ValidatorPluginManagerFactory' => $vendorDir . '/laminas/laminas-validator/src/ValidatorPluginManagerFactory.php', 'Laminas\\Validator\\ValidatorProviderInterface' => $vendorDir . '/laminas/laminas-validator/src/ValidatorProviderInterface.php', + 'LayoutvorlagenPDF' => $baseDir . '/www/lib/dokumente/class.layoutvorlagen.php', 'League\\ColorExtractor\\Color' => $vendorDir . '/league/color-extractor/src/League/ColorExtractor/Color.php', 'League\\ColorExtractor\\ColorExtractor' => $vendorDir . '/league/color-extractor/src/League/ColorExtractor/ColorExtractor.php', 'League\\ColorExtractor\\Palette' => $vendorDir . '/league/color-extractor/src/League/ColorExtractor/Palette.php', @@ -1567,36 +1624,32 @@ 'League\\MimeTypeDetection\\GeneratedExtensionToMimeTypeMap' => $vendorDir . '/league/mime-type-detection/src/GeneratedExtensionToMimeTypeMap.php', 'League\\MimeTypeDetection\\MimeTypeDetector' => $vendorDir . '/league/mime-type-detection/src/MimeTypeDetector.php', 'League\\MimeTypeDetection\\OverridingExtensionToMimeTypeMap' => $vendorDir . '/league/mime-type-detection/src/OverridingExtensionToMimeTypeMap.php', - 'League\\OAuth1\\Client\\Credentials\\ClientCredentials' => $vendorDir . '/league/oauth1-client/src/Credentials/ClientCredentials.php', - 'League\\OAuth1\\Client\\Credentials\\ClientCredentialsInterface' => $vendorDir . '/league/oauth1-client/src/Credentials/ClientCredentialsInterface.php', - 'League\\OAuth1\\Client\\Credentials\\Credentials' => $vendorDir . '/league/oauth1-client/src/Credentials/Credentials.php', - 'League\\OAuth1\\Client\\Credentials\\CredentialsException' => $vendorDir . '/league/oauth1-client/src/Credentials/CredentialsException.php', - 'League\\OAuth1\\Client\\Credentials\\CredentialsInterface' => $vendorDir . '/league/oauth1-client/src/Credentials/CredentialsInterface.php', - 'League\\OAuth1\\Client\\Credentials\\RsaClientCredentials' => $vendorDir . '/league/oauth1-client/src/Credentials/RsaClientCredentials.php', - 'League\\OAuth1\\Client\\Credentials\\TemporaryCredentials' => $vendorDir . '/league/oauth1-client/src/Credentials/TemporaryCredentials.php', - 'League\\OAuth1\\Client\\Credentials\\TokenCredentials' => $vendorDir . '/league/oauth1-client/src/Credentials/TokenCredentials.php', - 'League\\OAuth1\\Client\\Server\\Bitbucket' => $vendorDir . '/league/oauth1-client/src/Server/Bitbucket.php', - 'League\\OAuth1\\Client\\Server\\Magento' => $vendorDir . '/league/oauth1-client/src/Server/Magento.php', - 'League\\OAuth1\\Client\\Server\\Server' => $vendorDir . '/league/oauth1-client/src/Server/Server.php', - 'League\\OAuth1\\Client\\Server\\Trello' => $vendorDir . '/league/oauth1-client/src/Server/Trello.php', - 'League\\OAuth1\\Client\\Server\\Tumblr' => $vendorDir . '/league/oauth1-client/src/Server/Tumblr.php', - 'League\\OAuth1\\Client\\Server\\Twitter' => $vendorDir . '/league/oauth1-client/src/Server/Twitter.php', - 'League\\OAuth1\\Client\\Server\\User' => $vendorDir . '/league/oauth1-client/src/Server/User.php', - 'League\\OAuth1\\Client\\Server\\Uservoice' => $vendorDir . '/league/oauth1-client/src/Server/Uservoice.php', - 'League\\OAuth1\\Client\\Server\\Xing' => $vendorDir . '/league/oauth1-client/src/Server/Xing.php', - 'League\\OAuth1\\Client\\Signature\\EncodesUrl' => $vendorDir . '/league/oauth1-client/src/Signature/EncodesUrl.php', - 'League\\OAuth1\\Client\\Signature\\HmacSha1Signature' => $vendorDir . '/league/oauth1-client/src/Signature/HmacSha1Signature.php', - 'League\\OAuth1\\Client\\Signature\\PlainTextSignature' => $vendorDir . '/league/oauth1-client/src/Signature/PlainTextSignature.php', - 'League\\OAuth1\\Client\\Signature\\RsaSha1Signature' => $vendorDir . '/league/oauth1-client/src/Signature/RsaSha1Signature.php', - 'League\\OAuth1\\Client\\Signature\\Signature' => $vendorDir . '/league/oauth1-client/src/Signature/Signature.php', - 'League\\OAuth1\\Client\\Signature\\SignatureInterface' => $vendorDir . '/league/oauth1-client/src/Signature/SignatureInterface.php', + 'LieferscheinPDF' => $baseDir . '/www/lib/dokumente/class.lieferschein.php', + 'LiveimportBase' => $baseDir . '/www/plugins/liveimport/LiveimportBase.php', + 'Location' => $baseDir . '/www/lib/class.location.php', + 'MahnwesenPDF' => $baseDir . '/www/lib/dokumente/class.mahnwesen.php', + 'MandatoryEntry' => $baseDir . '/phpwf/plugins/class.formhandler.php', + 'ModuleScriptCache' => $baseDir . '/phpwf/plugins/class.modulescriptcache.php', + 'Navigation' => $baseDir . '/www/lib/class.navigation_edit.php', 'Normalizer' => $vendorDir . '/symfony/polyfill-intl-normalizer/Resources/stubs/Normalizer.php', + 'ObjectAPI' => $baseDir . '/phpwf/plugins/class.objectapi.php', 'PDF417' => $vendorDir . '/tecnickcom/tcpdf/include/barcodes/pdf417.php', + 'PDF_EPS' => $baseDir . '/www/lib/pdf/fpdf_final.php', 'PHPMailer\\PHPMailer\\Exception' => $vendorDir . '/phpmailer/phpmailer/src/Exception.php', 'PHPMailer\\PHPMailer\\OAuth' => $vendorDir . '/phpmailer/phpmailer/src/OAuth.php', 'PHPMailer\\PHPMailer\\PHPMailer' => $vendorDir . '/phpmailer/phpmailer/src/PHPMailer.php', 'PHPMailer\\PHPMailer\\POP3' => $vendorDir . '/phpmailer/phpmailer/src/POP3.php', 'PHPMailer\\PHPMailer\\SMTP' => $vendorDir . '/phpmailer/phpmailer/src/SMTP.php', + 'Page' => $baseDir . '/phpwf/plugins/class.page.php', + 'PageBuilder' => $baseDir . '/phpwf/plugins/class.pagebuilder.php', + 'Player' => $baseDir . '/phpwf/class.player.php', + 'PreisanfragePDF' => $baseDir . '/www/lib/dokumente/class.preisanfrage.php', + 'Printer' => $baseDir . '/www/lib/class.printer.php', + 'PrinterBase' => $baseDir . '/www/lib/PrinterBase.php', + 'ProduktionPDF' => $baseDir . '/www/lib/dokumente/class.produktion.php', + 'ProformarechnungPDF' => $baseDir . '/www/lib/dokumente/class.proformarechnung.php', + 'ProjektPDF' => $baseDir . '/www/lib/dokumente/class.projekt.php', + 'ProvisionsgutschriftPDF' => $baseDir . '/www/lib/dokumente/class.provisionsgutschrift.php', 'Psr\\Container\\ContainerExceptionInterface' => $vendorDir . '/psr/container/src/ContainerExceptionInterface.php', 'Psr\\Container\\ContainerInterface' => $vendorDir . '/psr/container/src/ContainerInterface.php', 'Psr\\Container\\NotFoundExceptionInterface' => $vendorDir . '/psr/container/src/NotFoundExceptionInterface.php', @@ -1670,6 +1723,10 @@ 'Rakit\\Validation\\Rules\\Url' => $vendorDir . '/rakit/validation/src/Rules/Url.php', 'Rakit\\Validation\\Validation' => $vendorDir . '/rakit/validation/src/Validation.php', 'Rakit\\Validation\\Validator' => $vendorDir . '/rakit/validation/src/Validator.php', + 'RechnungPDF' => $baseDir . '/www/lib/dokumente/class.rechnung.php', + 'ReisekostenPDF' => $baseDir . '/www/lib/dokumente/class.reisekosten.php', + 'Remote' => $baseDir . '/www/lib/class.remote.php', + 'RetourePDF' => $baseDir . '/www/lib/dokumente/class.retoure.php', 'Sabre\\CalDAV\\Backend\\AbstractBackend' => $vendorDir . '/sabre/dav/lib/CalDAV/Backend/AbstractBackend.php', 'Sabre\\CalDAV\\Backend\\BackendInterface' => $vendorDir . '/sabre/dav/lib/CalDAV/Backend/BackendInterface.php', 'Sabre\\CalDAV\\Backend\\NotificationSupport' => $vendorDir . '/sabre/dav/lib/CalDAV/Backend/NotificationSupport.php', @@ -2010,6 +2067,11 @@ 'Sabre\\Xml\\Writer' => $vendorDir . '/sabre/xml/lib/Writer.php', 'Sabre\\Xml\\XmlDeserializable' => $vendorDir . '/sabre/xml/lib/XmlDeserializable.php', 'Sabre\\Xml\\XmlSerializable' => $vendorDir . '/sabre/xml/lib/XmlSerializable.php', + 'Secure' => $baseDir . '/phpwf/plugins/class.secure.php', + 'SepaMandat' => $baseDir . '/www/lib/dokumente/class.sepamandat.php', + 'Session' => $baseDir . '/phpwf/class.session.php', + 'ShopimporterBase' => $baseDir . '/www/lib/ShopimporterBase.php', + 'SimpleList' => $baseDir . '/phpwf/types/class.simplelist.php', 'Smarty' => $vendorDir . '/smarty/smarty/libs/Smarty.class.php', 'SmartyBC' => $vendorDir . '/smarty/smarty/libs/SmartyBC.class.php', 'SmartyCompilerException' => $vendorDir . '/smarty/smarty/libs/sysplugins/smartycompilerexception.php', @@ -2181,6 +2243,9 @@ 'Smarty_Template_Source' => $vendorDir . '/smarty/smarty/libs/sysplugins/smarty_template_source.php', 'Smarty_Undefined_Variable' => $vendorDir . '/smarty/smarty/libs/sysplugins/smarty_undefined_variable.php', 'Smarty_Variable' => $vendorDir . '/smarty/smarty/libs/sysplugins/smarty_variable.php', + 'SpeditionPDF' => $baseDir . '/www/lib/dokumente/class.spedition.php', + 'StringCleaner' => $baseDir . '/phpwf/plugins/class.stringcleaner.php', + 'SuperFPDF' => $baseDir . '/www/lib/dokumente/class.superfpdf.php', 'SwissPaymentSlip\\SwissPaymentSlipFpdf\\PaymentSlipFpdf' => $vendorDir . '/swiss-payment-slip/swiss-payment-slip-fpdf/src/PaymentSlipFpdf.php', 'SwissPaymentSlip\\SwissPaymentSlipPdf\\PaymentSlipPdf' => $vendorDir . '/swiss-payment-slip/swiss-payment-slip-pdf/src/PaymentSlipPdf.php', 'SwissPaymentSlip\\SwissPaymentSlip\\Exception\\DisabledDataException' => $vendorDir . '/swiss-payment-slip/swiss-payment-slip/src/Exception/DisabledDataException.php', @@ -2208,13 +2273,230 @@ 'TCPDF_STATIC' => $vendorDir . '/tecnickcom/tcpdf/include/tcpdf_static.php', 'TPC_yyStackEntry' => $vendorDir . '/smarty/smarty/libs/sysplugins/smarty_internal_configfileparser.php', 'TP_yyStackEntry' => $vendorDir . '/smarty/smarty/libs/sysplugins/smarty_internal_templateparser.php', + 'TemplateParser' => $baseDir . '/phpwf/plugins/class.templateparser.php', + 'ThemeTemplate' => $baseDir . '/phpwf/plugins/class.templateparser.php', + 'TransferBase' => $baseDir . '/www/lib/TransferBase.php', + 'USTID' => $baseDir . '/www/lib/class.ustid.php', + 'User' => $baseDir . '/phpwf/plugins/class.user.php', 'Versandart_dhl' => $baseDir . '/www/lib/versandarten/dhl.php', 'Versandart_dpddepot' => $baseDir . '/www/lib/versandarten/dpddepot.php', 'Versandart_go' => $baseDir . '/www/lib/versandarten/go.php', 'Versandart_sendcloud' => $baseDir . '/www/lib/versandarten/sendcloud.php', + 'VersandpaketscheinPDF' => $baseDir . '/www/lib/dokumente/class.versandpaketschein.php', + 'WaWisionOTP' => $baseDir . '/phpwf/plugins/class.wawision_otp.php', + 'WawiString' => $baseDir . '/phpwf/plugins/class.string.php', 'Webmozart\\Assert\\Assert' => $vendorDir . '/webmozart/assert/src/Assert.php', 'Webmozart\\Assert\\InvalidArgumentException' => $vendorDir . '/webmozart/assert/src/InvalidArgumentException.php', 'Webmozart\\Assert\\Mixin' => $vendorDir . '/webmozart/assert/src/Mixin.php', + 'WidgetAPI' => $baseDir . '/phpwf/plugins/class.widgetapi.php', + 'WidgetAbrechnungsartikel' => $baseDir . '/www/widgets/widget.abrechnungsartikel.php', + 'WidgetAdapterbox' => $baseDir . '/www/widgets/widget.adapterbox.php', + 'WidgetAdresse' => $baseDir . '/www/widgets/widget.adresse.php', + 'WidgetAdresse_accounts' => $baseDir . '/www/widgets/widget.adresse_accounts.php', + 'WidgetAdresse_rolle' => $baseDir . '/www/widgets/widget.adresse_rolle.php', + 'WidgetAdresse_typ' => $baseDir . '/www/widgets/widget.adresse_typ.php', + 'WidgetAktionscode_liste' => $baseDir . '/www/widgets/widget.aktionscode_liste.php', + 'WidgetAnfrage' => $baseDir . '/www/widgets/widget.anfrage.php', + 'WidgetAnfrage_position' => $baseDir . '/www/widgets/widget.anfrage_position.php', + 'WidgetAngebot' => $baseDir . '/www/widgets/widget.angebot.php', + 'WidgetAngebot_position' => $baseDir . '/www/widgets/widget.angebot_position.php', + 'WidgetAnsprechpartner' => $baseDir . '/www/widgets/widget.ansprechpartner.php', + 'WidgetArbeitsfreietage' => $baseDir . '/www/widgets/widget.arbeitsfreietage.php', + 'WidgetArbeitsnachweis' => $baseDir . '/www/widgets/widget.arbeitsnachweis.php', + 'WidgetArbeitsnachweis_position' => $baseDir . '/www/widgets/widget.arbeitsnachweis_position.php', + 'WidgetArbeitspaket' => $baseDir . '/www/widgets/widget.arbeitspaket.php', + 'WidgetArtikel' => $baseDir . '/www/widgets/widget.artikel.php', + 'WidgetArtikeleigenschaften' => $baseDir . '/www/widgets/widget.artikeleigenschaften.php', + 'WidgetArtikeleinheit' => $baseDir . '/www/widgets/widget.artikeleinheit.php', + 'WidgetArtikelgruppen' => $baseDir . '/www/widgets/widget.artikelgruppen.php', + 'WidgetArtikelkategorien' => $baseDir . '/www/widgets/widget.artikelkategorien.php', + 'WidgetArtikeloptionengruppe' => $baseDir . '/www/widgets/widget.artikeloptionengruppe.php', + 'WidgetAufgabe' => $baseDir . '/www/widgets/widget.aufgabe.php', + 'WidgetAuftrag' => $baseDir . '/www/widgets/widget.auftrag.php', + 'WidgetAuftrag_artikel' => $baseDir . '/www/widgets/widget.auftrag_artikel.php', + 'WidgetAuftrag_position' => $baseDir . '/www/widgets/widget.auftrag_position.php', + 'WidgetBerichte' => $baseDir . '/www/widgets/widget.berichte.php', + 'WidgetBestellung' => $baseDir . '/www/widgets/widget.bestellung.php', + 'WidgetBestellung_position' => $baseDir . '/www/widgets/widget.bestellung_position.php', + 'WidgetBrief' => $baseDir . '/www/widgets/widget.brief.php', + 'WidgetDrucker' => $baseDir . '/www/widgets/widget.drucker.php', + 'WidgetEinkaufspreise' => $baseDir . '/www/widgets/widget.einkaufspreise.php', + 'WidgetEmail' => $baseDir . '/www/widgets/widget.email.php', + 'WidgetEtiketten' => $baseDir . '/www/widgets/widget.etiketten.php', + 'WidgetExportvorlage' => $baseDir . '/www/widgets/widget.exportvorlage.php', + 'WidgetGenabrechnungsartikel' => $baseDir . '/www/widgets/_gen/widget.gen.abrechnungsartikel.php', + 'WidgetGenadapterbox' => $baseDir . '/www/widgets/_gen/widget.gen.adapterbox.php', + 'WidgetGenadresse' => $baseDir . '/www/widgets/_gen/widget.gen.adresse.php', + 'WidgetGenadresse_accounts' => $baseDir . '/www/widgets/_gen/widget.gen.adresse_accounts.php', + 'WidgetGenadresse_onchange' => $baseDir . '/www/widgets/_gen/widget.gen.adresse_onchange.php', + 'WidgetGenadresse_rolle' => $baseDir . '/www/widgets/_gen/widget.gen.adresse_rolle.php', + 'WidgetGenadresse_typ' => $baseDir . '/www/widgets/_gen/widget.gen.adresse_typ.php', + 'WidgetGenaktionscode_liste' => $baseDir . '/www/widgets/_gen/widget.gen.aktionscode_liste.php', + 'WidgetGenanfrage' => $baseDir . '/www/widgets/_gen/widget.gen.anfrage.php', + 'WidgetGenanfrage_position' => $baseDir . '/www/widgets/_gen/widget.gen.anfrage_position.php', + 'WidgetGenangebot' => $baseDir . '/www/widgets/_gen/widget.gen.angebot.php', + 'WidgetGenangebot_position' => $baseDir . '/www/widgets/_gen/widget.gen.angebot_position.php', + 'WidgetGenansprechpartner' => $baseDir . '/www/widgets/_gen/widget.gen.ansprechpartner.php', + 'WidgetGenarbeitsfreietage' => $baseDir . '/www/widgets/_gen/widget.gen.arbeitsfreietage.php', + 'WidgetGenarbeitsnachweis' => $baseDir . '/www/widgets/_gen/widget.gen.arbeitsnachweis.php', + 'WidgetGenarbeitsnachweis_position' => $baseDir . '/www/widgets/_gen/widget.gen.arbeitsnachweis_position.php', + 'WidgetGenarbeitspaket' => $baseDir . '/www/widgets/_gen/widget.gen.arbeitspaket.php', + 'WidgetGenartikel' => $baseDir . '/www/widgets/_gen/widget.gen.artikel.php', + 'WidgetGenartikeleigenschaften' => $baseDir . '/www/widgets/_gen/widget.gen.artikeleigenschaften.php', + 'WidgetGenartikeleinheit' => $baseDir . '/www/widgets/_gen/widget.gen.artikeleinheit.php', + 'WidgetGenartikelgruppen' => $baseDir . '/www/widgets/_gen/widget.gen.artikelgruppen.php', + 'WidgetGenartikelkategorien' => $baseDir . '/www/widgets/_gen/widget.gen.artikelkategorien.php', + 'WidgetGenartikeloptionengruppe' => $baseDir . '/www/widgets/_gen/widget.gen.artikeloptionengruppe.php', + 'WidgetGenaufgabe' => $baseDir . '/www/widgets/_gen/widget.gen.aufgabe.php', + 'WidgetGenauftrag' => $baseDir . '/www/widgets/_gen/widget.gen.auftrag.php', + 'WidgetGenauftrag_artikel' => $baseDir . '/www/widgets/_gen/widget.gen.auftrag_artikel.php', + 'WidgetGenauftrag_position' => $baseDir . '/www/widgets/_gen/widget.gen.auftrag_position.php', + 'WidgetGenauftragsannahme' => $baseDir . '/www/widgets/_gen/widget.gen.auftragsannahme.php', + 'WidgetGenbackupserver' => $baseDir . '/www/widgets/_gen/widget.gen.backupserver.php', + 'WidgetGenberichte' => $baseDir . '/www/widgets/_gen/widget.gen.berichte.php', + 'WidgetGenbestellung' => $baseDir . '/www/widgets/_gen/widget.gen.bestellung.php', + 'WidgetGenbestellung_position' => $baseDir . '/www/widgets/_gen/widget.gen.bestellung_position.php', + 'WidgetGenbrief' => $baseDir . '/www/widgets/_gen/widget.gen.brief.php', + 'WidgetGenchargen' => $baseDir . '/www/widgets/_gen/widget.gen.chargen.php', + 'WidgetGencluster' => $baseDir . '/www/widgets/_gen/widget.gen.cluster.php', + 'WidgetGendatei_stichwortvorlagen' => $baseDir . '/www/widgets/_gen/widget.gen.datei_stichwortvorlagen.php', + 'WidgetGendrucker' => $baseDir . '/www/widgets/_gen/widget.gen.drucker.php', + 'WidgetGeneigenschaften' => $baseDir . '/www/widgets/_gen/widget.gen.eigenschaften.php', + 'WidgetGeneinkaufspreise' => $baseDir . '/www/widgets/_gen/widget.gen.einkaufspreise.php', + 'WidgetGenemail' => $baseDir . '/www/widgets/_gen/widget.gen.email.php', + 'WidgetGenemailbackup' => $baseDir . '/www/widgets/_gen/widget.gen.emailbackup.php', + 'WidgetGenetiketten' => $baseDir . '/www/widgets/_gen/widget.gen.etiketten.php', + 'WidgetGenexportvorlage' => $baseDir . '/www/widgets/_gen/widget.gen.exportvorlage.php', + 'WidgetGenfahrtenbuch' => $baseDir . '/www/widgets/_gen/widget.gen.fahrtenbuch.php', + 'WidgetGengeraeteverwaltung' => $baseDir . '/www/widgets/_gen/widget.gen.geraeteverwaltung.php', + 'WidgetGengeschaeftsbrief_vorlagen' => $baseDir . '/www/widgets/_gen/widget.gen.geschaeftsbrief_vorlagen.php', + 'WidgetGengeschaeftsfall' => $baseDir . '/www/widgets/_gen/widget.gen.geschaeftsfall.php', + 'WidgetGengruppen' => $baseDir . '/www/widgets/_gen/widget.gen.gruppen.php', + 'WidgetGengruppen_kategorien' => $baseDir . '/www/widgets/_gen/widget.gen.gruppen_kategorien.php', + 'WidgetGengutschrift' => $baseDir . '/www/widgets/_gen/widget.gen.gutschrift.php', + 'WidgetGengutschrift_position' => $baseDir . '/www/widgets/_gen/widget.gen.gutschrift_position.php', + 'WidgetGenimportvorlage' => $baseDir . '/www/widgets/_gen/widget.gen.importvorlage.php', + 'WidgetGeninhalt' => $baseDir . '/www/widgets/_gen/widget.gen.inhalt.php', + 'WidgetGeninventur' => $baseDir . '/www/widgets/_gen/widget.gen.inventur.php', + 'WidgetGeninventur_position' => $baseDir . '/www/widgets/_gen/widget.gen.inventur_position.php', + 'WidgetGenkalkulation' => $baseDir . '/www/widgets/_gen/widget.gen.kalkulation.php', + 'WidgetGenkalkulation_position' => $baseDir . '/www/widgets/_gen/widget.gen.kalkulation_position.php', + 'WidgetGenkasse' => $baseDir . '/www/widgets/_gen/widget.gen.kasse.php', + 'WidgetGenkontorahmen' => $baseDir . '/www/widgets/_gen/widget.gen.kontorahmen.php', + 'WidgetGenkostenstellen' => $baseDir . '/www/widgets/_gen/widget.gen.kostenstellen.php', + 'WidgetGenkundevorlage' => $baseDir . '/www/widgets/_gen/widget.gen.kundevorlage.php', + 'WidgetGenlager' => $baseDir . '/www/widgets/_gen/widget.gen.lager.php', + 'WidgetGenlieferadressen' => $baseDir . '/www/widgets/_gen/widget.gen.lieferadressen.php', + 'WidgetGenlieferantvorlage' => $baseDir . '/www/widgets/_gen/widget.gen.lieferantvorlage.php', + 'WidgetGenlieferbedingungen' => $baseDir . '/www/widgets/_gen/widget.gen.lieferbedingungen.php', + 'WidgetGenlieferschein' => $baseDir . '/www/widgets/_gen/widget.gen.lieferschein.php', + 'WidgetGenlieferschein_position' => $baseDir . '/www/widgets/_gen/widget.gen.lieferschein_position.php', + 'WidgetGenpartner' => $baseDir . '/www/widgets/_gen/widget.gen.partner.php', + 'WidgetGenpos_kassierer' => $baseDir . '/www/widgets/_gen/widget.gen.pos_kassierer.php', + 'WidgetGenpreisanfrage' => $baseDir . '/www/widgets/_gen/widget.gen.preisanfrage.php', + 'WidgetGenpreisanfrage_position' => $baseDir . '/www/widgets/_gen/widget.gen.preisanfrage_position.php', + 'WidgetGenproduktion' => $baseDir . '/www/widgets/_gen/widget.gen.produktion.php', + 'WidgetGenproduktion_position' => $baseDir . '/www/widgets/_gen/widget.gen.produktion_position.php', + 'WidgetGenproformarechnung' => $baseDir . '/www/widgets/_gen/widget.gen.proformarechnung.php', + 'WidgetGenproformarechnung_position' => $baseDir . '/www/widgets/_gen/widget.gen.proformarechnung_position.php', + 'WidgetGenprojekt' => $baseDir . '/www/widgets/_gen/widget.gen.projekt.php', + 'WidgetGenprozessstarter' => $baseDir . '/www/widgets/_gen/widget.gen.prozessstarter.php', + 'WidgetGenrechnung' => $baseDir . '/www/widgets/_gen/widget.gen.rechnung.php', + 'WidgetGenrechnung_position' => $baseDir . '/www/widgets/_gen/widget.gen.rechnung_position.php', + 'WidgetGenreisekosten' => $baseDir . '/www/widgets/_gen/widget.gen.reisekosten.php', + 'WidgetGenreisekosten_position' => $baseDir . '/www/widgets/_gen/widget.gen.reisekosten_position.php', + 'WidgetGenreisekosten_positionen' => $baseDir . '/www/widgets/_gen/widget.gen.reisekosten_positionen.php', + 'WidgetGenreisekostenart' => $baseDir . '/www/widgets/_gen/widget.gen.reisekostenart.php', + 'WidgetGenremotezugang' => $baseDir . '/www/widgets/_gen/widget.gen.remotezugang.php', + 'WidgetGenretoure' => $baseDir . '/www/widgets/_gen/widget.gen.retoure.php', + 'WidgetGenretoure_position' => $baseDir . '/www/widgets/_gen/widget.gen.retoure_position.php', + 'WidgetGenrohstoffe' => $baseDir . '/www/widgets/_gen/widget.gen.rohstoffe.php', + 'WidgetGenseriennummern' => $baseDir . '/www/widgets/_gen/widget.gen.seriennummern.php', + 'WidgetGenservice' => $baseDir . '/www/widgets/_gen/widget.gen.service.php', + 'WidgetGenshopexport' => $baseDir . '/www/widgets/_gen/widget.gen.shopexport.php', + 'WidgetGenshopexport_kampange' => $baseDir . '/www/widgets/_gen/widget.gen.shopexport_kampange.php', + 'WidgetGenspedition' => $baseDir . '/www/widgets/_gen/widget.gen.spedition.php', + 'WidgetGenspedition_avi' => $baseDir . '/www/widgets/_gen/widget.gen.spedition_avi.php', + 'WidgetGenstation' => $baseDir . '/www/widgets/_gen/widget.gen.station.php', + 'WidgetGenstueckliste' => $baseDir . '/www/widgets/_gen/widget.gen.stueckliste.php', + 'WidgetGensupportapp' => $baseDir . '/www/widgets/_gen/widget.gen.supportapp.php', + 'WidgetGenterminals' => $baseDir . '/www/widgets/_gen/widget.gen.terminals.php', + 'WidgetGenticket' => $baseDir . '/www/widgets/_gen/widget.gen.ticket.php', + 'WidgetGenticket_vorlage' => $baseDir . '/www/widgets/_gen/widget.gen.ticket_vorlage.php', + 'WidgetGenuebersetzung' => $baseDir . '/www/widgets/_gen/widget.gen.uebersetzung.php', + 'WidgetGenuser' => $baseDir . '/www/widgets/_gen/widget.gen.user.php', + 'WidgetGenuservorlage' => $baseDir . '/www/widgets/_gen/widget.gen.uservorlage.php', + 'WidgetGenverbindlichkeit' => $baseDir . '/www/widgets/_gen/widget.gen.verbindlichkeit.php', + 'WidgetGenverbindlichkeit_position' => $baseDir . '/www/widgets/_gen/widget.gen.verbindlichkeit_position.php', + 'WidgetGenverkaufspreise' => $baseDir . '/www/widgets/_gen/widget.gen.verkaufspreise.php', + 'WidgetGenverrechnungsart' => $baseDir . '/www/widgets/_gen/widget.gen.verrechnungsart.php', + 'WidgetGenversandarten' => $baseDir . '/www/widgets/_gen/widget.gen.versandarten.php', + 'WidgetGenvorlage' => $baseDir . '/www/widgets/_gen/widget.gen.vorlage.php', + 'WidgetGenwaage_artikel' => $baseDir . '/www/widgets/_gen/widget.gen.waage_artikel.php', + 'WidgetGenwarteschlangen' => $baseDir . '/www/widgets/_gen/widget.gen.warteschlangen.php', + 'WidgetGenwawisioneinrichtung' => $baseDir . '/www/widgets/_gen/widget.gen.wawisioneinrichtung.php', + 'WidgetGenwebmail' => $baseDir . '/www/widgets/_gen/widget.gen.webmail.php', + 'WidgetGenwebmail_mails' => $baseDir . '/www/widgets/_gen/widget.gen.webmail_mails.php', + 'WidgetGenwebmail_zuordnung' => $baseDir . '/www/widgets/_gen/widget.gen.webmail_zuordnung.php', + 'WidgetGenwiedervorlage' => $baseDir . '/www/widgets/_gen/widget.gen.wiedervorlage.php', + 'WidgetGenwissensdatenbank' => $baseDir . '/www/widgets/_gen/widget.gen.wissensdatenbank.php', + 'WidgetGenzahlungsweisen' => $baseDir . '/www/widgets/_gen/widget.gen.zahlungsweisen.php', + 'WidgetGenzeiterfassungvorlage' => $baseDir . '/www/widgets/_gen/widget.gen.zeiterfassungvorlage.php', + 'WidgetGenzolltarifnummer' => $baseDir . '/www/widgets/_gen/widget.gen.zolltarifnummer.php', + 'WidgetGenzugangstoken' => $baseDir . '/www/widgets/_gen/widget.gen.zugangstoken.php', + 'WidgetGeschaeftsbrief_vorlagen' => $baseDir . '/www/widgets/widget.geschaeftsbrief_vorlagen.php', + 'WidgetGutschrift' => $baseDir . '/www/widgets/widget.gutschrift.php', + 'WidgetGutschrift_position' => $baseDir . '/www/widgets/widget.gutschrift_position.php', + 'WidgetImportvorlage' => $baseDir . '/www/widgets/widget.importvorlage.php', + 'WidgetInhalt' => $baseDir . '/www/widgets/widget.inhalt.php', + 'WidgetInventur' => $baseDir . '/www/widgets/widget.inventur.php', + 'WidgetInventur_position' => $baseDir . '/www/widgets/widget.inventur_position.php', + 'WidgetKalkulation' => $baseDir . '/www/widgets/widget.kalkulation.php', + 'WidgetKalkulation_position' => $baseDir . '/www/widgets/widget.kalkulation_position.php', + 'WidgetKostenstellen' => $baseDir . '/www/widgets/widget.kostenstellen.php', + 'WidgetKundevorlage' => $baseDir . '/www/widgets/widget.kundevorlage.php', + 'WidgetLager' => $baseDir . '/www/widgets/widget.lager.php', + 'WidgetLieferadressen' => $baseDir . '/www/widgets/widget.lieferadressen.php', + 'WidgetLieferantvorlage' => $baseDir . '/www/widgets/widget.lieferantvorlage.php', + 'WidgetLieferschein' => $baseDir . '/www/widgets/widget.lieferschein.php', + 'WidgetLieferschein_position' => $baseDir . '/www/widgets/widget.lieferschein_position.php', + 'WidgetPreisanfrage' => $baseDir . '/www/widgets/widget.preisanfrage.php', + 'WidgetPreisanfrage_position' => $baseDir . '/www/widgets/widget.preisanfrage_position.php', + 'WidgetProformarechnung' => $baseDir . '/www/widgets/widget.proformarechnung.php', + 'WidgetProformarechnung_position' => $baseDir . '/www/widgets/widget.proformarechnung_position.php', + 'WidgetProjekt' => $baseDir . '/www/widgets/widget.projekt.php', + 'WidgetProzessstarter' => $baseDir . '/www/widgets/widget.prozessstarter.php', + 'WidgetRechnung' => $baseDir . '/www/widgets/widget.rechnung.php', + 'WidgetRechnung_position' => $baseDir . '/www/widgets/widget.rechnung_position.php', + 'WidgetReisekosten' => $baseDir . '/www/widgets/widget.reisekosten.php', + 'WidgetReisekosten_position' => $baseDir . '/www/widgets/widget.reisekosten_position.php', + 'WidgetReisekostenart' => $baseDir . '/www/widgets/widget.reisekostenart.php', + 'WidgetRetoure' => $baseDir . '/www/widgets/widget.retoure.php', + 'WidgetRetoure_position' => $baseDir . '/www/widgets/widget.retoure_position.php', + 'WidgetRohstoffe' => $baseDir . '/www/widgets/widget.rohstoffe.php', + 'WidgetShopexport' => $baseDir . '/www/widgets/widget.shopexport.php', + 'WidgetShopexport_kampange' => $baseDir . '/www/widgets/widget.shopexport_kampange.php', + 'WidgetStueckliste' => $baseDir . '/www/widgets/widget.stueckliste.php', + 'WidgetUebersetzung' => $baseDir . '/www/widgets/widget.uebersetzung.php', + 'WidgetUser' => $baseDir . '/www/widgets/widget.user.php', + 'WidgetUservorlage' => $baseDir . '/www/widgets/widget.uservorlage.php', + 'WidgetVerbindlichkeit' => $baseDir . '/www/widgets/widget.verbindlichkeit.php', + 'WidgetVerbindlichkeit_position' => $baseDir . '/www/widgets/widget.verbindlichkeit_position.php', + 'WidgetVerkaufspreise' => $baseDir . '/www/widgets/widget.verkaufspreise.php', + 'WidgetVerrechnungsart' => $baseDir . '/www/widgets/widget.verrechnungsart.php', + 'WidgetVersandarten' => $baseDir . '/www/widgets/widget.versandarten.php', + 'WidgetVorlage' => $baseDir . '/www/widgets/widget.vorlage.php', + 'WidgetWawisioneinrichtung' => $baseDir . '/www/widgets/widget.wawisioneinrichtung.php', + 'WidgetWebmail_mails' => $baseDir . '/www/widgets/widget.webmail_mails.php', + 'WidgetWiedervorlage' => $baseDir . '/www/widgets/widget.wiedervorlage.php', + 'WidgetWissensdatenbank' => $baseDir . '/www/widgets/widget.wissensdatenbank.php', + 'WidgetZahlungsweisen' => $baseDir . '/www/widgets/widget.zahlungsweisen.php', + 'WidgetZeiterfassungvorlage' => $baseDir . '/www/widgets/widget.zeiterfassungvorlage.php', + 'WidgetZolltarifnummer' => $baseDir . '/www/widgets/widget.zolltarifnummer.php', + 'Widgetgruppen' => $baseDir . '/www/widgets/widget.gruppen.php', + 'Widgetgruppen_kategorien' => $baseDir . '/www/widgets/widget.gruppen_kategorien.php', + 'WikiParser' => $baseDir . '/www/plugins/class.wikiparser.php', + 'XTEA' => $baseDir . '/www/lib/class.xtea.php', 'Xentral\\Carrier\\Dhl\\Data\\Bank' => $baseDir . '/classes/Carrier/Dhl/Data/Bank.php', 'Xentral\\Carrier\\Dhl\\Data\\Communication' => $baseDir . '/classes/Carrier/Dhl/Data/Communication.php', 'Xentral\\Carrier\\Dhl\\Data\\Contact' => $baseDir . '/classes/Carrier/Dhl/Data/Contact.php', @@ -2514,8 +2796,6 @@ 'Xentral\\Components\\Mailer\\Transport\\PhpMailerOAuth' => $baseDir . '/classes/Components/Mailer/Transport/PhpMailerOAuth.php', 'Xentral\\Components\\Mailer\\Transport\\PhpMailerOAuthAuthentificationInterface' => $baseDir . '/classes/Components/Mailer/Transport/PhpMailerOAuthAuthentificationInterface.php', 'Xentral\\Components\\Mailer\\Transport\\PhpMailerTransport' => $baseDir . '/classes/Components/Mailer/Transport/PhpMailerTransport.php', - 'Xentral\\Components\\Mailer\\Wrapper\\LoggerWrapper' => $baseDir . '/classes/Components/Mailer/Wrapper/LoggerWrapper.php', - 'Xentral\\Components\\Mailer\\Wrapper\\MemoryLogger' => $baseDir . '/classes/Components/Mailer/Wrapper/MemoryLogger.php', 'Xentral\\Components\\Pdf\\Bootstrap' => $baseDir . '/classes/Components/Pdf/Bootstrap.php', 'Xentral\\Components\\Pdf\\Exception\\FileExistsException' => $baseDir . '/classes/Components/Pdf/Exception/FileExistsException.php', 'Xentral\\Components\\Pdf\\Exception\\FileNotFoundException' => $baseDir . '/classes/Components/Pdf/Exception/FileNotFoundException.php', @@ -3028,15 +3308,6 @@ 'Xentral\\Modules\\Ebay\\Service\\EbayStockLoggingService' => $baseDir . '/classes/Modules/Ebay/Service/EbayStockLoggingService.php', 'Xentral\\Modules\\Ebay\\Wrapper\\EbayStockCalculationWrapperInterface' => $baseDir . '/classes/Modules/Ebay/Wrapper/EbayStockCalculationWrapperInterface.php', 'Xentral\\Modules\\Ebay\\Wrapper\\StockCalculationWrapper' => $baseDir . '/classes/Modules/Ebay/Wrapper/StockCalculationWrapper.php', - 'Xentral\\Modules\\EtsyApi\\Credential\\AbstractCredentialData' => $baseDir . '/classes/Modules/EtsyApi/Credential/AbstractCredentialData.php', - 'Xentral\\Modules\\EtsyApi\\Credential\\ClientCredentialData' => $baseDir . '/classes/Modules/EtsyApi/Credential/ClientCredentialData.php', - 'Xentral\\Modules\\EtsyApi\\Credential\\CredentialDataInterface' => $baseDir . '/classes/Modules/EtsyApi/Credential/CredentialDataInterface.php', - 'Xentral\\Modules\\EtsyApi\\Credential\\TemporaryCredentialData' => $baseDir . '/classes/Modules/EtsyApi/Credential/TemporaryCredentialData.php', - 'Xentral\\Modules\\EtsyApi\\Credential\\TokenCredentialData' => $baseDir . '/classes/Modules/EtsyApi/Credential/TokenCredentialData.php', - 'Xentral\\Modules\\EtsyApi\\EtsyOAuthHelper' => $baseDir . '/classes/Modules/EtsyApi/EtsyOAuthHelper.php', - 'Xentral\\Modules\\EtsyApi\\Exception\\CredentialException' => $baseDir . '/classes/Modules/EtsyApi/Exception/CredentialException.php', - 'Xentral\\Modules\\EtsyApi\\Exception\\EtsyApiExceptionInterface' => $baseDir . '/classes/Modules/EtsyApi/Exception/EtsyApiExceptionInterface.php', - 'Xentral\\Modules\\EtsyApi\\Exception\\EtsyOAuthException' => $baseDir . '/classes/Modules/EtsyApi/Exception/EtsyOAuthException.php', 'Xentral\\Modules\\FeeReduction\\Bootstrap' => $baseDir . '/classes/Modules/FeeReduction/Bootstrap.php', 'Xentral\\Modules\\FeeReduction\\Exception\\FeeReductionExceptionInterface' => $baseDir . '/classes/Modules/FeeReduction/Exception/FeeReductionExceptionInterface.php', 'Xentral\\Modules\\FeeReduction\\Exception\\InvalidArgumentException' => $baseDir . '/classes/Modules/FeeReduction/Exception/InvalidArgumentException.php', @@ -3291,7 +3562,6 @@ 'Xentral\\Modules\\Log\\Service\\DatabaseLogGateway' => $baseDir . '/classes/Modules/Log/Service/DatabaseLogGateway.php', 'Xentral\\Modules\\Log\\Service\\DatabaseLogService' => $baseDir . '/classes/Modules/Log/Service/DatabaseLogService.php', 'Xentral\\Modules\\Log\\Service\\LoggerConfigService' => $baseDir . '/classes/Modules/Log/Service/LoggerConfigService.php', - 'Xentral\\Modules\\Log\\Wrapper\\CompanyConfigWrapper' => $baseDir . '/classes/Modules/Log/Wrapper/CompanyConfigWrapper.php', 'Xentral\\Modules\\MandatoryFields\\Bootstrap' => $baseDir . '/classes/Modules/MandatoryFields/Bootstrap.php', 'Xentral\\Modules\\MandatoryFields\\Data\\MandatoryFieldData' => $baseDir . '/classes/Modules/MandatoryFields/Data/MandatoryFieldData.php', 'Xentral\\Modules\\MandatoryFields\\Data\\ValidatorResultData' => $baseDir . '/classes/Modules/MandatoryFields/Data/ValidatorResultData.php', @@ -3807,8 +4077,12 @@ 'Xentral\\Widgets\\SuperSearch\\Result\\ResultDetail' => $baseDir . '/classes/Widgets/SuperSearch/Result/ResultDetail.php', 'Xentral\\Widgets\\SuperSearch\\Result\\ResultGroup' => $baseDir . '/classes/Widgets/SuperSearch/Result/ResultGroup.php', 'Xentral\\Widgets\\SuperSearch\\Result\\ResultItem' => $baseDir . '/classes/Widgets/SuperSearch/Result/ResultItem.php', - 'Y0lk\\OAuth1\\Client\\Server\\Etsy' => $vendorDir . '/y0lk/oauth1-etsy/src/Etsy.php', + 'YUI' => $baseDir . '/phpwf/plugins/class.yui.php', + 'erpAPI' => $baseDir . '/www/lib/class.erpapi.php', + 'erpooSystem' => $baseDir . '/www/eproosystem.php', + 'image' => $baseDir . '/www/lib/class.image.php', 'lfkeitel\\phptotp\\Base32' => $vendorDir . '/lfkeitel/phptotp/src/Base32.php', 'lfkeitel\\phptotp\\Hotp' => $vendorDir . '/lfkeitel/phptotp/src/Hotp.php', 'lfkeitel\\phptotp\\Totp' => $vendorDir . '/lfkeitel/phptotp/src/Totp.php', + 'phpprint' => $baseDir . '/www/plugins/php-print.php', ); diff --git a/vendor/composer/autoload_files.php b/vendor/composer/autoload_files.php index 09f2014a2..cc3b80ec6 100644 --- a/vendor/composer/autoload_files.php +++ b/vendor/composer/autoload_files.php @@ -11,15 +11,15 @@ 'e69f7f6ee287b969198c3c9d6777bd38' => $vendorDir . '/symfony/polyfill-intl-normalizer/bootstrap.php', 'c964ee0ededf28c96ebd9db5099ef910' => $vendorDir . '/guzzlehttp/promises/src/functions_include.php', 'a0edc8309cc5e1d60e3047b5df6b7052' => $vendorDir . '/guzzlehttp/psr7/src/functions_include.php', - 'f598d06aa772fa33d905e87be6398fb1' => $vendorDir . '/symfony/polyfill-intl-idn/bootstrap.php', - '37a3dc5111fe8f707ab4c132ef1dbc62' => $vendorDir . '/guzzlehttp/guzzle/src/functions_include.php', '2b9d0f43f9552984cfa82fee95491826' => $vendorDir . '/sabre/event/lib/coroutine.php', 'd81bab31d3feb45bfe2f283ea3c8fdf7' => $vendorDir . '/sabre/event/lib/Loop/functions.php', 'a1cce3d26cc15c00fcd0b3354bd72c88' => $vendorDir . '/sabre/event/lib/Promise/functions.php', '3569eecfeed3bcf0bad3c998a494ecb8' => $vendorDir . '/sabre/xml/lib/Deserializer/functions.php', '93aa591bc4ca510c520999e34229ee79' => $vendorDir . '/sabre/xml/lib/Serializer/functions.php', + 'f598d06aa772fa33d905e87be6398fb1' => $vendorDir . '/symfony/polyfill-intl-idn/bootstrap.php', '0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => $vendorDir . '/symfony/polyfill-mbstring/bootstrap.php', 'c9d07b32a2e02bc0fc582d4f0c1b56cc' => $vendorDir . '/laminas/laminas-servicemanager/src/autoload.php', + '37a3dc5111fe8f707ab4c132ef1dbc62' => $vendorDir . '/guzzlehttp/guzzle/src/functions_include.php', 'b067bc7112e384b61c701452d53a14a8' => $vendorDir . '/mtdowling/jmespath.php/src/JmesPath.php', 'ebdb698ed4152ae445614b69b5e4bb6a' => $vendorDir . '/sabre/http/lib/functions.php', '8a9dc1de0ca7e01f3e08231539562f61' => $vendorDir . '/aws/aws-sdk-php/src/functions.php', diff --git a/vendor/composer/autoload_psr4.php b/vendor/composer/autoload_psr4.php index aa47ba3c3..aa66e398f 100644 --- a/vendor/composer/autoload_psr4.php +++ b/vendor/composer/autoload_psr4.php @@ -7,7 +7,6 @@ return array( 'lfkeitel\\phptotp\\' => array($vendorDir . '/lfkeitel/phptotp/src'), - 'Y0lk\\OAuth1\\Client\\Server\\' => array($vendorDir . '/y0lk/oauth1-etsy/src'), 'Xentral\\' => array($baseDir . '/classes'), 'Webmozart\\Assert\\' => array($vendorDir . '/webmozart/assert/src'), 'Symfony\\Polyfill\\Mbstring\\' => array($vendorDir . '/symfony/polyfill-mbstring'), @@ -30,7 +29,6 @@ 'Psr\\Http\\Message\\' => array($vendorDir . '/psr/http-message/src'), 'Psr\\Container\\' => array($vendorDir . '/psr/container/src'), 'PHPMailer\\PHPMailer\\' => array($vendorDir . '/phpmailer/phpmailer/src'), - 'League\\OAuth1\\Client\\' => array($vendorDir . '/league/oauth1-client/src'), 'League\\MimeTypeDetection\\' => array($vendorDir . '/league/mime-type-detection/src'), 'League\\Flysystem\\' => array($vendorDir . '/league/flysystem/src'), 'Laminas\\Validator\\' => array($vendorDir . '/laminas/laminas-validator/src'), diff --git a/vendor/composer/autoload_real.php b/vendor/composer/autoload_real.php index adb873a96..00d985aef 100644 --- a/vendor/composer/autoload_real.php +++ b/vendor/composer/autoload_real.php @@ -2,7 +2,7 @@ // autoload_real.php @generated by Composer -class ComposerAutoloaderInit0c49a81c1214ef2f7493c6ce921b17ee +class ComposerAutoloaderInit79eff8c373a8f453cf73098a3a8ce631 { private static $loader; @@ -24,16 +24,16 @@ public static function getLoader() require __DIR__ . '/platform_check.php'; - spl_autoload_register(array('ComposerAutoloaderInit0c49a81c1214ef2f7493c6ce921b17ee', 'loadClassLoader'), true, true); + spl_autoload_register(array('ComposerAutoloaderInit79eff8c373a8f453cf73098a3a8ce631', 'loadClassLoader'), true, true); self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(__DIR__)); - spl_autoload_unregister(array('ComposerAutoloaderInit0c49a81c1214ef2f7493c6ce921b17ee', 'loadClassLoader')); + spl_autoload_unregister(array('ComposerAutoloaderInit79eff8c373a8f453cf73098a3a8ce631', 'loadClassLoader')); require __DIR__ . '/autoload_static.php'; - call_user_func(\Composer\Autoload\ComposerStaticInit0c49a81c1214ef2f7493c6ce921b17ee::getInitializer($loader)); + call_user_func(\Composer\Autoload\ComposerStaticInit79eff8c373a8f453cf73098a3a8ce631::getInitializer($loader)); $loader->register(true); - $filesToLoad = \Composer\Autoload\ComposerStaticInit0c49a81c1214ef2f7493c6ce921b17ee::$files; + $filesToLoad = \Composer\Autoload\ComposerStaticInit79eff8c373a8f453cf73098a3a8ce631::$files; $requireFile = \Closure::bind(static function ($fileIdentifier, $file) { if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) { $GLOBALS['__composer_autoload_files'][$fileIdentifier] = true; diff --git a/vendor/composer/autoload_static.php b/vendor/composer/autoload_static.php index 449b91726..6a3f72664 100644 --- a/vendor/composer/autoload_static.php +++ b/vendor/composer/autoload_static.php @@ -4,7 +4,7 @@ namespace Composer\Autoload; -class ComposerStaticInit0c49a81c1214ef2f7493c6ce921b17ee +class ComposerStaticInit79eff8c373a8f453cf73098a3a8ce631 { public static $files = array ( '383eaff206634a77a1be54e64e6459c7' => __DIR__ . '/..' . '/sabre/uri/lib/functions.php', @@ -12,15 +12,15 @@ class ComposerStaticInit0c49a81c1214ef2f7493c6ce921b17ee 'e69f7f6ee287b969198c3c9d6777bd38' => __DIR__ . '/..' . '/symfony/polyfill-intl-normalizer/bootstrap.php', 'c964ee0ededf28c96ebd9db5099ef910' => __DIR__ . '/..' . '/guzzlehttp/promises/src/functions_include.php', 'a0edc8309cc5e1d60e3047b5df6b7052' => __DIR__ . '/..' . '/guzzlehttp/psr7/src/functions_include.php', - 'f598d06aa772fa33d905e87be6398fb1' => __DIR__ . '/..' . '/symfony/polyfill-intl-idn/bootstrap.php', - '37a3dc5111fe8f707ab4c132ef1dbc62' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/functions_include.php', '2b9d0f43f9552984cfa82fee95491826' => __DIR__ . '/..' . '/sabre/event/lib/coroutine.php', 'd81bab31d3feb45bfe2f283ea3c8fdf7' => __DIR__ . '/..' . '/sabre/event/lib/Loop/functions.php', 'a1cce3d26cc15c00fcd0b3354bd72c88' => __DIR__ . '/..' . '/sabre/event/lib/Promise/functions.php', '3569eecfeed3bcf0bad3c998a494ecb8' => __DIR__ . '/..' . '/sabre/xml/lib/Deserializer/functions.php', '93aa591bc4ca510c520999e34229ee79' => __DIR__ . '/..' . '/sabre/xml/lib/Serializer/functions.php', + 'f598d06aa772fa33d905e87be6398fb1' => __DIR__ . '/..' . '/symfony/polyfill-intl-idn/bootstrap.php', '0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => __DIR__ . '/..' . '/symfony/polyfill-mbstring/bootstrap.php', 'c9d07b32a2e02bc0fc582d4f0c1b56cc' => __DIR__ . '/..' . '/laminas/laminas-servicemanager/src/autoload.php', + '37a3dc5111fe8f707ab4c132ef1dbc62' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/functions_include.php', 'b067bc7112e384b61c701452d53a14a8' => __DIR__ . '/..' . '/mtdowling/jmespath.php/src/JmesPath.php', 'ebdb698ed4152ae445614b69b5e4bb6a' => __DIR__ . '/..' . '/sabre/http/lib/functions.php', '8a9dc1de0ca7e01f3e08231539562f61' => __DIR__ . '/..' . '/aws/aws-sdk-php/src/functions.php', @@ -33,10 +33,6 @@ class ComposerStaticInit0c49a81c1214ef2f7493c6ce921b17ee array ( 'lfkeitel\\phptotp\\' => 17, ), - 'Y' => - array ( - 'Y0lk\\OAuth1\\Client\\Server\\' => 26, - ), 'X' => array ( 'Xentral\\' => 8, @@ -76,7 +72,6 @@ class ComposerStaticInit0c49a81c1214ef2f7493c6ce921b17ee ), 'L' => array ( - 'League\\OAuth1\\Client\\' => 21, 'League\\MimeTypeDetection\\' => 25, 'League\\Flysystem\\' => 17, 'Laminas\\Validator\\' => 18, @@ -119,10 +114,6 @@ class ComposerStaticInit0c49a81c1214ef2f7493c6ce921b17ee array ( 0 => __DIR__ . '/..' . '/lfkeitel/phptotp/src', ), - 'Y0lk\\OAuth1\\Client\\Server\\' => - array ( - 0 => __DIR__ . '/..' . '/y0lk/oauth1-etsy/src', - ), 'Xentral\\' => array ( 0 => __DIR__ . '/../..' . '/classes', @@ -211,10 +202,6 @@ class ComposerStaticInit0c49a81c1214ef2f7493c6ce921b17ee array ( 0 => __DIR__ . '/..' . '/phpmailer/phpmailer/src', ), - 'League\\OAuth1\\Client\\' => - array ( - 0 => __DIR__ . '/..' . '/league/oauth1-client/src', - ), 'League\\MimeTypeDetection\\' => array ( 0 => __DIR__ . '/..' . '/league/mime-type-detection/src', @@ -308,6 +295,17 @@ class ComposerStaticInit0c49a81c1214ef2f7493c6ce921b17ee ); public static $classMap = array ( + 'AES' => __DIR__ . '/../..' . '/www/lib/class.aes2.php', + 'Acl' => __DIR__ . '/../..' . '/phpwf/plugins/class.acl.php', + 'AdressstammblattPDF' => __DIR__ . '/../..' . '/www/lib/dokumente/class.adressstammblatt.php', + 'AnfragePDF' => __DIR__ . '/../..' . '/www/lib/dokumente/class.anfrage.php', + 'AngebotPDF' => __DIR__ . '/../..' . '/www/lib/dokumente/class.angebot.php', + 'Application' => __DIR__ . '/../..' . '/phpwf/class.application.php', + 'ApplicationCore' => __DIR__ . '/../..' . '/phpwf/class.application_core.php', + 'ArbeitsnachweisPDF' => __DIR__ . '/../..' . '/www/lib/dokumente/class.arbeitsnachweis.php', + 'ArbeitszeitnachweisPDF' => __DIR__ . '/../..' . '/www/lib/dokumente/class.arbeitszeitnachweis.php', + 'ArtikelTabelle' => __DIR__ . '/../..' . '/www/widgets/artikeltable.php', + 'AuftragPDF' => __DIR__ . '/../..' . '/www/lib/dokumente/class.auftrag.php', 'Aura\\SqlQuery\\AbstractDmlQuery' => __DIR__ . '/..' . '/aura/sqlquery/src/AbstractDmlQuery.php', 'Aura\\SqlQuery\\AbstractQuery' => __DIR__ . '/..' . '/aura/sqlquery/src/AbstractQuery.php', 'Aura\\SqlQuery\\Common\\Delete' => __DIR__ . '/..' . '/aura/sqlquery/src/Common/Delete.php', @@ -1114,7 +1112,16 @@ class ComposerStaticInit0c49a81c1214ef2f7493c6ce921b17ee 'Aws\\kendra\\kendraClient' => __DIR__ . '/..' . '/aws/aws-sdk-php/src/kendra/kendraClient.php', 'Aws\\signer\\Exception\\signerException' => __DIR__ . '/..' . '/aws/aws-sdk-php/src/signer/Exception/signerException.php', 'Aws\\signer\\signerClient' => __DIR__ . '/..' . '/aws/aws-sdk-php/src/signer/signerClient.php', + 'BestellungPDF' => __DIR__ . '/../..' . '/www/lib/dokumente/class.bestellung.php', + 'BlindField' => __DIR__ . '/../..' . '/phpwf/htmltags/class.form.php', + 'BriefPDF' => __DIR__ . '/../..' . '/www/lib/dokumente/class.brief.php', + 'Briefpapier' => __DIR__ . '/../..' . '/www/lib/dokumente/class.briefpapier.php', + 'BriefpapierCustom' => __DIR__ . '/../..' . '/www/lib/dokumente/class.briefpapier_custom.php', + 'CallbackEntry' => __DIR__ . '/../..' . '/phpwf/plugins/class.formhandler.php', + 'Chart' => __DIR__ . '/../..' . '/phpwf/widgets/chart.php', 'Composer\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php', + 'Config' => __DIR__ . '/../..' . '/conf/main.conf.php', + 'DB' => __DIR__ . '/../..' . '/phpwf/plugins/class.mysql.php', 'Datamatrix' => __DIR__ . '/..' . '/tecnickcom/tcpdf/include/barcodes/datamatrix.php', 'Datto\\JsonRpc\\Client' => __DIR__ . '/..' . '/datto/json-rpc/src/Client.php', 'Datto\\JsonRpc\\Evaluator' => __DIR__ . '/..' . '/datto/json-rpc/src/Evaluator.php', @@ -1134,6 +1141,18 @@ class ComposerStaticInit0c49a81c1214ef2f7493c6ce921b17ee 'Datto\\JsonRpc\\Responses\\Response' => __DIR__ . '/..' . '/datto/json-rpc/src/Responses/Response.php', 'Datto\\JsonRpc\\Responses\\ResultResponse' => __DIR__ . '/..' . '/datto/json-rpc/src/Responses/ResultResponse.php', 'Datto\\JsonRpc\\Server' => __DIR__ . '/..' . '/datto/json-rpc/src/Server.php', + 'DocscanAuth' => __DIR__ . '/../..' . '/www/docscan/classes/DocscanAuth.php', + 'DocscanDir' => __DIR__ . '/../..' . '/www/docscan/classes/DocscanDir.php', + 'DocscanFile' => __DIR__ . '/../..' . '/www/docscan/classes/DocscanFile.php', + 'DocscanRoot' => __DIR__ . '/../..' . '/www/docscan/classes/DocscanRoot.php', + 'DokuArbeitszeit' => __DIR__ . '/../..' . '/www/lib/dokumente/class.dokuarbeitszeit.php', + 'Dokumentenvorlage' => __DIR__ . '/../..' . '/www/lib/dokumente/class.dokumentenvorlage.php', + 'DownloadSpoolerTable' => __DIR__ . '/../..' . '/phpwf/widgets/downloadspoolertable.php', + 'EasyCalendar' => __DIR__ . '/../..' . '/phpwf/widgets/easycalendar.php', + 'EasyTable' => __DIR__ . '/../..' . '/phpwf/widgets/easytable.php', + 'Etikett' => __DIR__ . '/../..' . '/www/lib/dokumente/class.etikett.php', + 'EtikettenPDF' => __DIR__ . '/../..' . '/www/lib/dokumente/class.etiketten.php', + 'FPDFWAWISION' => __DIR__ . '/../..' . '/www/lib/pdf/fpdf_3.php', 'FastRoute\\BadRouteException' => __DIR__ . '/..' . '/nikic/fast-route/src/BadRouteException.php', 'FastRoute\\DataGenerator' => __DIR__ . '/..' . '/nikic/fast-route/src/DataGenerator.php', 'FastRoute\\DataGenerator\\CharCountBased' => __DIR__ . '/..' . '/nikic/fast-route/src/DataGenerator/CharCountBased.php', @@ -1151,6 +1170,7 @@ class ComposerStaticInit0c49a81c1214ef2f7493c6ce921b17ee 'FastRoute\\RouteCollector' => __DIR__ . '/..' . '/nikic/fast-route/src/RouteCollector.php', 'FastRoute\\RouteParser' => __DIR__ . '/..' . '/nikic/fast-route/src/RouteParser.php', 'FastRoute\\RouteParser\\Std' => __DIR__ . '/..' . '/nikic/fast-route/src/RouteParser/Std.php', + 'FileTable' => __DIR__ . '/../..' . '/phpwf/widgets/filetable.php', 'FiskalyClient\\FiskalyClient' => __DIR__ . '/..' . '/fiskaly/fiskaly-sdk-php/src/FiskalyClient.php', 'FiskalyClient\\errors\\FiskalyErrorHandler' => __DIR__ . '/..' . '/fiskaly/fiskaly-sdk-php/src/errors/FiskalyErrorHandler.php', 'FiskalyClient\\errors\\exceptions\\FiskalyClientException' => __DIR__ . '/..' . '/fiskaly/fiskaly-sdk-php/src/errors/exceptions/FiskalyClientException.php', @@ -1161,6 +1181,12 @@ class ComposerStaticInit0c49a81c1214ef2f7493c6ce921b17ee 'FiskalyClient\\responses\\RequestResponse' => __DIR__ . '/..' . '/fiskaly/fiskaly-sdk-php/src/responses/RequestResponse.php', 'FiskalyClient\\responses\\SelfTestResponse' => __DIR__ . '/..' . '/fiskaly/fiskaly-sdk-php/src/responses/SelfTestResponse.php', 'FiskalyClient\\responses\\VersionResponse' => __DIR__ . '/..' . '/fiskaly/fiskaly-sdk-php/src/responses/VersionResponse.php', + 'FormActionHandler' => __DIR__ . '/../..' . '/phpwf/plugins/class.formhandler.php', + 'FormHandler' => __DIR__ . '/../..' . '/phpwf/plugins/class.formhandler.php', + 'FormHandlerField' => __DIR__ . '/../..' . '/phpwf/plugins/class.formhandler.php', + 'Geschaeftsbrief' => __DIR__ . '/../..' . '/www/lib/dokumente/class.geschaeftsbrief.php', + 'GroupTable' => __DIR__ . '/../..' . '/phpwf/widgets/grouptable.php', + 'GutschriftPDF' => __DIR__ . '/../..' . '/www/lib/dokumente/class.gutschrift.php', 'GuzzleHttp\\Client' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/Client.php', 'GuzzleHttp\\ClientInterface' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/ClientInterface.php', 'GuzzleHttp\\Cookie\\CookieJar' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/Cookie/CookieJar.php', @@ -1242,6 +1268,10 @@ class ComposerStaticInit0c49a81c1214ef2f7493c6ce921b17ee 'GuzzleHttp\\TransferStats' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/TransferStats.php', 'GuzzleHttp\\UriTemplate' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/UriTemplate.php', 'GuzzleHttp\\Utils' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/Utils.php', + 'HTMLCheckbox' => __DIR__ . '/../..' . '/phpwf/htmltags/class.form.php', + 'HTMLForm' => __DIR__ . '/../..' . '/phpwf/htmltags/class.form.php', + 'HTMLInput' => __DIR__ . '/../..' . '/phpwf/htmltags/class.form.php', + 'HTMLListEntry' => __DIR__ . '/../..' . '/phpwf/plugins/class.formhandler.php', 'HTMLPurifier' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier.php', 'HTMLPurifier_Arborize' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/Arborize.php', 'HTMLPurifier_AttrCollections' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/AttrCollections.php', @@ -1472,6 +1502,14 @@ class ComposerStaticInit0c49a81c1214ef2f7493c6ce921b17ee 'HTMLPurifier_VarParser_Flexible' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/VarParser/Flexible.php', 'HTMLPurifier_VarParser_Native' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/VarParser/Native.php', 'HTMLPurifier_Zipper' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/Zipper.php', + 'HTMLSelect' => __DIR__ . '/../..' . '/phpwf/htmltags/class.form.php', + 'HTMLTable' => __DIR__ . '/../..' . '/phpwf/htmltags/class.table.php', + 'HTMLTextarea' => __DIR__ . '/../..' . '/phpwf/htmltags/class.form.php', + 'HttpClient' => __DIR__ . '/../..' . '/www/lib/class.httpclient.php', + 'ICS' => __DIR__ . '/../..' . '/www/plugins/class.ics.php', + 'IMAP' => __DIR__ . '/../..' . '/www/lib/imap.inc.php', + 'ImageManipulator' => __DIR__ . '/../..' . '/www/lib/class.image.php', + 'IndexPoint' => __DIR__ . '/../..' . '/www/plugins/class.wikiparser.php', 'JmesPath\\AstRuntime' => __DIR__ . '/..' . '/mtdowling/jmespath.php/src/AstRuntime.php', 'JmesPath\\CompilerRuntime' => __DIR__ . '/..' . '/mtdowling/jmespath.php/src/CompilerRuntime.php', 'JmesPath\\DebugRuntime' => __DIR__ . '/..' . '/mtdowling/jmespath.php/src/DebugRuntime.php', @@ -1483,6 +1521,11 @@ class ComposerStaticInit0c49a81c1214ef2f7493c6ce921b17ee 'JmesPath\\TreeCompiler' => __DIR__ . '/..' . '/mtdowling/jmespath.php/src/TreeCompiler.php', 'JmesPath\\TreeInterpreter' => __DIR__ . '/..' . '/mtdowling/jmespath.php/src/TreeInterpreter.php', 'JmesPath\\Utils' => __DIR__ . '/..' . '/mtdowling/jmespath.php/src/Utils.php', + 'KalkulationPDF' => __DIR__ . '/../..' . '/www/lib/dokumente/class.kalkulation.php', + 'KatalogPDF' => __DIR__ . '/../..' . '/www/lib/dokumente/class.katalog.php', + 'KommissionierungPDF' => __DIR__ . '/../..' . '/www/lib/dokumente/class.kommissionierung.php', + 'KorrespondenzPDF' => __DIR__ . '/../..' . '/www/lib/dokumente/class.korrespondenz.php', + 'LagermindestmengenPDF' => __DIR__ . '/../..' . '/www/lib/dokumente/class.lagermindestmengen.php', 'Laminas\\Loader\\AutoloaderFactory' => __DIR__ . '/..' . '/laminas/laminas-loader/src/AutoloaderFactory.php', 'Laminas\\Loader\\ClassMapAutoloader' => __DIR__ . '/..' . '/laminas/laminas-loader/src/ClassMapAutoloader.php', 'Laminas\\Loader\\Exception\\BadMethodCallException' => __DIR__ . '/..' . '/laminas/laminas-loader/src/Exception/BadMethodCallException.php', @@ -1807,6 +1850,7 @@ class ComposerStaticInit0c49a81c1214ef2f7493c6ce921b17ee 'Laminas\\Validator\\ValidatorPluginManagerAwareInterface' => __DIR__ . '/..' . '/laminas/laminas-validator/src/ValidatorPluginManagerAwareInterface.php', 'Laminas\\Validator\\ValidatorPluginManagerFactory' => __DIR__ . '/..' . '/laminas/laminas-validator/src/ValidatorPluginManagerFactory.php', 'Laminas\\Validator\\ValidatorProviderInterface' => __DIR__ . '/..' . '/laminas/laminas-validator/src/ValidatorProviderInterface.php', + 'LayoutvorlagenPDF' => __DIR__ . '/../..' . '/www/lib/dokumente/class.layoutvorlagen.php', 'League\\ColorExtractor\\Color' => __DIR__ . '/..' . '/league/color-extractor/src/League/ColorExtractor/Color.php', 'League\\ColorExtractor\\ColorExtractor' => __DIR__ . '/..' . '/league/color-extractor/src/League/ColorExtractor/ColorExtractor.php', 'League\\ColorExtractor\\Palette' => __DIR__ . '/..' . '/league/color-extractor/src/League/ColorExtractor/Palette.php', @@ -1869,36 +1913,32 @@ class ComposerStaticInit0c49a81c1214ef2f7493c6ce921b17ee 'League\\MimeTypeDetection\\GeneratedExtensionToMimeTypeMap' => __DIR__ . '/..' . '/league/mime-type-detection/src/GeneratedExtensionToMimeTypeMap.php', 'League\\MimeTypeDetection\\MimeTypeDetector' => __DIR__ . '/..' . '/league/mime-type-detection/src/MimeTypeDetector.php', 'League\\MimeTypeDetection\\OverridingExtensionToMimeTypeMap' => __DIR__ . '/..' . '/league/mime-type-detection/src/OverridingExtensionToMimeTypeMap.php', - 'League\\OAuth1\\Client\\Credentials\\ClientCredentials' => __DIR__ . '/..' . '/league/oauth1-client/src/Credentials/ClientCredentials.php', - 'League\\OAuth1\\Client\\Credentials\\ClientCredentialsInterface' => __DIR__ . '/..' . '/league/oauth1-client/src/Credentials/ClientCredentialsInterface.php', - 'League\\OAuth1\\Client\\Credentials\\Credentials' => __DIR__ . '/..' . '/league/oauth1-client/src/Credentials/Credentials.php', - 'League\\OAuth1\\Client\\Credentials\\CredentialsException' => __DIR__ . '/..' . '/league/oauth1-client/src/Credentials/CredentialsException.php', - 'League\\OAuth1\\Client\\Credentials\\CredentialsInterface' => __DIR__ . '/..' . '/league/oauth1-client/src/Credentials/CredentialsInterface.php', - 'League\\OAuth1\\Client\\Credentials\\RsaClientCredentials' => __DIR__ . '/..' . '/league/oauth1-client/src/Credentials/RsaClientCredentials.php', - 'League\\OAuth1\\Client\\Credentials\\TemporaryCredentials' => __DIR__ . '/..' . '/league/oauth1-client/src/Credentials/TemporaryCredentials.php', - 'League\\OAuth1\\Client\\Credentials\\TokenCredentials' => __DIR__ . '/..' . '/league/oauth1-client/src/Credentials/TokenCredentials.php', - 'League\\OAuth1\\Client\\Server\\Bitbucket' => __DIR__ . '/..' . '/league/oauth1-client/src/Server/Bitbucket.php', - 'League\\OAuth1\\Client\\Server\\Magento' => __DIR__ . '/..' . '/league/oauth1-client/src/Server/Magento.php', - 'League\\OAuth1\\Client\\Server\\Server' => __DIR__ . '/..' . '/league/oauth1-client/src/Server/Server.php', - 'League\\OAuth1\\Client\\Server\\Trello' => __DIR__ . '/..' . '/league/oauth1-client/src/Server/Trello.php', - 'League\\OAuth1\\Client\\Server\\Tumblr' => __DIR__ . '/..' . '/league/oauth1-client/src/Server/Tumblr.php', - 'League\\OAuth1\\Client\\Server\\Twitter' => __DIR__ . '/..' . '/league/oauth1-client/src/Server/Twitter.php', - 'League\\OAuth1\\Client\\Server\\User' => __DIR__ . '/..' . '/league/oauth1-client/src/Server/User.php', - 'League\\OAuth1\\Client\\Server\\Uservoice' => __DIR__ . '/..' . '/league/oauth1-client/src/Server/Uservoice.php', - 'League\\OAuth1\\Client\\Server\\Xing' => __DIR__ . '/..' . '/league/oauth1-client/src/Server/Xing.php', - 'League\\OAuth1\\Client\\Signature\\EncodesUrl' => __DIR__ . '/..' . '/league/oauth1-client/src/Signature/EncodesUrl.php', - 'League\\OAuth1\\Client\\Signature\\HmacSha1Signature' => __DIR__ . '/..' . '/league/oauth1-client/src/Signature/HmacSha1Signature.php', - 'League\\OAuth1\\Client\\Signature\\PlainTextSignature' => __DIR__ . '/..' . '/league/oauth1-client/src/Signature/PlainTextSignature.php', - 'League\\OAuth1\\Client\\Signature\\RsaSha1Signature' => __DIR__ . '/..' . '/league/oauth1-client/src/Signature/RsaSha1Signature.php', - 'League\\OAuth1\\Client\\Signature\\Signature' => __DIR__ . '/..' . '/league/oauth1-client/src/Signature/Signature.php', - 'League\\OAuth1\\Client\\Signature\\SignatureInterface' => __DIR__ . '/..' . '/league/oauth1-client/src/Signature/SignatureInterface.php', + 'LieferscheinPDF' => __DIR__ . '/../..' . '/www/lib/dokumente/class.lieferschein.php', + 'LiveimportBase' => __DIR__ . '/../..' . '/www/plugins/liveimport/LiveimportBase.php', + 'Location' => __DIR__ . '/../..' . '/www/lib/class.location.php', + 'MahnwesenPDF' => __DIR__ . '/../..' . '/www/lib/dokumente/class.mahnwesen.php', + 'MandatoryEntry' => __DIR__ . '/../..' . '/phpwf/plugins/class.formhandler.php', + 'ModuleScriptCache' => __DIR__ . '/../..' . '/phpwf/plugins/class.modulescriptcache.php', + 'Navigation' => __DIR__ . '/../..' . '/www/lib/class.navigation_edit.php', 'Normalizer' => __DIR__ . '/..' . '/symfony/polyfill-intl-normalizer/Resources/stubs/Normalizer.php', + 'ObjectAPI' => __DIR__ . '/../..' . '/phpwf/plugins/class.objectapi.php', 'PDF417' => __DIR__ . '/..' . '/tecnickcom/tcpdf/include/barcodes/pdf417.php', + 'PDF_EPS' => __DIR__ . '/../..' . '/www/lib/pdf/fpdf_final.php', 'PHPMailer\\PHPMailer\\Exception' => __DIR__ . '/..' . '/phpmailer/phpmailer/src/Exception.php', 'PHPMailer\\PHPMailer\\OAuth' => __DIR__ . '/..' . '/phpmailer/phpmailer/src/OAuth.php', 'PHPMailer\\PHPMailer\\PHPMailer' => __DIR__ . '/..' . '/phpmailer/phpmailer/src/PHPMailer.php', 'PHPMailer\\PHPMailer\\POP3' => __DIR__ . '/..' . '/phpmailer/phpmailer/src/POP3.php', 'PHPMailer\\PHPMailer\\SMTP' => __DIR__ . '/..' . '/phpmailer/phpmailer/src/SMTP.php', + 'Page' => __DIR__ . '/../..' . '/phpwf/plugins/class.page.php', + 'PageBuilder' => __DIR__ . '/../..' . '/phpwf/plugins/class.pagebuilder.php', + 'Player' => __DIR__ . '/../..' . '/phpwf/class.player.php', + 'PreisanfragePDF' => __DIR__ . '/../..' . '/www/lib/dokumente/class.preisanfrage.php', + 'Printer' => __DIR__ . '/../..' . '/www/lib/class.printer.php', + 'PrinterBase' => __DIR__ . '/../..' . '/www/lib/PrinterBase.php', + 'ProduktionPDF' => __DIR__ . '/../..' . '/www/lib/dokumente/class.produktion.php', + 'ProformarechnungPDF' => __DIR__ . '/../..' . '/www/lib/dokumente/class.proformarechnung.php', + 'ProjektPDF' => __DIR__ . '/../..' . '/www/lib/dokumente/class.projekt.php', + 'ProvisionsgutschriftPDF' => __DIR__ . '/../..' . '/www/lib/dokumente/class.provisionsgutschrift.php', 'Psr\\Container\\ContainerExceptionInterface' => __DIR__ . '/..' . '/psr/container/src/ContainerExceptionInterface.php', 'Psr\\Container\\ContainerInterface' => __DIR__ . '/..' . '/psr/container/src/ContainerInterface.php', 'Psr\\Container\\NotFoundExceptionInterface' => __DIR__ . '/..' . '/psr/container/src/NotFoundExceptionInterface.php', @@ -1972,6 +2012,10 @@ class ComposerStaticInit0c49a81c1214ef2f7493c6ce921b17ee 'Rakit\\Validation\\Rules\\Url' => __DIR__ . '/..' . '/rakit/validation/src/Rules/Url.php', 'Rakit\\Validation\\Validation' => __DIR__ . '/..' . '/rakit/validation/src/Validation.php', 'Rakit\\Validation\\Validator' => __DIR__ . '/..' . '/rakit/validation/src/Validator.php', + 'RechnungPDF' => __DIR__ . '/../..' . '/www/lib/dokumente/class.rechnung.php', + 'ReisekostenPDF' => __DIR__ . '/../..' . '/www/lib/dokumente/class.reisekosten.php', + 'Remote' => __DIR__ . '/../..' . '/www/lib/class.remote.php', + 'RetourePDF' => __DIR__ . '/../..' . '/www/lib/dokumente/class.retoure.php', 'Sabre\\CalDAV\\Backend\\AbstractBackend' => __DIR__ . '/..' . '/sabre/dav/lib/CalDAV/Backend/AbstractBackend.php', 'Sabre\\CalDAV\\Backend\\BackendInterface' => __DIR__ . '/..' . '/sabre/dav/lib/CalDAV/Backend/BackendInterface.php', 'Sabre\\CalDAV\\Backend\\NotificationSupport' => __DIR__ . '/..' . '/sabre/dav/lib/CalDAV/Backend/NotificationSupport.php', @@ -2312,6 +2356,11 @@ class ComposerStaticInit0c49a81c1214ef2f7493c6ce921b17ee 'Sabre\\Xml\\Writer' => __DIR__ . '/..' . '/sabre/xml/lib/Writer.php', 'Sabre\\Xml\\XmlDeserializable' => __DIR__ . '/..' . '/sabre/xml/lib/XmlDeserializable.php', 'Sabre\\Xml\\XmlSerializable' => __DIR__ . '/..' . '/sabre/xml/lib/XmlSerializable.php', + 'Secure' => __DIR__ . '/../..' . '/phpwf/plugins/class.secure.php', + 'SepaMandat' => __DIR__ . '/../..' . '/www/lib/dokumente/class.sepamandat.php', + 'Session' => __DIR__ . '/../..' . '/phpwf/class.session.php', + 'ShopimporterBase' => __DIR__ . '/../..' . '/www/lib/ShopimporterBase.php', + 'SimpleList' => __DIR__ . '/../..' . '/phpwf/types/class.simplelist.php', 'Smarty' => __DIR__ . '/..' . '/smarty/smarty/libs/Smarty.class.php', 'SmartyBC' => __DIR__ . '/..' . '/smarty/smarty/libs/SmartyBC.class.php', 'SmartyCompilerException' => __DIR__ . '/..' . '/smarty/smarty/libs/sysplugins/smartycompilerexception.php', @@ -2483,6 +2532,9 @@ class ComposerStaticInit0c49a81c1214ef2f7493c6ce921b17ee 'Smarty_Template_Source' => __DIR__ . '/..' . '/smarty/smarty/libs/sysplugins/smarty_template_source.php', 'Smarty_Undefined_Variable' => __DIR__ . '/..' . '/smarty/smarty/libs/sysplugins/smarty_undefined_variable.php', 'Smarty_Variable' => __DIR__ . '/..' . '/smarty/smarty/libs/sysplugins/smarty_variable.php', + 'SpeditionPDF' => __DIR__ . '/../..' . '/www/lib/dokumente/class.spedition.php', + 'StringCleaner' => __DIR__ . '/../..' . '/phpwf/plugins/class.stringcleaner.php', + 'SuperFPDF' => __DIR__ . '/../..' . '/www/lib/dokumente/class.superfpdf.php', 'SwissPaymentSlip\\SwissPaymentSlipFpdf\\PaymentSlipFpdf' => __DIR__ . '/..' . '/swiss-payment-slip/swiss-payment-slip-fpdf/src/PaymentSlipFpdf.php', 'SwissPaymentSlip\\SwissPaymentSlipPdf\\PaymentSlipPdf' => __DIR__ . '/..' . '/swiss-payment-slip/swiss-payment-slip-pdf/src/PaymentSlipPdf.php', 'SwissPaymentSlip\\SwissPaymentSlip\\Exception\\DisabledDataException' => __DIR__ . '/..' . '/swiss-payment-slip/swiss-payment-slip/src/Exception/DisabledDataException.php', @@ -2510,13 +2562,230 @@ class ComposerStaticInit0c49a81c1214ef2f7493c6ce921b17ee 'TCPDF_STATIC' => __DIR__ . '/..' . '/tecnickcom/tcpdf/include/tcpdf_static.php', 'TPC_yyStackEntry' => __DIR__ . '/..' . '/smarty/smarty/libs/sysplugins/smarty_internal_configfileparser.php', 'TP_yyStackEntry' => __DIR__ . '/..' . '/smarty/smarty/libs/sysplugins/smarty_internal_templateparser.php', + 'TemplateParser' => __DIR__ . '/../..' . '/phpwf/plugins/class.templateparser.php', + 'ThemeTemplate' => __DIR__ . '/../..' . '/phpwf/plugins/class.templateparser.php', + 'TransferBase' => __DIR__ . '/../..' . '/www/lib/TransferBase.php', + 'USTID' => __DIR__ . '/../..' . '/www/lib/class.ustid.php', + 'User' => __DIR__ . '/../..' . '/phpwf/plugins/class.user.php', 'Versandart_dhl' => __DIR__ . '/../..' . '/www/lib/versandarten/dhl.php', 'Versandart_dpddepot' => __DIR__ . '/../..' . '/www/lib/versandarten/dpddepot.php', 'Versandart_go' => __DIR__ . '/../..' . '/www/lib/versandarten/go.php', 'Versandart_sendcloud' => __DIR__ . '/../..' . '/www/lib/versandarten/sendcloud.php', + 'VersandpaketscheinPDF' => __DIR__ . '/../..' . '/www/lib/dokumente/class.versandpaketschein.php', + 'WaWisionOTP' => __DIR__ . '/../..' . '/phpwf/plugins/class.wawision_otp.php', + 'WawiString' => __DIR__ . '/../..' . '/phpwf/plugins/class.string.php', 'Webmozart\\Assert\\Assert' => __DIR__ . '/..' . '/webmozart/assert/src/Assert.php', 'Webmozart\\Assert\\InvalidArgumentException' => __DIR__ . '/..' . '/webmozart/assert/src/InvalidArgumentException.php', 'Webmozart\\Assert\\Mixin' => __DIR__ . '/..' . '/webmozart/assert/src/Mixin.php', + 'WidgetAPI' => __DIR__ . '/../..' . '/phpwf/plugins/class.widgetapi.php', + 'WidgetAbrechnungsartikel' => __DIR__ . '/../..' . '/www/widgets/widget.abrechnungsartikel.php', + 'WidgetAdapterbox' => __DIR__ . '/../..' . '/www/widgets/widget.adapterbox.php', + 'WidgetAdresse' => __DIR__ . '/../..' . '/www/widgets/widget.adresse.php', + 'WidgetAdresse_accounts' => __DIR__ . '/../..' . '/www/widgets/widget.adresse_accounts.php', + 'WidgetAdresse_rolle' => __DIR__ . '/../..' . '/www/widgets/widget.adresse_rolle.php', + 'WidgetAdresse_typ' => __DIR__ . '/../..' . '/www/widgets/widget.adresse_typ.php', + 'WidgetAktionscode_liste' => __DIR__ . '/../..' . '/www/widgets/widget.aktionscode_liste.php', + 'WidgetAnfrage' => __DIR__ . '/../..' . '/www/widgets/widget.anfrage.php', + 'WidgetAnfrage_position' => __DIR__ . '/../..' . '/www/widgets/widget.anfrage_position.php', + 'WidgetAngebot' => __DIR__ . '/../..' . '/www/widgets/widget.angebot.php', + 'WidgetAngebot_position' => __DIR__ . '/../..' . '/www/widgets/widget.angebot_position.php', + 'WidgetAnsprechpartner' => __DIR__ . '/../..' . '/www/widgets/widget.ansprechpartner.php', + 'WidgetArbeitsfreietage' => __DIR__ . '/../..' . '/www/widgets/widget.arbeitsfreietage.php', + 'WidgetArbeitsnachweis' => __DIR__ . '/../..' . '/www/widgets/widget.arbeitsnachweis.php', + 'WidgetArbeitsnachweis_position' => __DIR__ . '/../..' . '/www/widgets/widget.arbeitsnachweis_position.php', + 'WidgetArbeitspaket' => __DIR__ . '/../..' . '/www/widgets/widget.arbeitspaket.php', + 'WidgetArtikel' => __DIR__ . '/../..' . '/www/widgets/widget.artikel.php', + 'WidgetArtikeleigenschaften' => __DIR__ . '/../..' . '/www/widgets/widget.artikeleigenschaften.php', + 'WidgetArtikeleinheit' => __DIR__ . '/../..' . '/www/widgets/widget.artikeleinheit.php', + 'WidgetArtikelgruppen' => __DIR__ . '/../..' . '/www/widgets/widget.artikelgruppen.php', + 'WidgetArtikelkategorien' => __DIR__ . '/../..' . '/www/widgets/widget.artikelkategorien.php', + 'WidgetArtikeloptionengruppe' => __DIR__ . '/../..' . '/www/widgets/widget.artikeloptionengruppe.php', + 'WidgetAufgabe' => __DIR__ . '/../..' . '/www/widgets/widget.aufgabe.php', + 'WidgetAuftrag' => __DIR__ . '/../..' . '/www/widgets/widget.auftrag.php', + 'WidgetAuftrag_artikel' => __DIR__ . '/../..' . '/www/widgets/widget.auftrag_artikel.php', + 'WidgetAuftrag_position' => __DIR__ . '/../..' . '/www/widgets/widget.auftrag_position.php', + 'WidgetBerichte' => __DIR__ . '/../..' . '/www/widgets/widget.berichte.php', + 'WidgetBestellung' => __DIR__ . '/../..' . '/www/widgets/widget.bestellung.php', + 'WidgetBestellung_position' => __DIR__ . '/../..' . '/www/widgets/widget.bestellung_position.php', + 'WidgetBrief' => __DIR__ . '/../..' . '/www/widgets/widget.brief.php', + 'WidgetDrucker' => __DIR__ . '/../..' . '/www/widgets/widget.drucker.php', + 'WidgetEinkaufspreise' => __DIR__ . '/../..' . '/www/widgets/widget.einkaufspreise.php', + 'WidgetEmail' => __DIR__ . '/../..' . '/www/widgets/widget.email.php', + 'WidgetEtiketten' => __DIR__ . '/../..' . '/www/widgets/widget.etiketten.php', + 'WidgetExportvorlage' => __DIR__ . '/../..' . '/www/widgets/widget.exportvorlage.php', + 'WidgetGenabrechnungsartikel' => __DIR__ . '/../..' . '/www/widgets/_gen/widget.gen.abrechnungsartikel.php', + 'WidgetGenadapterbox' => __DIR__ . '/../..' . '/www/widgets/_gen/widget.gen.adapterbox.php', + 'WidgetGenadresse' => __DIR__ . '/../..' . '/www/widgets/_gen/widget.gen.adresse.php', + 'WidgetGenadresse_accounts' => __DIR__ . '/../..' . '/www/widgets/_gen/widget.gen.adresse_accounts.php', + 'WidgetGenadresse_onchange' => __DIR__ . '/../..' . '/www/widgets/_gen/widget.gen.adresse_onchange.php', + 'WidgetGenadresse_rolle' => __DIR__ . '/../..' . '/www/widgets/_gen/widget.gen.adresse_rolle.php', + 'WidgetGenadresse_typ' => __DIR__ . '/../..' . '/www/widgets/_gen/widget.gen.adresse_typ.php', + 'WidgetGenaktionscode_liste' => __DIR__ . '/../..' . '/www/widgets/_gen/widget.gen.aktionscode_liste.php', + 'WidgetGenanfrage' => __DIR__ . '/../..' . '/www/widgets/_gen/widget.gen.anfrage.php', + 'WidgetGenanfrage_position' => __DIR__ . '/../..' . '/www/widgets/_gen/widget.gen.anfrage_position.php', + 'WidgetGenangebot' => __DIR__ . '/../..' . '/www/widgets/_gen/widget.gen.angebot.php', + 'WidgetGenangebot_position' => __DIR__ . '/../..' . '/www/widgets/_gen/widget.gen.angebot_position.php', + 'WidgetGenansprechpartner' => __DIR__ . '/../..' . '/www/widgets/_gen/widget.gen.ansprechpartner.php', + 'WidgetGenarbeitsfreietage' => __DIR__ . '/../..' . '/www/widgets/_gen/widget.gen.arbeitsfreietage.php', + 'WidgetGenarbeitsnachweis' => __DIR__ . '/../..' . '/www/widgets/_gen/widget.gen.arbeitsnachweis.php', + 'WidgetGenarbeitsnachweis_position' => __DIR__ . '/../..' . '/www/widgets/_gen/widget.gen.arbeitsnachweis_position.php', + 'WidgetGenarbeitspaket' => __DIR__ . '/../..' . '/www/widgets/_gen/widget.gen.arbeitspaket.php', + 'WidgetGenartikel' => __DIR__ . '/../..' . '/www/widgets/_gen/widget.gen.artikel.php', + 'WidgetGenartikeleigenschaften' => __DIR__ . '/../..' . '/www/widgets/_gen/widget.gen.artikeleigenschaften.php', + 'WidgetGenartikeleinheit' => __DIR__ . '/../..' . '/www/widgets/_gen/widget.gen.artikeleinheit.php', + 'WidgetGenartikelgruppen' => __DIR__ . '/../..' . '/www/widgets/_gen/widget.gen.artikelgruppen.php', + 'WidgetGenartikelkategorien' => __DIR__ . '/../..' . '/www/widgets/_gen/widget.gen.artikelkategorien.php', + 'WidgetGenartikeloptionengruppe' => __DIR__ . '/../..' . '/www/widgets/_gen/widget.gen.artikeloptionengruppe.php', + 'WidgetGenaufgabe' => __DIR__ . '/../..' . '/www/widgets/_gen/widget.gen.aufgabe.php', + 'WidgetGenauftrag' => __DIR__ . '/../..' . '/www/widgets/_gen/widget.gen.auftrag.php', + 'WidgetGenauftrag_artikel' => __DIR__ . '/../..' . '/www/widgets/_gen/widget.gen.auftrag_artikel.php', + 'WidgetGenauftrag_position' => __DIR__ . '/../..' . '/www/widgets/_gen/widget.gen.auftrag_position.php', + 'WidgetGenauftragsannahme' => __DIR__ . '/../..' . '/www/widgets/_gen/widget.gen.auftragsannahme.php', + 'WidgetGenbackupserver' => __DIR__ . '/../..' . '/www/widgets/_gen/widget.gen.backupserver.php', + 'WidgetGenberichte' => __DIR__ . '/../..' . '/www/widgets/_gen/widget.gen.berichte.php', + 'WidgetGenbestellung' => __DIR__ . '/../..' . '/www/widgets/_gen/widget.gen.bestellung.php', + 'WidgetGenbestellung_position' => __DIR__ . '/../..' . '/www/widgets/_gen/widget.gen.bestellung_position.php', + 'WidgetGenbrief' => __DIR__ . '/../..' . '/www/widgets/_gen/widget.gen.brief.php', + 'WidgetGenchargen' => __DIR__ . '/../..' . '/www/widgets/_gen/widget.gen.chargen.php', + 'WidgetGencluster' => __DIR__ . '/../..' . '/www/widgets/_gen/widget.gen.cluster.php', + 'WidgetGendatei_stichwortvorlagen' => __DIR__ . '/../..' . '/www/widgets/_gen/widget.gen.datei_stichwortvorlagen.php', + 'WidgetGendrucker' => __DIR__ . '/../..' . '/www/widgets/_gen/widget.gen.drucker.php', + 'WidgetGeneigenschaften' => __DIR__ . '/../..' . '/www/widgets/_gen/widget.gen.eigenschaften.php', + 'WidgetGeneinkaufspreise' => __DIR__ . '/../..' . '/www/widgets/_gen/widget.gen.einkaufspreise.php', + 'WidgetGenemail' => __DIR__ . '/../..' . '/www/widgets/_gen/widget.gen.email.php', + 'WidgetGenemailbackup' => __DIR__ . '/../..' . '/www/widgets/_gen/widget.gen.emailbackup.php', + 'WidgetGenetiketten' => __DIR__ . '/../..' . '/www/widgets/_gen/widget.gen.etiketten.php', + 'WidgetGenexportvorlage' => __DIR__ . '/../..' . '/www/widgets/_gen/widget.gen.exportvorlage.php', + 'WidgetGenfahrtenbuch' => __DIR__ . '/../..' . '/www/widgets/_gen/widget.gen.fahrtenbuch.php', + 'WidgetGengeraeteverwaltung' => __DIR__ . '/../..' . '/www/widgets/_gen/widget.gen.geraeteverwaltung.php', + 'WidgetGengeschaeftsbrief_vorlagen' => __DIR__ . '/../..' . '/www/widgets/_gen/widget.gen.geschaeftsbrief_vorlagen.php', + 'WidgetGengeschaeftsfall' => __DIR__ . '/../..' . '/www/widgets/_gen/widget.gen.geschaeftsfall.php', + 'WidgetGengruppen' => __DIR__ . '/../..' . '/www/widgets/_gen/widget.gen.gruppen.php', + 'WidgetGengruppen_kategorien' => __DIR__ . '/../..' . '/www/widgets/_gen/widget.gen.gruppen_kategorien.php', + 'WidgetGengutschrift' => __DIR__ . '/../..' . '/www/widgets/_gen/widget.gen.gutschrift.php', + 'WidgetGengutschrift_position' => __DIR__ . '/../..' . '/www/widgets/_gen/widget.gen.gutschrift_position.php', + 'WidgetGenimportvorlage' => __DIR__ . '/../..' . '/www/widgets/_gen/widget.gen.importvorlage.php', + 'WidgetGeninhalt' => __DIR__ . '/../..' . '/www/widgets/_gen/widget.gen.inhalt.php', + 'WidgetGeninventur' => __DIR__ . '/../..' . '/www/widgets/_gen/widget.gen.inventur.php', + 'WidgetGeninventur_position' => __DIR__ . '/../..' . '/www/widgets/_gen/widget.gen.inventur_position.php', + 'WidgetGenkalkulation' => __DIR__ . '/../..' . '/www/widgets/_gen/widget.gen.kalkulation.php', + 'WidgetGenkalkulation_position' => __DIR__ . '/../..' . '/www/widgets/_gen/widget.gen.kalkulation_position.php', + 'WidgetGenkasse' => __DIR__ . '/../..' . '/www/widgets/_gen/widget.gen.kasse.php', + 'WidgetGenkontorahmen' => __DIR__ . '/../..' . '/www/widgets/_gen/widget.gen.kontorahmen.php', + 'WidgetGenkostenstellen' => __DIR__ . '/../..' . '/www/widgets/_gen/widget.gen.kostenstellen.php', + 'WidgetGenkundevorlage' => __DIR__ . '/../..' . '/www/widgets/_gen/widget.gen.kundevorlage.php', + 'WidgetGenlager' => __DIR__ . '/../..' . '/www/widgets/_gen/widget.gen.lager.php', + 'WidgetGenlieferadressen' => __DIR__ . '/../..' . '/www/widgets/_gen/widget.gen.lieferadressen.php', + 'WidgetGenlieferantvorlage' => __DIR__ . '/../..' . '/www/widgets/_gen/widget.gen.lieferantvorlage.php', + 'WidgetGenlieferbedingungen' => __DIR__ . '/../..' . '/www/widgets/_gen/widget.gen.lieferbedingungen.php', + 'WidgetGenlieferschein' => __DIR__ . '/../..' . '/www/widgets/_gen/widget.gen.lieferschein.php', + 'WidgetGenlieferschein_position' => __DIR__ . '/../..' . '/www/widgets/_gen/widget.gen.lieferschein_position.php', + 'WidgetGenpartner' => __DIR__ . '/../..' . '/www/widgets/_gen/widget.gen.partner.php', + 'WidgetGenpos_kassierer' => __DIR__ . '/../..' . '/www/widgets/_gen/widget.gen.pos_kassierer.php', + 'WidgetGenpreisanfrage' => __DIR__ . '/../..' . '/www/widgets/_gen/widget.gen.preisanfrage.php', + 'WidgetGenpreisanfrage_position' => __DIR__ . '/../..' . '/www/widgets/_gen/widget.gen.preisanfrage_position.php', + 'WidgetGenproduktion' => __DIR__ . '/../..' . '/www/widgets/_gen/widget.gen.produktion.php', + 'WidgetGenproduktion_position' => __DIR__ . '/../..' . '/www/widgets/_gen/widget.gen.produktion_position.php', + 'WidgetGenproformarechnung' => __DIR__ . '/../..' . '/www/widgets/_gen/widget.gen.proformarechnung.php', + 'WidgetGenproformarechnung_position' => __DIR__ . '/../..' . '/www/widgets/_gen/widget.gen.proformarechnung_position.php', + 'WidgetGenprojekt' => __DIR__ . '/../..' . '/www/widgets/_gen/widget.gen.projekt.php', + 'WidgetGenprozessstarter' => __DIR__ . '/../..' . '/www/widgets/_gen/widget.gen.prozessstarter.php', + 'WidgetGenrechnung' => __DIR__ . '/../..' . '/www/widgets/_gen/widget.gen.rechnung.php', + 'WidgetGenrechnung_position' => __DIR__ . '/../..' . '/www/widgets/_gen/widget.gen.rechnung_position.php', + 'WidgetGenreisekosten' => __DIR__ . '/../..' . '/www/widgets/_gen/widget.gen.reisekosten.php', + 'WidgetGenreisekosten_position' => __DIR__ . '/../..' . '/www/widgets/_gen/widget.gen.reisekosten_position.php', + 'WidgetGenreisekosten_positionen' => __DIR__ . '/../..' . '/www/widgets/_gen/widget.gen.reisekosten_positionen.php', + 'WidgetGenreisekostenart' => __DIR__ . '/../..' . '/www/widgets/_gen/widget.gen.reisekostenart.php', + 'WidgetGenremotezugang' => __DIR__ . '/../..' . '/www/widgets/_gen/widget.gen.remotezugang.php', + 'WidgetGenretoure' => __DIR__ . '/../..' . '/www/widgets/_gen/widget.gen.retoure.php', + 'WidgetGenretoure_position' => __DIR__ . '/../..' . '/www/widgets/_gen/widget.gen.retoure_position.php', + 'WidgetGenrohstoffe' => __DIR__ . '/../..' . '/www/widgets/_gen/widget.gen.rohstoffe.php', + 'WidgetGenseriennummern' => __DIR__ . '/../..' . '/www/widgets/_gen/widget.gen.seriennummern.php', + 'WidgetGenservice' => __DIR__ . '/../..' . '/www/widgets/_gen/widget.gen.service.php', + 'WidgetGenshopexport' => __DIR__ . '/../..' . '/www/widgets/_gen/widget.gen.shopexport.php', + 'WidgetGenshopexport_kampange' => __DIR__ . '/../..' . '/www/widgets/_gen/widget.gen.shopexport_kampange.php', + 'WidgetGenspedition' => __DIR__ . '/../..' . '/www/widgets/_gen/widget.gen.spedition.php', + 'WidgetGenspedition_avi' => __DIR__ . '/../..' . '/www/widgets/_gen/widget.gen.spedition_avi.php', + 'WidgetGenstation' => __DIR__ . '/../..' . '/www/widgets/_gen/widget.gen.station.php', + 'WidgetGenstueckliste' => __DIR__ . '/../..' . '/www/widgets/_gen/widget.gen.stueckliste.php', + 'WidgetGensupportapp' => __DIR__ . '/../..' . '/www/widgets/_gen/widget.gen.supportapp.php', + 'WidgetGenterminals' => __DIR__ . '/../..' . '/www/widgets/_gen/widget.gen.terminals.php', + 'WidgetGenticket' => __DIR__ . '/../..' . '/www/widgets/_gen/widget.gen.ticket.php', + 'WidgetGenticket_vorlage' => __DIR__ . '/../..' . '/www/widgets/_gen/widget.gen.ticket_vorlage.php', + 'WidgetGenuebersetzung' => __DIR__ . '/../..' . '/www/widgets/_gen/widget.gen.uebersetzung.php', + 'WidgetGenuser' => __DIR__ . '/../..' . '/www/widgets/_gen/widget.gen.user.php', + 'WidgetGenuservorlage' => __DIR__ . '/../..' . '/www/widgets/_gen/widget.gen.uservorlage.php', + 'WidgetGenverbindlichkeit' => __DIR__ . '/../..' . '/www/widgets/_gen/widget.gen.verbindlichkeit.php', + 'WidgetGenverbindlichkeit_position' => __DIR__ . '/../..' . '/www/widgets/_gen/widget.gen.verbindlichkeit_position.php', + 'WidgetGenverkaufspreise' => __DIR__ . '/../..' . '/www/widgets/_gen/widget.gen.verkaufspreise.php', + 'WidgetGenverrechnungsart' => __DIR__ . '/../..' . '/www/widgets/_gen/widget.gen.verrechnungsart.php', + 'WidgetGenversandarten' => __DIR__ . '/../..' . '/www/widgets/_gen/widget.gen.versandarten.php', + 'WidgetGenvorlage' => __DIR__ . '/../..' . '/www/widgets/_gen/widget.gen.vorlage.php', + 'WidgetGenwaage_artikel' => __DIR__ . '/../..' . '/www/widgets/_gen/widget.gen.waage_artikel.php', + 'WidgetGenwarteschlangen' => __DIR__ . '/../..' . '/www/widgets/_gen/widget.gen.warteschlangen.php', + 'WidgetGenwawisioneinrichtung' => __DIR__ . '/../..' . '/www/widgets/_gen/widget.gen.wawisioneinrichtung.php', + 'WidgetGenwebmail' => __DIR__ . '/../..' . '/www/widgets/_gen/widget.gen.webmail.php', + 'WidgetGenwebmail_mails' => __DIR__ . '/../..' . '/www/widgets/_gen/widget.gen.webmail_mails.php', + 'WidgetGenwebmail_zuordnung' => __DIR__ . '/../..' . '/www/widgets/_gen/widget.gen.webmail_zuordnung.php', + 'WidgetGenwiedervorlage' => __DIR__ . '/../..' . '/www/widgets/_gen/widget.gen.wiedervorlage.php', + 'WidgetGenwissensdatenbank' => __DIR__ . '/../..' . '/www/widgets/_gen/widget.gen.wissensdatenbank.php', + 'WidgetGenzahlungsweisen' => __DIR__ . '/../..' . '/www/widgets/_gen/widget.gen.zahlungsweisen.php', + 'WidgetGenzeiterfassungvorlage' => __DIR__ . '/../..' . '/www/widgets/_gen/widget.gen.zeiterfassungvorlage.php', + 'WidgetGenzolltarifnummer' => __DIR__ . '/../..' . '/www/widgets/_gen/widget.gen.zolltarifnummer.php', + 'WidgetGenzugangstoken' => __DIR__ . '/../..' . '/www/widgets/_gen/widget.gen.zugangstoken.php', + 'WidgetGeschaeftsbrief_vorlagen' => __DIR__ . '/../..' . '/www/widgets/widget.geschaeftsbrief_vorlagen.php', + 'WidgetGutschrift' => __DIR__ . '/../..' . '/www/widgets/widget.gutschrift.php', + 'WidgetGutschrift_position' => __DIR__ . '/../..' . '/www/widgets/widget.gutschrift_position.php', + 'WidgetImportvorlage' => __DIR__ . '/../..' . '/www/widgets/widget.importvorlage.php', + 'WidgetInhalt' => __DIR__ . '/../..' . '/www/widgets/widget.inhalt.php', + 'WidgetInventur' => __DIR__ . '/../..' . '/www/widgets/widget.inventur.php', + 'WidgetInventur_position' => __DIR__ . '/../..' . '/www/widgets/widget.inventur_position.php', + 'WidgetKalkulation' => __DIR__ . '/../..' . '/www/widgets/widget.kalkulation.php', + 'WidgetKalkulation_position' => __DIR__ . '/../..' . '/www/widgets/widget.kalkulation_position.php', + 'WidgetKostenstellen' => __DIR__ . '/../..' . '/www/widgets/widget.kostenstellen.php', + 'WidgetKundevorlage' => __DIR__ . '/../..' . '/www/widgets/widget.kundevorlage.php', + 'WidgetLager' => __DIR__ . '/../..' . '/www/widgets/widget.lager.php', + 'WidgetLieferadressen' => __DIR__ . '/../..' . '/www/widgets/widget.lieferadressen.php', + 'WidgetLieferantvorlage' => __DIR__ . '/../..' . '/www/widgets/widget.lieferantvorlage.php', + 'WidgetLieferschein' => __DIR__ . '/../..' . '/www/widgets/widget.lieferschein.php', + 'WidgetLieferschein_position' => __DIR__ . '/../..' . '/www/widgets/widget.lieferschein_position.php', + 'WidgetPreisanfrage' => __DIR__ . '/../..' . '/www/widgets/widget.preisanfrage.php', + 'WidgetPreisanfrage_position' => __DIR__ . '/../..' . '/www/widgets/widget.preisanfrage_position.php', + 'WidgetProformarechnung' => __DIR__ . '/../..' . '/www/widgets/widget.proformarechnung.php', + 'WidgetProformarechnung_position' => __DIR__ . '/../..' . '/www/widgets/widget.proformarechnung_position.php', + 'WidgetProjekt' => __DIR__ . '/../..' . '/www/widgets/widget.projekt.php', + 'WidgetProzessstarter' => __DIR__ . '/../..' . '/www/widgets/widget.prozessstarter.php', + 'WidgetRechnung' => __DIR__ . '/../..' . '/www/widgets/widget.rechnung.php', + 'WidgetRechnung_position' => __DIR__ . '/../..' . '/www/widgets/widget.rechnung_position.php', + 'WidgetReisekosten' => __DIR__ . '/../..' . '/www/widgets/widget.reisekosten.php', + 'WidgetReisekosten_position' => __DIR__ . '/../..' . '/www/widgets/widget.reisekosten_position.php', + 'WidgetReisekostenart' => __DIR__ . '/../..' . '/www/widgets/widget.reisekostenart.php', + 'WidgetRetoure' => __DIR__ . '/../..' . '/www/widgets/widget.retoure.php', + 'WidgetRetoure_position' => __DIR__ . '/../..' . '/www/widgets/widget.retoure_position.php', + 'WidgetRohstoffe' => __DIR__ . '/../..' . '/www/widgets/widget.rohstoffe.php', + 'WidgetShopexport' => __DIR__ . '/../..' . '/www/widgets/widget.shopexport.php', + 'WidgetShopexport_kampange' => __DIR__ . '/../..' . '/www/widgets/widget.shopexport_kampange.php', + 'WidgetStueckliste' => __DIR__ . '/../..' . '/www/widgets/widget.stueckliste.php', + 'WidgetUebersetzung' => __DIR__ . '/../..' . '/www/widgets/widget.uebersetzung.php', + 'WidgetUser' => __DIR__ . '/../..' . '/www/widgets/widget.user.php', + 'WidgetUservorlage' => __DIR__ . '/../..' . '/www/widgets/widget.uservorlage.php', + 'WidgetVerbindlichkeit' => __DIR__ . '/../..' . '/www/widgets/widget.verbindlichkeit.php', + 'WidgetVerbindlichkeit_position' => __DIR__ . '/../..' . '/www/widgets/widget.verbindlichkeit_position.php', + 'WidgetVerkaufspreise' => __DIR__ . '/../..' . '/www/widgets/widget.verkaufspreise.php', + 'WidgetVerrechnungsart' => __DIR__ . '/../..' . '/www/widgets/widget.verrechnungsart.php', + 'WidgetVersandarten' => __DIR__ . '/../..' . '/www/widgets/widget.versandarten.php', + 'WidgetVorlage' => __DIR__ . '/../..' . '/www/widgets/widget.vorlage.php', + 'WidgetWawisioneinrichtung' => __DIR__ . '/../..' . '/www/widgets/widget.wawisioneinrichtung.php', + 'WidgetWebmail_mails' => __DIR__ . '/../..' . '/www/widgets/widget.webmail_mails.php', + 'WidgetWiedervorlage' => __DIR__ . '/../..' . '/www/widgets/widget.wiedervorlage.php', + 'WidgetWissensdatenbank' => __DIR__ . '/../..' . '/www/widgets/widget.wissensdatenbank.php', + 'WidgetZahlungsweisen' => __DIR__ . '/../..' . '/www/widgets/widget.zahlungsweisen.php', + 'WidgetZeiterfassungvorlage' => __DIR__ . '/../..' . '/www/widgets/widget.zeiterfassungvorlage.php', + 'WidgetZolltarifnummer' => __DIR__ . '/../..' . '/www/widgets/widget.zolltarifnummer.php', + 'Widgetgruppen' => __DIR__ . '/../..' . '/www/widgets/widget.gruppen.php', + 'Widgetgruppen_kategorien' => __DIR__ . '/../..' . '/www/widgets/widget.gruppen_kategorien.php', + 'WikiParser' => __DIR__ . '/../..' . '/www/plugins/class.wikiparser.php', + 'XTEA' => __DIR__ . '/../..' . '/www/lib/class.xtea.php', 'Xentral\\Carrier\\Dhl\\Data\\Bank' => __DIR__ . '/../..' . '/classes/Carrier/Dhl/Data/Bank.php', 'Xentral\\Carrier\\Dhl\\Data\\Communication' => __DIR__ . '/../..' . '/classes/Carrier/Dhl/Data/Communication.php', 'Xentral\\Carrier\\Dhl\\Data\\Contact' => __DIR__ . '/../..' . '/classes/Carrier/Dhl/Data/Contact.php', @@ -2816,8 +3085,6 @@ class ComposerStaticInit0c49a81c1214ef2f7493c6ce921b17ee 'Xentral\\Components\\Mailer\\Transport\\PhpMailerOAuth' => __DIR__ . '/../..' . '/classes/Components/Mailer/Transport/PhpMailerOAuth.php', 'Xentral\\Components\\Mailer\\Transport\\PhpMailerOAuthAuthentificationInterface' => __DIR__ . '/../..' . '/classes/Components/Mailer/Transport/PhpMailerOAuthAuthentificationInterface.php', 'Xentral\\Components\\Mailer\\Transport\\PhpMailerTransport' => __DIR__ . '/../..' . '/classes/Components/Mailer/Transport/PhpMailerTransport.php', - 'Xentral\\Components\\Mailer\\Wrapper\\LoggerWrapper' => __DIR__ . '/../..' . '/classes/Components/Mailer/Wrapper/LoggerWrapper.php', - 'Xentral\\Components\\Mailer\\Wrapper\\MemoryLogger' => __DIR__ . '/../..' . '/classes/Components/Mailer/Wrapper/MemoryLogger.php', 'Xentral\\Components\\Pdf\\Bootstrap' => __DIR__ . '/../..' . '/classes/Components/Pdf/Bootstrap.php', 'Xentral\\Components\\Pdf\\Exception\\FileExistsException' => __DIR__ . '/../..' . '/classes/Components/Pdf/Exception/FileExistsException.php', 'Xentral\\Components\\Pdf\\Exception\\FileNotFoundException' => __DIR__ . '/../..' . '/classes/Components/Pdf/Exception/FileNotFoundException.php', @@ -3330,15 +3597,6 @@ class ComposerStaticInit0c49a81c1214ef2f7493c6ce921b17ee 'Xentral\\Modules\\Ebay\\Service\\EbayStockLoggingService' => __DIR__ . '/../..' . '/classes/Modules/Ebay/Service/EbayStockLoggingService.php', 'Xentral\\Modules\\Ebay\\Wrapper\\EbayStockCalculationWrapperInterface' => __DIR__ . '/../..' . '/classes/Modules/Ebay/Wrapper/EbayStockCalculationWrapperInterface.php', 'Xentral\\Modules\\Ebay\\Wrapper\\StockCalculationWrapper' => __DIR__ . '/../..' . '/classes/Modules/Ebay/Wrapper/StockCalculationWrapper.php', - 'Xentral\\Modules\\EtsyApi\\Credential\\AbstractCredentialData' => __DIR__ . '/../..' . '/classes/Modules/EtsyApi/Credential/AbstractCredentialData.php', - 'Xentral\\Modules\\EtsyApi\\Credential\\ClientCredentialData' => __DIR__ . '/../..' . '/classes/Modules/EtsyApi/Credential/ClientCredentialData.php', - 'Xentral\\Modules\\EtsyApi\\Credential\\CredentialDataInterface' => __DIR__ . '/../..' . '/classes/Modules/EtsyApi/Credential/CredentialDataInterface.php', - 'Xentral\\Modules\\EtsyApi\\Credential\\TemporaryCredentialData' => __DIR__ . '/../..' . '/classes/Modules/EtsyApi/Credential/TemporaryCredentialData.php', - 'Xentral\\Modules\\EtsyApi\\Credential\\TokenCredentialData' => __DIR__ . '/../..' . '/classes/Modules/EtsyApi/Credential/TokenCredentialData.php', - 'Xentral\\Modules\\EtsyApi\\EtsyOAuthHelper' => __DIR__ . '/../..' . '/classes/Modules/EtsyApi/EtsyOAuthHelper.php', - 'Xentral\\Modules\\EtsyApi\\Exception\\CredentialException' => __DIR__ . '/../..' . '/classes/Modules/EtsyApi/Exception/CredentialException.php', - 'Xentral\\Modules\\EtsyApi\\Exception\\EtsyApiExceptionInterface' => __DIR__ . '/../..' . '/classes/Modules/EtsyApi/Exception/EtsyApiExceptionInterface.php', - 'Xentral\\Modules\\EtsyApi\\Exception\\EtsyOAuthException' => __DIR__ . '/../..' . '/classes/Modules/EtsyApi/Exception/EtsyOAuthException.php', 'Xentral\\Modules\\FeeReduction\\Bootstrap' => __DIR__ . '/../..' . '/classes/Modules/FeeReduction/Bootstrap.php', 'Xentral\\Modules\\FeeReduction\\Exception\\FeeReductionExceptionInterface' => __DIR__ . '/../..' . '/classes/Modules/FeeReduction/Exception/FeeReductionExceptionInterface.php', 'Xentral\\Modules\\FeeReduction\\Exception\\InvalidArgumentException' => __DIR__ . '/../..' . '/classes/Modules/FeeReduction/Exception/InvalidArgumentException.php', @@ -3593,7 +3851,6 @@ class ComposerStaticInit0c49a81c1214ef2f7493c6ce921b17ee 'Xentral\\Modules\\Log\\Service\\DatabaseLogGateway' => __DIR__ . '/../..' . '/classes/Modules/Log/Service/DatabaseLogGateway.php', 'Xentral\\Modules\\Log\\Service\\DatabaseLogService' => __DIR__ . '/../..' . '/classes/Modules/Log/Service/DatabaseLogService.php', 'Xentral\\Modules\\Log\\Service\\LoggerConfigService' => __DIR__ . '/../..' . '/classes/Modules/Log/Service/LoggerConfigService.php', - 'Xentral\\Modules\\Log\\Wrapper\\CompanyConfigWrapper' => __DIR__ . '/../..' . '/classes/Modules/Log/Wrapper/CompanyConfigWrapper.php', 'Xentral\\Modules\\MandatoryFields\\Bootstrap' => __DIR__ . '/../..' . '/classes/Modules/MandatoryFields/Bootstrap.php', 'Xentral\\Modules\\MandatoryFields\\Data\\MandatoryFieldData' => __DIR__ . '/../..' . '/classes/Modules/MandatoryFields/Data/MandatoryFieldData.php', 'Xentral\\Modules\\MandatoryFields\\Data\\ValidatorResultData' => __DIR__ . '/../..' . '/classes/Modules/MandatoryFields/Data/ValidatorResultData.php', @@ -4109,20 +4366,24 @@ class ComposerStaticInit0c49a81c1214ef2f7493c6ce921b17ee 'Xentral\\Widgets\\SuperSearch\\Result\\ResultDetail' => __DIR__ . '/../..' . '/classes/Widgets/SuperSearch/Result/ResultDetail.php', 'Xentral\\Widgets\\SuperSearch\\Result\\ResultGroup' => __DIR__ . '/../..' . '/classes/Widgets/SuperSearch/Result/ResultGroup.php', 'Xentral\\Widgets\\SuperSearch\\Result\\ResultItem' => __DIR__ . '/../..' . '/classes/Widgets/SuperSearch/Result/ResultItem.php', - 'Y0lk\\OAuth1\\Client\\Server\\Etsy' => __DIR__ . '/..' . '/y0lk/oauth1-etsy/src/Etsy.php', + 'YUI' => __DIR__ . '/../..' . '/phpwf/plugins/class.yui.php', + 'erpAPI' => __DIR__ . '/../..' . '/www/lib/class.erpapi.php', + 'erpooSystem' => __DIR__ . '/../..' . '/www/eproosystem.php', + 'image' => __DIR__ . '/../..' . '/www/lib/class.image.php', 'lfkeitel\\phptotp\\Base32' => __DIR__ . '/..' . '/lfkeitel/phptotp/src/Base32.php', 'lfkeitel\\phptotp\\Hotp' => __DIR__ . '/..' . '/lfkeitel/phptotp/src/Hotp.php', 'lfkeitel\\phptotp\\Totp' => __DIR__ . '/..' . '/lfkeitel/phptotp/src/Totp.php', + 'phpprint' => __DIR__ . '/../..' . '/www/plugins/php-print.php', ); public static function getInitializer(ClassLoader $loader) { return \Closure::bind(function () use ($loader) { - $loader->prefixLengthsPsr4 = ComposerStaticInit0c49a81c1214ef2f7493c6ce921b17ee::$prefixLengthsPsr4; - $loader->prefixDirsPsr4 = ComposerStaticInit0c49a81c1214ef2f7493c6ce921b17ee::$prefixDirsPsr4; - $loader->fallbackDirsPsr4 = ComposerStaticInit0c49a81c1214ef2f7493c6ce921b17ee::$fallbackDirsPsr4; - $loader->prefixesPsr0 = ComposerStaticInit0c49a81c1214ef2f7493c6ce921b17ee::$prefixesPsr0; - $loader->classMap = ComposerStaticInit0c49a81c1214ef2f7493c6ce921b17ee::$classMap; + $loader->prefixLengthsPsr4 = ComposerStaticInit79eff8c373a8f453cf73098a3a8ce631::$prefixLengthsPsr4; + $loader->prefixDirsPsr4 = ComposerStaticInit79eff8c373a8f453cf73098a3a8ce631::$prefixDirsPsr4; + $loader->fallbackDirsPsr4 = ComposerStaticInit79eff8c373a8f453cf73098a3a8ce631::$fallbackDirsPsr4; + $loader->prefixesPsr0 = ComposerStaticInit79eff8c373a8f453cf73098a3a8ce631::$prefixesPsr0; + $loader->classMap = ComposerStaticInit79eff8c373a8f453cf73098a3a8ce631::$classMap; }, null, ClassLoader::class); } diff --git a/vendor/composer/installed.json b/vendor/composer/installed.json index 8f974ba08..884225af4 100644 --- a/vendor/composer/installed.json +++ b/vendor/composer/installed.json @@ -1,3111 +1,2991 @@ { - "packages": [ - { - "name": "aura/sqlquery", - "version": "2.7.1", - "version_normalized": "2.7.1.0", - "source": { - "type": "git", - "url": "https://github.com/auraphp/Aura.SqlQuery.git", - "reference": "dd81b57aeb43628180a9c70a4df58d872024d7f2" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/auraphp/Aura.SqlQuery/zipball/dd81b57aeb43628180a9c70a4df58d872024d7f2", - "reference": "dd81b57aeb43628180a9c70a4df58d872024d7f2", - "shasum": "" - }, - "require": { - "php": ">=5.3.9" - }, - "suggest": { - "aura/sql": "Provides an extension to the native PDO along with a profiler and connection locator. Use version 2.*." - }, - "time": "2016-10-03T20:34:56+00:00", - "type": "library", - "extra": { - "aura": { - "type": "library" - } - }, - "installation-source": "dist", - "autoload": { - "psr-4": { - "Aura\\SqlQuery\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-2-Clause" - ], - "authors": [ - { - "name": "Aura.SqlQuery Contributors", - "homepage": "https://github.com/auraphp/Aura.SqlQuery/contributors" - } - ], - "description": "Object-oriented query builders for MySQL, Postgres, SQLite, and SQLServer; can be used with any database connection library.", - "homepage": "https://github.com/auraphp/Aura.SqlQuery", - "keywords": [ - "database", - "db", - "delete", - "dml", - "insert", - "mysql", - "pdo", - "pgsql", - "postgres", - "postgresql", - "query", - "select", - "sql", - "sql server", - "sqlite", - "sqlserver", - "update" - ], - "support": { - "issues": "https://github.com/auraphp/Aura.SqlQuery/issues", - "source": "https://github.com/auraphp/Aura.SqlQuery/tree/2.7.1" - }, - "install-path": "../aura/sqlquery" + "packages": [ + { + "name": "aura/sqlquery", + "version": "2.7.1", + "version_normalized": "2.7.1.0", + "source": { + "type": "git", + "url": "https://github.com/auraphp/Aura.SqlQuery.git", + "reference": "dd81b57aeb43628180a9c70a4df58d872024d7f2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/auraphp/Aura.SqlQuery/zipball/dd81b57aeb43628180a9c70a4df58d872024d7f2", + "reference": "dd81b57aeb43628180a9c70a4df58d872024d7f2", + "shasum": "" + }, + "require": { + "php": ">=5.3.9" + }, + "suggest": { + "aura/sql": "Provides an extension to the native PDO along with a profiler and connection locator. Use version 2.*." + }, + "time": "2016-10-03T20:34:56+00:00", + "type": "library", + "extra": { + "aura": { + "type": "library" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Aura\\SqlQuery\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-2-Clause" + ], + "authors": [ + { + "name": "Aura.SqlQuery Contributors", + "homepage": "https://github.com/auraphp/Aura.SqlQuery/contributors" + } + ], + "description": "Object-oriented query builders for MySQL, Postgres, SQLite, and SQLServer; can be used with any database connection library.", + "homepage": "https://github.com/auraphp/Aura.SqlQuery", + "keywords": [ + "database", + "db", + "delete", + "dml", + "insert", + "mysql", + "pdo", + "pgsql", + "postgres", + "postgresql", + "query", + "select", + "sql", + "sql server", + "sqlite", + "sqlserver", + "update" + ], + "support": { + "issues": "https://github.com/auraphp/Aura.SqlQuery/issues", + "source": "https://github.com/auraphp/Aura.SqlQuery/tree/2.7.1" + }, + "install-path": "../aura/sqlquery" + }, + { + "name": "aws/aws-sdk-php", + "version": "3.175.2", + "version_normalized": "3.175.2.0", + "source": { + "type": "git", + "url": "https://github.com/aws/aws-sdk-php.git", + "reference": "a8e88eac60b403ed76643327e74f55831570a64b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/a8e88eac60b403ed76643327e74f55831570a64b", + "reference": "a8e88eac60b403ed76643327e74f55831570a64b", + "shasum": "" + }, + "require": { + "ext-json": "*", + "ext-pcre": "*", + "ext-simplexml": "*", + "guzzlehttp/guzzle": "^5.3.3|^6.2.1|^7.0", + "guzzlehttp/promises": "^1.4.0", + "guzzlehttp/psr7": "^1.7.0", + "mtdowling/jmespath.php": "^2.6", + "php": ">=5.5" + }, + "require-dev": { + "andrewsville/php-token-reflection": "^1.4", + "aws/aws-php-sns-message-validator": "~1.0", + "behat/behat": "~3.0", + "doctrine/cache": "~1.4", + "ext-dom": "*", + "ext-openssl": "*", + "ext-pcntl": "*", + "ext-sockets": "*", + "nette/neon": "^2.3", + "paragonie/random_compat": ">= 2", + "phpunit/phpunit": "^4.8.35|^5.4.3", + "psr/cache": "^1.0", + "psr/simple-cache": "^1.0", + "sebastian/comparator": "^1.2.3" + }, + "suggest": { + "aws/aws-php-sns-message-validator": "To validate incoming SNS notifications", + "doctrine/cache": "To use the DoctrineCacheAdapter", + "ext-curl": "To send requests using cURL", + "ext-openssl": "Allows working with CloudFront private distributions and verifying received SNS messages", + "ext-sockets": "To use client-side monitoring" + }, + "time": "2021-03-23T18:18:49+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0-dev" + } + }, + "installation-source": "dist", + "autoload": { + "files": [ + "src/functions.php" + ], + "psr-4": { + "Aws\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "Amazon Web Services", + "homepage": "http://aws.amazon.com" + } + ], + "description": "AWS SDK for PHP - Use Amazon Web Services in your PHP project", + "homepage": "http://aws.amazon.com/sdkforphp", + "keywords": [ + "amazon", + "aws", + "cloud", + "dynamodb", + "ec2", + "glacier", + "s3", + "sdk" + ], + "support": { + "forum": "https://forums.aws.amazon.com/forum.jspa?forumID=80", + "issues": "https://github.com/aws/aws-sdk-php/issues", + "source": "https://github.com/aws/aws-sdk-php/tree/3.175.2" + }, + "install-path": "../aws/aws-sdk-php" + }, + { + "name": "datto/json-rpc", + "version": "6.1.0", + "version_normalized": "6.1.0.0", + "source": { + "type": "git", + "url": "https://github.com/datto/php-json-rpc.git", + "reference": "ad4d735f48d80c6b53f7405e5007d97c996533f6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/datto/php-json-rpc/zipball/ad4d735f48d80c6b53f7405e5007d97c996533f6", + "reference": "ad4d735f48d80c6b53f7405e5007d97c996533f6", + "shasum": "" + }, + "require": { + "php": ">=7.0.0" + }, + "require-dev": { + "phpunit/phpunit": "^6.5" + }, + "time": "2020-02-28T23:54:06+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "Datto\\JsonRpc\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "LGPL-3.0+" + ], + "authors": [ + { + "name": "Spencer Mortensen", + "email": "smortensen@datto.com", + "homepage": "http://spencermortensen.com", + "role": "Developer" + } + ], + "description": "Fully unit-tested JSON-RPC 2.0 for PHP", + "homepage": "http://datto.com", + "keywords": [ + "json", + "json-rpc", + "jsonrpc", + "php", + "php-json-rpc", + "rpc" + ], + "support": { + "issues": "https://github.com/datto/php-json-rpc/issues", + "source": "https://github.com/datto/php-json-rpc/tree/6.1.0" + }, + "install-path": "../datto/json-rpc" + }, + { + "name": "datto/json-rpc-http", + "version": "5.0.6", + "version_normalized": "5.0.6.0", + "source": { + "type": "git", + "url": "https://github.com/datto/php-json-rpc-http.git", + "reference": "db15a075f3562c4e8d297b9082acc5b2869bd4b4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/datto/php-json-rpc-http/zipball/db15a075f3562c4e8d297b9082acc5b2869bd4b4", + "reference": "db15a075f3562c4e8d297b9082acc5b2869bd4b4", + "shasum": "" + }, + "require": { + "datto/json-rpc": "~6.1", + "php": ">=7.0.0" + }, + "time": "2020-03-02T21:27:10+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "Datto\\JsonRpc\\Http\\": "src", + "Datto\\JsonRpc\\Http\\Examples\\": "examples/src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "LGPL-3.0+" + ], + "authors": [ + { + "name": "Spencer Mortensen", + "email": "smortensen@datto.com", + "homepage": "http://spencermortensen.com", + "role": "Developer" + } + ], + "description": "HTTP client and server for JSON-RPC 2.0", + "homepage": "http://datto.com", + "keywords": [ + "client", + "http", + "json", + "json-rpc", + "jsonrpc", + "php", + "php-json-rpc", + "rpc", + "server" + ], + "support": { + "issues": "https://github.com/datto/php-json-rpc-http/issues", + "source": "https://github.com/datto/php-json-rpc-http/tree/master" + }, + "install-path": "../datto/json-rpc-http" + }, + { + "name": "ezyang/htmlpurifier", + "version": "v4.13.0", + "version_normalized": "4.13.0.0", + "source": { + "type": "git", + "url": "https://github.com/ezyang/htmlpurifier.git", + "reference": "08e27c97e4c6ed02f37c5b2b20488046c8d90d75" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ezyang/htmlpurifier/zipball/08e27c97e4c6ed02f37c5b2b20488046c8d90d75", + "reference": "08e27c97e4c6ed02f37c5b2b20488046c8d90d75", + "shasum": "" + }, + "require": { + "php": ">=5.2" + }, + "require-dev": { + "simpletest/simpletest": "dev-master#72de02a7b80c6bb8864ef9bf66d41d2f58f826bd" + }, + "time": "2020-06-29T00:56:53+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "files": [ + "library/HTMLPurifier.composer.php" + ], + "psr-0": { + "HTMLPurifier": "library/" }, + "exclude-from-classmap": [ + "/library/HTMLPurifier/Language/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "LGPL-2.1-or-later" + ], + "authors": [ + { + "name": "Edward Z. Yang", + "email": "admin@htmlpurifier.org", + "homepage": "http://ezyang.com" + } + ], + "description": "Standards compliant HTML filter written in PHP", + "homepage": "http://htmlpurifier.org/", + "keywords": [ + "html" + ], + "support": { + "issues": "https://github.com/ezyang/htmlpurifier/issues", + "source": "https://github.com/ezyang/htmlpurifier/tree/master" + }, + "install-path": "../ezyang/htmlpurifier" + }, + { + "name": "fiskaly/fiskaly-sdk-php", + "version": "1.2.100", + "version_normalized": "1.2.100.0", + "source": { + "type": "git", + "url": "https://github.com/fiskaly/fiskaly-sdk-php.git", + "reference": "f2598d32f51ca18f81615df2b63deff7d9569097" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/fiskaly/fiskaly-sdk-php/zipball/f2598d32f51ca18f81615df2b63deff7d9569097", + "reference": "f2598d32f51ca18f81615df2b63deff7d9569097", + "shasum": "" + }, + "require": { + "datto/json-rpc-http": "*", + "ext-json": "*", + "php": ">=7.1" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "^2.16", + "phpunit/phpunit": "^9.1" + }, + "time": "2020-08-19T12:28:28+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "FiskalyClient\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "fiskaly Cloud-TSE SDK for PHP", + "homepage": "https://github.com/fiskaly/fiskaly-sdk-php", + "keywords": [ + "fiskaly", + "php", + "src" + ], + "support": { + "issues": "https://github.com/fiskaly/fiskaly-sdk-php/issues", + "source": "https://github.com/fiskaly/fiskaly-sdk-php/tree/master" + }, + "abandoned": true, + "install-path": "../fiskaly/fiskaly-sdk-php" + }, + { + "name": "guzzlehttp/guzzle", + "version": "6.5.8", + "version_normalized": "6.5.8.0", + "source": { + "type": "git", + "url": "https://github.com/guzzle/guzzle.git", + "reference": "a52f0440530b54fa079ce76e8c5d196a42cad981" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/guzzle/zipball/a52f0440530b54fa079ce76e8c5d196a42cad981", + "reference": "a52f0440530b54fa079ce76e8c5d196a42cad981", + "shasum": "" + }, + "require": { + "ext-json": "*", + "guzzlehttp/promises": "^1.0", + "guzzlehttp/psr7": "^1.9", + "php": ">=5.5", + "symfony/polyfill-intl-idn": "^1.17" + }, + "require-dev": { + "ext-curl": "*", + "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.4 || ^7.0", + "psr/log": "^1.1" + }, + "suggest": { + "psr/log": "Required for using the Log middleware" + }, + "time": "2022-06-20T22:16:07+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "6.5-dev" + } + }, + "installation-source": "dist", + "autoload": { + "files": [ + "src/functions_include.php" + ], + "psr-4": { + "GuzzleHttp\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ { - "name": "aws/aws-sdk-php", - "version": "3.175.2", - "version_normalized": "3.175.2.0", - "source": { - "type": "git", - "url": "https://github.com/aws/aws-sdk-php.git", - "reference": "a8e88eac60b403ed76643327e74f55831570a64b" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/a8e88eac60b403ed76643327e74f55831570a64b", - "reference": "a8e88eac60b403ed76643327e74f55831570a64b", - "shasum": "" - }, - "require": { - "ext-json": "*", - "ext-pcre": "*", - "ext-simplexml": "*", - "guzzlehttp/guzzle": "^5.3.3|^6.2.1|^7.0", - "guzzlehttp/promises": "^1.4.0", - "guzzlehttp/psr7": "^1.7.0", - "mtdowling/jmespath.php": "^2.6", - "php": ">=5.5" - }, - "require-dev": { - "andrewsville/php-token-reflection": "^1.4", - "aws/aws-php-sns-message-validator": "~1.0", - "behat/behat": "~3.0", - "doctrine/cache": "~1.4", - "ext-dom": "*", - "ext-openssl": "*", - "ext-pcntl": "*", - "ext-sockets": "*", - "nette/neon": "^2.3", - "paragonie/random_compat": ">= 2", - "phpunit/phpunit": "^4.8.35|^5.4.3", - "psr/cache": "^1.0", - "psr/simple-cache": "^1.0", - "sebastian/comparator": "^1.2.3" - }, - "suggest": { - "aws/aws-php-sns-message-validator": "To validate incoming SNS notifications", - "doctrine/cache": "To use the DoctrineCacheAdapter", - "ext-curl": "To send requests using cURL", - "ext-openssl": "Allows working with CloudFront private distributions and verifying received SNS messages", - "ext-sockets": "To use client-side monitoring" - }, - "time": "2021-03-23T18:18:49+00:00", - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.0-dev" - } - }, - "installation-source": "dist", - "autoload": { - "psr-4": { - "Aws\\": "src/" - }, - "files": [ - "src/functions.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "Apache-2.0" - ], - "authors": [ - { - "name": "Amazon Web Services", - "homepage": "http://aws.amazon.com" - } - ], - "description": "AWS SDK for PHP - Use Amazon Web Services in your PHP project", - "homepage": "http://aws.amazon.com/sdkforphp", - "keywords": [ - "amazon", - "aws", - "cloud", - "dynamodb", - "ec2", - "glacier", - "s3", - "sdk" - ], - "support": { - "forum": "https://forums.aws.amazon.com/forum.jspa?forumID=80", - "issues": "https://github.com/aws/aws-sdk-php/issues", - "source": "https://github.com/aws/aws-sdk-php/tree/3.175.2" - }, - "install-path": "../aws/aws-sdk-php" + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" }, { - "name": "datto/json-rpc", - "version": "6.1.0", - "version_normalized": "6.1.0.0", - "source": { - "type": "git", - "url": "https://github.com/datto/php-json-rpc.git", - "reference": "ad4d735f48d80c6b53f7405e5007d97c996533f6" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/datto/php-json-rpc/zipball/ad4d735f48d80c6b53f7405e5007d97c996533f6", - "reference": "ad4d735f48d80c6b53f7405e5007d97c996533f6", - "shasum": "" - }, - "require": { - "php": ">=7.0.0" - }, - "require-dev": { - "phpunit/phpunit": "^6.5" - }, - "time": "2020-02-28T23:54:06+00:00", - "type": "library", - "installation-source": "dist", - "autoload": { - "psr-4": { - "Datto\\JsonRpc\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "LGPL-3.0+" - ], - "authors": [ - { - "name": "Spencer Mortensen", - "email": "smortensen@datto.com", - "homepage": "http://spencermortensen.com", - "role": "Developer" - } - ], - "description": "Fully unit-tested JSON-RPC 2.0 for PHP", - "homepage": "http://datto.com", - "keywords": [ - "json", - "json-rpc", - "jsonrpc", - "php", - "php-json-rpc", - "rpc" - ], - "support": { - "issues": "https://github.com/datto/php-json-rpc/issues", - "source": "https://github.com/datto/php-json-rpc/tree/6.1.0" - }, - "install-path": "../datto/json-rpc" + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" }, { - "name": "datto/json-rpc-http", - "version": "5.0.6", - "version_normalized": "5.0.6.0", - "source": { - "type": "git", - "url": "https://github.com/datto/php-json-rpc-http.git", - "reference": "db15a075f3562c4e8d297b9082acc5b2869bd4b4" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/datto/php-json-rpc-http/zipball/db15a075f3562c4e8d297b9082acc5b2869bd4b4", - "reference": "db15a075f3562c4e8d297b9082acc5b2869bd4b4", - "shasum": "" - }, - "require": { - "datto/json-rpc": "~6.1", - "php": ">=7.0.0" - }, - "time": "2020-03-02T21:27:10+00:00", - "type": "library", - "installation-source": "dist", - "autoload": { - "psr-4": { - "Datto\\JsonRpc\\Http\\Examples\\": "examples/src", - "Datto\\JsonRpc\\Http\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "LGPL-3.0+" - ], - "authors": [ - { - "name": "Spencer Mortensen", - "email": "smortensen@datto.com", - "homepage": "http://spencermortensen.com", - "role": "Developer" - } - ], - "description": "HTTP client and server for JSON-RPC 2.0", - "homepage": "http://datto.com", - "keywords": [ - "client", - "http", - "json", - "json-rpc", - "jsonrpc", - "php", - "php-json-rpc", - "rpc", - "server" - ], - "support": { - "issues": "https://github.com/datto/php-json-rpc-http/issues", - "source": "https://github.com/datto/php-json-rpc-http/tree/master" - }, - "install-path": "../datto/json-rpc-http" + "name": "Jeremy Lindblom", + "email": "jeremeamia@gmail.com", + "homepage": "https://github.com/jeremeamia" }, { - "name": "ezyang/htmlpurifier", - "version": "v4.13.0", - "version_normalized": "4.13.0.0", - "source": { - "type": "git", - "url": "https://github.com/ezyang/htmlpurifier.git", - "reference": "08e27c97e4c6ed02f37c5b2b20488046c8d90d75" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/ezyang/htmlpurifier/zipball/08e27c97e4c6ed02f37c5b2b20488046c8d90d75", - "reference": "08e27c97e4c6ed02f37c5b2b20488046c8d90d75", - "shasum": "" - }, - "require": { - "php": ">=5.2" - }, - "require-dev": { - "simpletest/simpletest": "dev-master#72de02a7b80c6bb8864ef9bf66d41d2f58f826bd" - }, - "time": "2020-06-29T00:56:53+00:00", - "type": "library", - "installation-source": "dist", - "autoload": { - "psr-0": { - "HTMLPurifier": "library/" - }, - "files": [ - "library/HTMLPurifier.composer.php" - ], - "exclude-from-classmap": [ - "/library/HTMLPurifier/Language/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "LGPL-2.1-or-later" - ], - "authors": [ - { - "name": "Edward Z. Yang", - "email": "admin@htmlpurifier.org", - "homepage": "http://ezyang.com" - } - ], - "description": "Standards compliant HTML filter written in PHP", - "homepage": "http://htmlpurifier.org/", - "keywords": [ - "html" - ], - "support": { - "issues": "https://github.com/ezyang/htmlpurifier/issues", - "source": "https://github.com/ezyang/htmlpurifier/tree/master" - }, - "install-path": "../ezyang/htmlpurifier" + "name": "George Mponos", + "email": "gmponos@gmail.com", + "homepage": "https://github.com/gmponos" }, { - "name": "fiskaly/fiskaly-sdk-php", - "version": "1.2.100", - "version_normalized": "1.2.100.0", - "source": { - "type": "git", - "url": "https://github.com/fiskaly/fiskaly-sdk-php.git", - "reference": "f2598d32f51ca18f81615df2b63deff7d9569097" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/fiskaly/fiskaly-sdk-php/zipball/f2598d32f51ca18f81615df2b63deff7d9569097", - "reference": "f2598d32f51ca18f81615df2b63deff7d9569097", - "shasum": "" - }, - "require": { - "datto/json-rpc-http": "*", - "ext-json": "*", - "php": ">=7.1" - }, - "require-dev": { - "friendsofphp/php-cs-fixer": "^2.16", - "phpunit/phpunit": "^9.1" - }, - "time": "2020-08-19T12:28:28+00:00", - "type": "library", - "installation-source": "dist", - "autoload": { - "psr-4": { - "FiskalyClient\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "fiskaly Cloud-TSE SDK for PHP", - "homepage": "https://github.com/fiskaly/fiskaly-sdk-php", - "keywords": [ - "fiskaly", - "php", - "src" - ], - "support": { - "issues": "https://github.com/fiskaly/fiskaly-sdk-php/issues", - "source": "https://github.com/fiskaly/fiskaly-sdk-php/tree/v1.2.100" - }, - "install-path": "../fiskaly/fiskaly-sdk-php" + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com", + "homepage": "https://github.com/Nyholm" }, { - "name": "guzzlehttp/guzzle", - "version": "6.5.8", - "version_normalized": "6.5.8.0", - "source": { - "type": "git", - "url": "https://github.com/guzzle/guzzle.git", - "reference": "a52f0440530b54fa079ce76e8c5d196a42cad981" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/guzzle/guzzle/zipball/a52f0440530b54fa079ce76e8c5d196a42cad981", - "reference": "a52f0440530b54fa079ce76e8c5d196a42cad981", - "shasum": "" - }, - "require": { - "ext-json": "*", - "guzzlehttp/promises": "^1.0", - "guzzlehttp/psr7": "^1.9", - "php": ">=5.5", - "symfony/polyfill-intl-idn": "^1.17" - }, - "require-dev": { - "ext-curl": "*", - "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.4 || ^7.0", - "psr/log": "^1.1" - }, - "suggest": { - "psr/log": "Required for using the Log middleware" - }, - "time": "2022-06-20T22:16:07+00:00", - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "6.5-dev" - } - }, - "installation-source": "dist", - "autoload": { - "files": [ - "src/functions_include.php" - ], - "psr-4": { - "GuzzleHttp\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Graham Campbell", - "email": "hello@gjcampbell.co.uk", - "homepage": "https://github.com/GrahamCampbell" - }, - { - "name": "Michael Dowling", - "email": "mtdowling@gmail.com", - "homepage": "https://github.com/mtdowling" - }, - { - "name": "Jeremy Lindblom", - "email": "jeremeamia@gmail.com", - "homepage": "https://github.com/jeremeamia" - }, - { - "name": "George Mponos", - "email": "gmponos@gmail.com", - "homepage": "https://github.com/gmponos" - }, - { - "name": "Tobias Nyholm", - "email": "tobias.nyholm@gmail.com", - "homepage": "https://github.com/Nyholm" - }, - { - "name": "Márk Sági-Kazár", - "email": "mark.sagikazar@gmail.com", - "homepage": "https://github.com/sagikazarmark" - }, - { - "name": "Tobias Schultze", - "email": "webmaster@tubo-world.de", - "homepage": "https://github.com/Tobion" - } - ], - "description": "Guzzle is a PHP HTTP client library", - "homepage": "http://guzzlephp.org/", - "keywords": [ - "client", - "curl", - "framework", - "http", - "http client", - "rest", - "web service" - ], - "support": { - "issues": "https://github.com/guzzle/guzzle/issues", - "source": "https://github.com/guzzle/guzzle/tree/6.5.8" - }, - "funding": [ - { - "url": "https://github.com/GrahamCampbell", - "type": "github" - }, - { - "url": "https://github.com/Nyholm", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/guzzle", - "type": "tidelift" - } - ], - "install-path": "../guzzlehttp/guzzle" + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com", + "homepage": "https://github.com/sagikazarmark" }, { - "name": "guzzlehttp/promises", - "version": "1.5.3", - "version_normalized": "1.5.3.0", - "source": { - "type": "git", - "url": "https://github.com/guzzle/promises.git", - "reference": "67ab6e18aaa14d753cc148911d273f6e6cb6721e" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/guzzle/promises/zipball/67ab6e18aaa14d753cc148911d273f6e6cb6721e", - "reference": "67ab6e18aaa14d753cc148911d273f6e6cb6721e", - "shasum": "" - }, - "require": { - "php": ">=5.5" - }, - "require-dev": { - "symfony/phpunit-bridge": "^4.4 || ^5.1" - }, - "time": "2023-05-21T12:31:43+00:00", - "type": "library", - "installation-source": "dist", - "autoload": { - "files": [ - "src/functions_include.php" - ], - "psr-4": { - "GuzzleHttp\\Promise\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Graham Campbell", - "email": "hello@gjcampbell.co.uk", - "homepage": "https://github.com/GrahamCampbell" - }, - { - "name": "Michael Dowling", - "email": "mtdowling@gmail.com", - "homepage": "https://github.com/mtdowling" - }, - { - "name": "Tobias Nyholm", - "email": "tobias.nyholm@gmail.com", - "homepage": "https://github.com/Nyholm" - }, - { - "name": "Tobias Schultze", - "email": "webmaster@tubo-world.de", - "homepage": "https://github.com/Tobion" - } - ], - "description": "Guzzle promises library", - "keywords": [ - "promise" - ], - "support": { - "issues": "https://github.com/guzzle/promises/issues", - "source": "https://github.com/guzzle/promises/tree/1.5.3" - }, - "funding": [ - { - "url": "https://github.com/GrahamCampbell", - "type": "github" - }, - { - "url": "https://github.com/Nyholm", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/promises", - "type": "tidelift" - } - ], - "install-path": "../guzzlehttp/promises" + "name": "Tobias Schultze", + "email": "webmaster@tubo-world.de", + "homepage": "https://github.com/Tobion" + } + ], + "description": "Guzzle is a PHP HTTP client library", + "homepage": "http://guzzlephp.org/", + "keywords": [ + "client", + "curl", + "framework", + "http", + "http client", + "rest", + "web service" + ], + "support": { + "issues": "https://github.com/guzzle/guzzle/issues", + "source": "https://github.com/guzzle/guzzle/tree/6.5.8" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" }, { - "name": "guzzlehttp/psr7", - "version": "1.9.1", - "version_normalized": "1.9.1.0", - "source": { - "type": "git", - "url": "https://github.com/guzzle/psr7.git", - "reference": "e4490cabc77465aaee90b20cfc9a770f8c04be6b" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/guzzle/psr7/zipball/e4490cabc77465aaee90b20cfc9a770f8c04be6b", - "reference": "e4490cabc77465aaee90b20cfc9a770f8c04be6b", - "shasum": "" - }, - "require": { - "php": ">=5.4.0", - "psr/http-message": "~1.0", - "ralouphie/getallheaders": "^2.0.5 || ^3.0.0" - }, - "provide": { - "psr/http-message-implementation": "1.0" - }, - "require-dev": { - "ext-zlib": "*", - "phpunit/phpunit": "~4.8.36 || ^5.7.27 || ^6.5.14 || ^7.5.20 || ^8.5.8 || ^9.3.10" - }, - "suggest": { - "laminas/laminas-httphandlerrunner": "Emit PSR-7 responses" - }, - "time": "2023-04-17T16:00:37+00:00", - "type": "library", - "installation-source": "dist", - "autoload": { - "files": [ - "src/functions_include.php" - ], - "psr-4": { - "GuzzleHttp\\Psr7\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Graham Campbell", - "email": "hello@gjcampbell.co.uk", - "homepage": "https://github.com/GrahamCampbell" - }, - { - "name": "Michael Dowling", - "email": "mtdowling@gmail.com", - "homepage": "https://github.com/mtdowling" - }, - { - "name": "George Mponos", - "email": "gmponos@gmail.com", - "homepage": "https://github.com/gmponos" - }, - { - "name": "Tobias Nyholm", - "email": "tobias.nyholm@gmail.com", - "homepage": "https://github.com/Nyholm" - }, - { - "name": "Márk Sági-Kazár", - "email": "mark.sagikazar@gmail.com", - "homepage": "https://github.com/sagikazarmark" - }, - { - "name": "Tobias Schultze", - "email": "webmaster@tubo-world.de", - "homepage": "https://github.com/Tobion" - } - ], - "description": "PSR-7 message implementation that also provides common utility methods", - "keywords": [ - "http", - "message", - "psr-7", - "request", - "response", - "stream", - "uri", - "url" - ], - "support": { - "issues": "https://github.com/guzzle/psr7/issues", - "source": "https://github.com/guzzle/psr7/tree/1.9.1" - }, - "funding": [ - { - "url": "https://github.com/GrahamCampbell", - "type": "github" - }, - { - "url": "https://github.com/Nyholm", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/psr7", - "type": "tidelift" - } - ], - "install-path": "../guzzlehttp/psr7" + "url": "https://github.com/Nyholm", + "type": "github" }, { - "name": "laminas/laminas-loader", - "version": "2.11.1", - "version_normalized": "2.11.1.0", - "source": { - "type": "git", - "url": "https://github.com/laminas/laminas-loader.git", - "reference": "c507d5eccb969f7208434e3980680a1f6c0b1d8d" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/laminas/laminas-loader/zipball/c507d5eccb969f7208434e3980680a1f6c0b1d8d", - "reference": "c507d5eccb969f7208434e3980680a1f6c0b1d8d", - "shasum": "" - }, - "require": { - "php": "~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0" - }, - "conflict": { - "zendframework/zend-loader": "*" - }, - "require-dev": { - "laminas/laminas-coding-standard": "~2.4.0", - "phpunit/phpunit": "~9.5.25" - }, - "time": "2024-12-05T14:43:32+00:00", - "type": "library", - "installation-source": "dist", - "autoload": { - "psr-4": { - "Laminas\\Loader\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "description": "Autoloading and plugin loading strategies", - "homepage": "https://laminas.dev", - "keywords": [ - "laminas", - "loader" - ], - "support": { - "chat": "https://laminas.dev/chat", - "docs": "https://docs.laminas.dev/laminas-loader/", - "forum": "https://discourse.laminas.dev", - "issues": "https://github.com/laminas/laminas-loader/issues", - "rss": "https://github.com/laminas/laminas-loader/releases.atom", - "source": "https://github.com/laminas/laminas-loader" - }, - "funding": [ - { - "url": "https://funding.communitybridge.org/projects/laminas-project", - "type": "community_bridge" - } - ], - "abandoned": true, - "install-path": "../laminas/laminas-loader" + "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/guzzle", + "type": "tidelift" + } + ], + "install-path": "../guzzlehttp/guzzle" + }, + { + "name": "guzzlehttp/promises", + "version": "1.5.3", + "version_normalized": "1.5.3.0", + "source": { + "type": "git", + "url": "https://github.com/guzzle/promises.git", + "reference": "67ab6e18aaa14d753cc148911d273f6e6cb6721e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/promises/zipball/67ab6e18aaa14d753cc148911d273f6e6cb6721e", + "reference": "67ab6e18aaa14d753cc148911d273f6e6cb6721e", + "shasum": "" + }, + "require": { + "php": ">=5.5" + }, + "require-dev": { + "symfony/phpunit-bridge": "^4.4 || ^5.1" + }, + "time": "2023-05-21T12:31:43+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "files": [ + "src/functions_include.php" + ], + "psr-4": { + "GuzzleHttp\\Promise\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" }, { - "name": "laminas/laminas-mail", - "version": "2.25.1", - "version_normalized": "2.25.1.0", - "source": { - "type": "git", - "url": "https://github.com/laminas/laminas-mail.git", - "reference": "110e04497395123998220e244cceecb167cc6dda" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/laminas/laminas-mail/zipball/110e04497395123998220e244cceecb167cc6dda", - "reference": "110e04497395123998220e244cceecb167cc6dda", - "shasum": "" - }, - "require": { - "ext-iconv": "*", - "laminas/laminas-loader": "^2.9.0", - "laminas/laminas-mime": "^2.11.0", - "laminas/laminas-stdlib": "^3.17.0", - "laminas/laminas-validator": "^2.31.0", - "php": "~8.1.0 || ~8.2.0 || ~8.3.0", - "symfony/polyfill-intl-idn": "^1.27.0", - "symfony/polyfill-mbstring": "^1.27.0", - "webmozart/assert": "^1.11.0" - }, - "require-dev": { - "laminas/laminas-coding-standard": "~2.5.0", - "laminas/laminas-db": "^2.18", - "laminas/laminas-servicemanager": "^3.22.1", - "phpunit/phpunit": "^10.4.2", - "psalm/plugin-phpunit": "^0.18.4", - "symfony/process": "^6.3.4", - "vimeo/psalm": "^5.15" - }, - "suggest": { - "laminas/laminas-servicemanager": "^3.21 when using SMTP to deliver messages" - }, - "time": "2023-11-02T10:32:34+00:00", - "type": "library", - "extra": { - "laminas": { - "component": "Laminas\\Mail", - "config-provider": "Laminas\\Mail\\ConfigProvider" - } - }, - "installation-source": "dist", - "autoload": { - "psr-4": { - "Laminas\\Mail\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "description": "Provides generalized functionality to compose and send both text and MIME-compliant multipart e-mail messages", - "homepage": "https://laminas.dev", - "keywords": [ - "laminas", - "mail" - ], - "support": { - "chat": "https://laminas.dev/chat", - "docs": "https://docs.laminas.dev/laminas-mail/", - "forum": "https://discourse.laminas.dev", - "issues": "https://github.com/laminas/laminas-mail/issues", - "rss": "https://github.com/laminas/laminas-mail/releases.atom", - "source": "https://github.com/laminas/laminas-mail" - }, - "funding": [ - { - "url": "https://funding.communitybridge.org/projects/laminas-project", - "type": "community_bridge" - } - ], - "abandoned": "symfony/mailer", - "install-path": "../laminas/laminas-mail" + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" }, { - "name": "laminas/laminas-mime", - "version": "2.12.0", - "version_normalized": "2.12.0.0", - "source": { - "type": "git", - "url": "https://github.com/laminas/laminas-mime.git", - "reference": "08cc544778829b7d68d27a097885bd6e7130135e" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/laminas/laminas-mime/zipball/08cc544778829b7d68d27a097885bd6e7130135e", - "reference": "08cc544778829b7d68d27a097885bd6e7130135e", - "shasum": "" - }, - "require": { - "laminas/laminas-stdlib": "^2.7 || ^3.0", - "php": "~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0" - }, - "conflict": { - "zendframework/zend-mime": "*" - }, - "require-dev": { - "laminas/laminas-coding-standard": "~2.4.0", - "laminas/laminas-mail": "^2.19.0", - "phpunit/phpunit": "~9.5.25" - }, - "suggest": { - "laminas/laminas-mail": "Laminas\\Mail component" - }, - "time": "2023-11-02T16:47:19+00:00", - "type": "library", - "installation-source": "dist", - "autoload": { - "psr-4": { - "Laminas\\Mime\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "description": "Create and parse MIME messages and parts", - "homepage": "https://laminas.dev", - "keywords": [ - "laminas", - "mime" - ], - "support": { - "chat": "https://laminas.dev/chat", - "docs": "https://docs.laminas.dev/laminas-mime/", - "forum": "https://discourse.laminas.dev", - "issues": "https://github.com/laminas/laminas-mime/issues", - "rss": "https://github.com/laminas/laminas-mime/releases.atom", - "source": "https://github.com/laminas/laminas-mime" - }, - "funding": [ - { - "url": "https://funding.communitybridge.org/projects/laminas-project", - "type": "community_bridge" - } - ], - "abandoned": "symfony/mime", - "install-path": "../laminas/laminas-mime" + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com", + "homepage": "https://github.com/Nyholm" }, { - "name": "laminas/laminas-servicemanager", - "version": "3.23.0", - "version_normalized": "3.23.0.0", - "source": { - "type": "git", - "url": "https://github.com/laminas/laminas-servicemanager.git", - "reference": "a8640182b892b99767d54404d19c5c3b3699f79b" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/laminas/laminas-servicemanager/zipball/a8640182b892b99767d54404d19c5c3b3699f79b", - "reference": "a8640182b892b99767d54404d19c5c3b3699f79b", - "shasum": "" - }, - "require": { - "laminas/laminas-stdlib": "^3.19", - "php": "~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0", - "psr/container": "^1.0" - }, - "conflict": { - "ext-psr": "*", - "laminas/laminas-code": "<4.10.0", - "zendframework/zend-code": "<3.3.1", - "zendframework/zend-servicemanager": "*" - }, - "provide": { - "psr/container-implementation": "^1.0" - }, - "replace": { - "container-interop/container-interop": "^1.2.0" - }, - "require-dev": { - "composer/package-versions-deprecated": "^1.11.99.5", - "friendsofphp/proxy-manager-lts": "^1.0.18", - "laminas/laminas-code": "^4.14.0", - "laminas/laminas-coding-standard": "~2.5.0", - "laminas/laminas-container-config-test": "^0.8", - "mikey179/vfsstream": "^1.6.12", - "phpbench/phpbench": "^1.3.1", - "phpunit/phpunit": "^10.5.36", - "psalm/plugin-phpunit": "^0.18.4", - "vimeo/psalm": "^5.26.1" - }, - "suggest": { - "friendsofphp/proxy-manager-lts": "ProxyManager ^2.1.1 to handle lazy initialization of services" - }, - "time": "2024-10-28T21:32:16+00:00", - "bin": [ - "bin/generate-deps-for-config-factory", - "bin/generate-factory-for-class" - ], - "type": "library", - "installation-source": "dist", - "autoload": { - "files": [ - "src/autoload.php" - ], - "psr-4": { - "Laminas\\ServiceManager\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "description": "Factory-Driven Dependency Injection Container", - "homepage": "https://laminas.dev", - "keywords": [ - "PSR-11", - "dependency-injection", - "di", - "dic", - "laminas", - "service-manager", - "servicemanager" - ], - "support": { - "chat": "https://laminas.dev/chat", - "docs": "https://docs.laminas.dev/laminas-servicemanager/", - "forum": "https://discourse.laminas.dev", - "issues": "https://github.com/laminas/laminas-servicemanager/issues", - "rss": "https://github.com/laminas/laminas-servicemanager/releases.atom", - "source": "https://github.com/laminas/laminas-servicemanager" - }, - "funding": [ - { - "url": "https://funding.communitybridge.org/projects/laminas-project", - "type": "community_bridge" - } - ], - "install-path": "../laminas/laminas-servicemanager" + "name": "Tobias Schultze", + "email": "webmaster@tubo-world.de", + "homepage": "https://github.com/Tobion" + } + ], + "description": "Guzzle promises library", + "keywords": [ + "promise" + ], + "support": { + "issues": "https://github.com/guzzle/promises/issues", + "source": "https://github.com/guzzle/promises/tree/1.5.3" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" }, { - "name": "laminas/laminas-stdlib", - "version": "3.20.0", - "version_normalized": "3.20.0.0", - "source": { - "type": "git", - "url": "https://github.com/laminas/laminas-stdlib.git", - "reference": "8974a1213be42c3e2f70b2c27b17f910291ab2f4" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/laminas/laminas-stdlib/zipball/8974a1213be42c3e2f70b2c27b17f910291ab2f4", - "reference": "8974a1213be42c3e2f70b2c27b17f910291ab2f4", - "shasum": "" - }, - "require": { - "php": "~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0" - }, - "conflict": { - "zendframework/zend-stdlib": "*" - }, - "require-dev": { - "laminas/laminas-coding-standard": "^3.0", - "phpbench/phpbench": "^1.3.1", - "phpunit/phpunit": "^10.5.38", - "psalm/plugin-phpunit": "^0.19.0", - "vimeo/psalm": "^5.26.1" - }, - "time": "2024-10-29T13:46:07+00:00", - "type": "library", - "installation-source": "dist", - "autoload": { - "psr-4": { - "Laminas\\Stdlib\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "description": "SPL extensions, array utilities, error handlers, and more", - "homepage": "https://laminas.dev", - "keywords": [ - "laminas", - "stdlib" - ], - "support": { - "chat": "https://laminas.dev/chat", - "docs": "https://docs.laminas.dev/laminas-stdlib/", - "forum": "https://discourse.laminas.dev", - "issues": "https://github.com/laminas/laminas-stdlib/issues", - "rss": "https://github.com/laminas/laminas-stdlib/releases.atom", - "source": "https://github.com/laminas/laminas-stdlib" - }, - "funding": [ - { - "url": "https://funding.communitybridge.org/projects/laminas-project", - "type": "community_bridge" - } - ], - "install-path": "../laminas/laminas-stdlib" + "url": "https://github.com/Nyholm", + "type": "github" }, { - "name": "laminas/laminas-validator", - "version": "2.64.2", - "version_normalized": "2.64.2.0", - "source": { - "type": "git", - "url": "https://github.com/laminas/laminas-validator.git", - "reference": "771e504760448ac7af660710237ceb93be602e08" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/laminas/laminas-validator/zipball/771e504760448ac7af660710237ceb93be602e08", - "reference": "771e504760448ac7af660710237ceb93be602e08", - "shasum": "" - }, - "require": { - "laminas/laminas-servicemanager": "^3.21.0", - "laminas/laminas-stdlib": "^3.19", - "php": "~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0", - "psr/http-message": "^1.0.1 || ^2.0.0" - }, - "conflict": { - "zendframework/zend-validator": "*" - }, - "require-dev": { - "laminas/laminas-coding-standard": "^2.5", - "laminas/laminas-db": "^2.20", - "laminas/laminas-filter": "^2.35.2", - "laminas/laminas-i18n": "^2.26.0", - "laminas/laminas-session": "^2.20", - "laminas/laminas-uri": "^2.11.0", - "phpunit/phpunit": "^10.5.20", - "psalm/plugin-phpunit": "^0.19.0", - "psr/http-client": "^1.0.3", - "psr/http-factory": "^1.1.0", - "vimeo/psalm": "^5.24.0" - }, - "suggest": { - "laminas/laminas-db": "Laminas\\Db component, required by the (No)RecordExists validator", - "laminas/laminas-filter": "Laminas\\Filter component, required by the Digits validator", - "laminas/laminas-i18n": "Laminas\\I18n component to allow translation of validation error messages", - "laminas/laminas-i18n-resources": "Translations of validator messages", - "laminas/laminas-servicemanager": "Laminas\\ServiceManager component to allow using the ValidatorPluginManager and validator chains", - "laminas/laminas-session": "Laminas\\Session component, ^2.8; required by the Csrf validator", - "laminas/laminas-uri": "Laminas\\Uri component, required by the Uri and Sitemap\\Loc validators", - "psr/http-message": "psr/http-message, required when validating PSR-7 UploadedFileInterface instances via the Upload and UploadFile validators" - }, - "time": "2024-11-26T21:29:17+00:00", - "type": "library", - "extra": { - "laminas": { - "component": "Laminas\\Validator", - "config-provider": "Laminas\\Validator\\ConfigProvider" - } - }, - "installation-source": "dist", - "autoload": { - "psr-4": { - "Laminas\\Validator\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "description": "Validation classes for a wide range of domains, and the ability to chain validators to create complex validation criteria", - "homepage": "https://laminas.dev", - "keywords": [ - "laminas", - "validator" - ], - "support": { - "chat": "https://laminas.dev/chat", - "docs": "https://docs.laminas.dev/laminas-validator/", - "forum": "https://discourse.laminas.dev", - "issues": "https://github.com/laminas/laminas-validator/issues", - "rss": "https://github.com/laminas/laminas-validator/releases.atom", - "source": "https://github.com/laminas/laminas-validator" - }, - "funding": [ - { - "url": "https://funding.communitybridge.org/projects/laminas-project", - "type": "community_bridge" - } - ], - "install-path": "../laminas/laminas-validator" + "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/promises", + "type": "tidelift" + } + ], + "install-path": "../guzzlehttp/promises" + }, + { + "name": "guzzlehttp/psr7", + "version": "1.9.1", + "version_normalized": "1.9.1.0", + "source": { + "type": "git", + "url": "https://github.com/guzzle/psr7.git", + "reference": "e4490cabc77465aaee90b20cfc9a770f8c04be6b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/psr7/zipball/e4490cabc77465aaee90b20cfc9a770f8c04be6b", + "reference": "e4490cabc77465aaee90b20cfc9a770f8c04be6b", + "shasum": "" + }, + "require": { + "php": ">=5.4.0", + "psr/http-message": "~1.0", + "ralouphie/getallheaders": "^2.0.5 || ^3.0.0" + }, + "provide": { + "psr/http-message-implementation": "1.0" + }, + "require-dev": { + "ext-zlib": "*", + "phpunit/phpunit": "~4.8.36 || ^5.7.27 || ^6.5.14 || ^7.5.20 || ^8.5.8 || ^9.3.10" + }, + "suggest": { + "laminas/laminas-httphandlerrunner": "Emit PSR-7 responses" + }, + "time": "2023-04-17T16:00:37+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "files": [ + "src/functions_include.php" + ], + "psr-4": { + "GuzzleHttp\\Psr7\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" }, { - "name": "league/color-extractor", - "version": "0.3.2", - "version_normalized": "0.3.2.0", - "source": { - "type": "git", - "url": "https://github.com/thephpleague/color-extractor.git", - "reference": "837086ec60f50c84c611c613963e4ad2e2aec806" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/thephpleague/color-extractor/zipball/837086ec60f50c84c611c613963e4ad2e2aec806", - "reference": "837086ec60f50c84c611c613963e4ad2e2aec806", - "shasum": "" - }, - "require": { - "ext-gd": "*", - "php": ">=5.4.0" - }, - "replace": { - "matthecat/colorextractor": "*" - }, - "require-dev": { - "friendsofphp/php-cs-fixer": "~2", - "phpunit/phpunit": "~5" - }, - "time": "2016-12-15T09:30:02+00:00", - "type": "library", - "installation-source": "dist", - "autoload": { - "psr-4": { - "": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Mathieu Lechat", - "email": "math.lechat@gmail.com", - "homepage": "http://matthecat.com", - "role": "Developer" - } - ], - "description": "Extract colors from an image as a human would do.", - "homepage": "https://github.com/thephpleague/color-extractor", - "keywords": [ - "color", - "extract", - "human", - "image", - "palette" - ], - "support": { - "issues": "https://github.com/thephpleague/color-extractor/issues", - "source": "https://github.com/thephpleague/color-extractor/tree/master" - }, - "install-path": "../league/color-extractor" + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" }, { - "name": "league/flysystem", - "version": "1.1.10", - "version_normalized": "1.1.10.0", - "source": { - "type": "git", - "url": "https://github.com/thephpleague/flysystem.git", - "reference": "3239285c825c152bcc315fe0e87d6b55f5972ed1" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/3239285c825c152bcc315fe0e87d6b55f5972ed1", - "reference": "3239285c825c152bcc315fe0e87d6b55f5972ed1", - "shasum": "" - }, - "require": { - "ext-fileinfo": "*", - "league/mime-type-detection": "^1.3", - "php": "^7.2.5 || ^8.0" - }, - "conflict": { - "league/flysystem-sftp": "<1.0.6" - }, - "require-dev": { - "phpspec/prophecy": "^1.11.1", - "phpunit/phpunit": "^8.5.8" - }, - "suggest": { - "ext-ftp": "Allows you to use FTP server storage", - "ext-openssl": "Allows you to use FTPS server storage", - "league/flysystem-aws-s3-v2": "Allows you to use S3 storage with AWS SDK v2", - "league/flysystem-aws-s3-v3": "Allows you to use S3 storage with AWS SDK v3", - "league/flysystem-azure": "Allows you to use Windows Azure Blob storage", - "league/flysystem-cached-adapter": "Flysystem adapter decorator for metadata caching", - "league/flysystem-eventable-filesystem": "Allows you to use EventableFilesystem", - "league/flysystem-rackspace": "Allows you to use Rackspace Cloud Files", - "league/flysystem-sftp": "Allows you to use SFTP server storage via phpseclib", - "league/flysystem-webdav": "Allows you to use WebDAV storage", - "league/flysystem-ziparchive": "Allows you to use ZipArchive adapter", - "spatie/flysystem-dropbox": "Allows you to use Dropbox storage", - "srmklive/flysystem-dropbox-v2": "Allows you to use Dropbox storage for PHP 5 applications" - }, - "time": "2022-10-04T09:16:37+00:00", - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.1-dev" - } - }, - "installation-source": "dist", - "autoload": { - "psr-4": { - "League\\Flysystem\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Frank de Jonge", - "email": "info@frenky.net" - } - ], - "description": "Filesystem abstraction: Many filesystems, one API.", - "keywords": [ - "Cloud Files", - "WebDAV", - "abstraction", - "aws", - "cloud", - "copy.com", - "dropbox", - "file systems", - "files", - "filesystem", - "filesystems", - "ftp", - "rackspace", - "remote", - "s3", - "sftp", - "storage" - ], - "support": { - "issues": "https://github.com/thephpleague/flysystem/issues", - "source": "https://github.com/thephpleague/flysystem/tree/1.1.10" - }, - "funding": [ - { - "url": "https://offset.earth/frankdejonge", - "type": "other" - } - ], - "install-path": "../league/flysystem" + "name": "George Mponos", + "email": "gmponos@gmail.com", + "homepage": "https://github.com/gmponos" }, { - "name": "league/mime-type-detection", - "version": "1.16.0", - "version_normalized": "1.16.0.0", - "source": { - "type": "git", - "url": "https://github.com/thephpleague/mime-type-detection.git", - "reference": "2d6702ff215bf922936ccc1ad31007edc76451b9" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/thephpleague/mime-type-detection/zipball/2d6702ff215bf922936ccc1ad31007edc76451b9", - "reference": "2d6702ff215bf922936ccc1ad31007edc76451b9", - "shasum": "" - }, - "require": { - "ext-fileinfo": "*", - "php": "^7.4 || ^8.0" - }, - "require-dev": { - "friendsofphp/php-cs-fixer": "^3.2", - "phpstan/phpstan": "^0.12.68", - "phpunit/phpunit": "^8.5.8 || ^9.3 || ^10.0" - }, - "time": "2024-09-21T08:32:55+00:00", - "type": "library", - "installation-source": "dist", - "autoload": { - "psr-4": { - "League\\MimeTypeDetection\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Frank de Jonge", - "email": "info@frankdejonge.nl" - } - ], - "description": "Mime-type detection for Flysystem", - "support": { - "issues": "https://github.com/thephpleague/mime-type-detection/issues", - "source": "https://github.com/thephpleague/mime-type-detection/tree/1.16.0" - }, - "funding": [ - { - "url": "https://github.com/frankdejonge", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/league/flysystem", - "type": "tidelift" - } - ], - "install-path": "../league/mime-type-detection" + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com", + "homepage": "https://github.com/Nyholm" }, { - "name": "league/oauth1-client", - "version": "v1.9.0", - "version_normalized": "1.9.0.0", - "source": { - "type": "git", - "url": "https://github.com/thephpleague/oauth1-client.git", - "reference": "1e7e6be2dc543bf466236fb171e5b20e1b06aee6" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/thephpleague/oauth1-client/zipball/1e7e6be2dc543bf466236fb171e5b20e1b06aee6", - "reference": "1e7e6be2dc543bf466236fb171e5b20e1b06aee6", - "shasum": "" - }, - "require": { - "ext-json": "*", - "ext-openssl": "*", - "guzzlehttp/guzzle": "^6.0|^7.0", - "php": ">=7.1||>=8.0" - }, - "require-dev": { - "ext-simplexml": "*", - "friendsofphp/php-cs-fixer": "^2.17", - "mockery/mockery": "^1.3.3", - "phpstan/phpstan": "^0.12.42", - "phpunit/phpunit": "^7.5||9.5" - }, - "suggest": { - "ext-simplexml": "For decoding XML-based responses." - }, - "time": "2021-01-20T01:40:53+00:00", - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0-dev", - "dev-develop": "2.0-dev" - } - }, - "installation-source": "dist", - "autoload": { - "psr-4": { - "League\\OAuth1\\Client\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Ben Corlett", - "email": "bencorlett@me.com", - "homepage": "http://www.webcomm.com.au", - "role": "Developer" - } - ], - "description": "OAuth 1.0 Client Library", - "keywords": [ - "Authentication", - "SSO", - "authorization", - "bitbucket", - "identity", - "idp", - "oauth", - "oauth1", - "single sign on", - "trello", - "tumblr", - "twitter" - ], - "support": { - "issues": "https://github.com/thephpleague/oauth1-client/issues", - "source": "https://github.com/thephpleague/oauth1-client/tree/v1.9.0" - }, - "install-path": "../league/oauth1-client" + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com", + "homepage": "https://github.com/sagikazarmark" }, { - "name": "lfkeitel/phptotp", - "version": "v1.1.0", - "version_normalized": "1.1.0.0", - "source": { - "type": "git", - "url": "https://github.com/lfkeitel/php-totp.git", - "reference": "5b1673e895f857856b3e75ccb442855771c9b9be" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/lfkeitel/php-totp/zipball/5b1673e895f857856b3e75ccb442855771c9b9be", - "reference": "5b1673e895f857856b3e75ccb442855771c9b9be", - "shasum": "" - }, - "require": { - "php": "^5.6 || ^7.0 || ^8.0" - }, - "time": "2022-04-07T20:52:00+00:00", - "type": "library", - "installation-source": "dist", - "autoload": { - "psr-4": { - "lfkeitel\\phptotp\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "TOTP/HOTP library for PHP", - "keywords": [ - "Authentication", - "hotp", - "totp", - "two-factor" - ], - "support": { - "issues": "https://github.com/lfkeitel/php-totp/issues", - "source": "https://github.com/lfkeitel/php-totp/tree/v1.1.0" - }, - "install-path": "../lfkeitel/phptotp" + "name": "Tobias Schultze", + "email": "webmaster@tubo-world.de", + "homepage": "https://github.com/Tobion" + } + ], + "description": "PSR-7 message implementation that also provides common utility methods", + "keywords": [ + "http", + "message", + "psr-7", + "request", + "response", + "stream", + "uri", + "url" + ], + "support": { + "issues": "https://github.com/guzzle/psr7/issues", + "source": "https://github.com/guzzle/psr7/tree/1.9.1" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" }, { - "name": "mtdowling/jmespath.php", - "version": "2.8.0", - "version_normalized": "2.8.0.0", - "source": { - "type": "git", - "url": "https://github.com/jmespath/jmespath.php.git", - "reference": "a2a865e05d5f420b50cc2f85bb78d565db12a6bc" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/jmespath/jmespath.php/zipball/a2a865e05d5f420b50cc2f85bb78d565db12a6bc", - "reference": "a2a865e05d5f420b50cc2f85bb78d565db12a6bc", - "shasum": "" - }, - "require": { - "php": "^7.2.5 || ^8.0", - "symfony/polyfill-mbstring": "^1.17" - }, - "require-dev": { - "composer/xdebug-handler": "^3.0.3", - "phpunit/phpunit": "^8.5.33" - }, - "time": "2024-09-04T18:46:31+00:00", - "bin": [ - "bin/jp.php" - ], - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.8-dev" - } - }, - "installation-source": "dist", - "autoload": { - "files": [ - "src/JmesPath.php" - ], - "psr-4": { - "JmesPath\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Graham Campbell", - "email": "hello@gjcampbell.co.uk", - "homepage": "https://github.com/GrahamCampbell" - }, - { - "name": "Michael Dowling", - "email": "mtdowling@gmail.com", - "homepage": "https://github.com/mtdowling" - } - ], - "description": "Declaratively specify how to extract elements from a JSON document", - "keywords": [ - "json", - "jsonpath" - ], - "support": { - "issues": "https://github.com/jmespath/jmespath.php/issues", - "source": "https://github.com/jmespath/jmespath.php/tree/2.8.0" - }, - "install-path": "../mtdowling/jmespath.php" + "url": "https://github.com/Nyholm", + "type": "github" }, { - "name": "nikic/fast-route", - "version": "v1.3.0", - "version_normalized": "1.3.0.0", - "source": { - "type": "git", - "url": "https://github.com/nikic/FastRoute.git", - "reference": "181d480e08d9476e61381e04a71b34dc0432e812" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/nikic/FastRoute/zipball/181d480e08d9476e61381e04a71b34dc0432e812", - "reference": "181d480e08d9476e61381e04a71b34dc0432e812", - "shasum": "" - }, - "require": { - "php": ">=5.4.0" - }, - "require-dev": { - "phpunit/phpunit": "^4.8.35|~5.7" - }, - "time": "2018-02-13T20:26:39+00:00", - "type": "library", - "installation-source": "dist", - "autoload": { - "psr-4": { - "FastRoute\\": "src/" - }, - "files": [ - "src/functions.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Nikita Popov", - "email": "nikic@php.net" - } - ], - "description": "Fast request router for PHP", - "keywords": [ - "router", - "routing" - ], - "support": { - "issues": "https://github.com/nikic/FastRoute/issues", - "source": "https://github.com/nikic/FastRoute/tree/master" - }, - "install-path": "../nikic/fast-route" + "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/psr7", + "type": "tidelift" + } + ], + "install-path": "../guzzlehttp/psr7" + }, + { + "name": "laminas/laminas-loader", + "version": "2.12.0", + "version_normalized": "2.12.0.0", + "source": { + "type": "git", + "url": "https://github.com/laminas/laminas-loader.git", + "reference": "ec8cee33fb254ee4d9c8e8908c870e5c797e1272" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/laminas/laminas-loader/zipball/ec8cee33fb254ee4d9c8e8908c870e5c797e1272", + "reference": "ec8cee33fb254ee4d9c8e8908c870e5c797e1272", + "shasum": "" + }, + "require": { + "php": "^8.0.0" + }, + "conflict": { + "zendframework/zend-loader": "*" + }, + "require-dev": { + "laminas/laminas-coding-standard": "~2.4.0", + "phpunit/phpunit": "~9.5.25" + }, + "time": "2025-12-30T11:30:39+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "Laminas\\Loader\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "description": "Autoloading and plugin loading strategies", + "homepage": "https://laminas.dev", + "keywords": [ + "laminas", + "loader" + ], + "support": { + "chat": "https://laminas.dev/chat", + "docs": "https://docs.laminas.dev/laminas-loader/", + "forum": "https://discourse.laminas.dev", + "issues": "https://github.com/laminas/laminas-loader/issues", + "rss": "https://github.com/laminas/laminas-loader/releases.atom", + "source": "https://github.com/laminas/laminas-loader" + }, + "funding": [ + { + "url": "https://funding.communitybridge.org/projects/laminas-project", + "type": "community_bridge" + } + ], + "abandoned": true, + "install-path": "../laminas/laminas-loader" + }, + { + "name": "laminas/laminas-mail", + "version": "2.25.1", + "version_normalized": "2.25.1.0", + "source": { + "type": "git", + "url": "https://github.com/laminas/laminas-mail.git", + "reference": "110e04497395123998220e244cceecb167cc6dda" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/laminas/laminas-mail/zipball/110e04497395123998220e244cceecb167cc6dda", + "reference": "110e04497395123998220e244cceecb167cc6dda", + "shasum": "" + }, + "require": { + "ext-iconv": "*", + "laminas/laminas-loader": "^2.9.0", + "laminas/laminas-mime": "^2.11.0", + "laminas/laminas-stdlib": "^3.17.0", + "laminas/laminas-validator": "^2.31.0", + "php": "~8.1.0 || ~8.2.0 || ~8.3.0", + "symfony/polyfill-intl-idn": "^1.27.0", + "symfony/polyfill-mbstring": "^1.27.0", + "webmozart/assert": "^1.11.0" + }, + "require-dev": { + "laminas/laminas-coding-standard": "~2.5.0", + "laminas/laminas-db": "^2.18", + "laminas/laminas-servicemanager": "^3.22.1", + "phpunit/phpunit": "^10.4.2", + "psalm/plugin-phpunit": "^0.18.4", + "symfony/process": "^6.3.4", + "vimeo/psalm": "^5.15" + }, + "suggest": { + "laminas/laminas-servicemanager": "^3.21 when using SMTP to deliver messages" + }, + "time": "2023-11-02T10:32:34+00:00", + "type": "library", + "extra": { + "laminas": { + "component": "Laminas\\Mail", + "config-provider": "Laminas\\Mail\\ConfigProvider" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Laminas\\Mail\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "description": "Provides generalized functionality to compose and send both text and MIME-compliant multipart e-mail messages", + "homepage": "https://laminas.dev", + "keywords": [ + "laminas", + "mail" + ], + "support": { + "chat": "https://laminas.dev/chat", + "docs": "https://docs.laminas.dev/laminas-mail/", + "forum": "https://discourse.laminas.dev", + "issues": "https://github.com/laminas/laminas-mail/issues", + "rss": "https://github.com/laminas/laminas-mail/releases.atom", + "source": "https://github.com/laminas/laminas-mail" + }, + "funding": [ + { + "url": "https://funding.communitybridge.org/projects/laminas-project", + "type": "community_bridge" + } + ], + "abandoned": "symfony/mailer", + "install-path": "../laminas/laminas-mail" + }, + { + "name": "laminas/laminas-mime", + "version": "2.12.0", + "version_normalized": "2.12.0.0", + "source": { + "type": "git", + "url": "https://github.com/laminas/laminas-mime.git", + "reference": "08cc544778829b7d68d27a097885bd6e7130135e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/laminas/laminas-mime/zipball/08cc544778829b7d68d27a097885bd6e7130135e", + "reference": "08cc544778829b7d68d27a097885bd6e7130135e", + "shasum": "" + }, + "require": { + "laminas/laminas-stdlib": "^2.7 || ^3.0", + "php": "~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0" + }, + "conflict": { + "zendframework/zend-mime": "*" + }, + "require-dev": { + "laminas/laminas-coding-standard": "~2.4.0", + "laminas/laminas-mail": "^2.19.0", + "phpunit/phpunit": "~9.5.25" + }, + "suggest": { + "laminas/laminas-mail": "Laminas\\Mail component" + }, + "time": "2023-11-02T16:47:19+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "Laminas\\Mime\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "description": "Create and parse MIME messages and parts", + "homepage": "https://laminas.dev", + "keywords": [ + "laminas", + "mime" + ], + "support": { + "chat": "https://laminas.dev/chat", + "docs": "https://docs.laminas.dev/laminas-mime/", + "forum": "https://discourse.laminas.dev", + "issues": "https://github.com/laminas/laminas-mime/issues", + "rss": "https://github.com/laminas/laminas-mime/releases.atom", + "source": "https://github.com/laminas/laminas-mime" + }, + "funding": [ + { + "url": "https://funding.communitybridge.org/projects/laminas-project", + "type": "community_bridge" + } + ], + "abandoned": "symfony/mime", + "install-path": "../laminas/laminas-mime" + }, + { + "name": "laminas/laminas-servicemanager", + "version": "3.23.1", + "version_normalized": "3.23.1.0", + "source": { + "type": "git", + "url": "https://github.com/laminas/laminas-servicemanager.git", + "reference": "06594db3a644447521eace9b5efdb12dc8446a33" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/laminas/laminas-servicemanager/zipball/06594db3a644447521eace9b5efdb12dc8446a33", + "reference": "06594db3a644447521eace9b5efdb12dc8446a33", + "shasum": "" + }, + "require": { + "laminas/laminas-stdlib": "^3.19", + "php": "~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0", + "psr/container": "^1.0" + }, + "conflict": { + "ext-psr": "*", + "laminas/laminas-code": "<4.10.0", + "zendframework/zend-code": "<3.3.1", + "zendframework/zend-servicemanager": "*" + }, + "provide": { + "psr/container-implementation": "^1.0" + }, + "replace": { + "container-interop/container-interop": "^1.2.0" + }, + "require-dev": { + "composer/package-versions-deprecated": "^1.11.99.5", + "friendsofphp/proxy-manager-lts": "^1.0.18", + "laminas/laminas-code": "^4.16.0", + "laminas/laminas-coding-standard": "~2.5.0", + "laminas/laminas-container-config-test": "^0.8", + "mikey179/vfsstream": "^1.6.12", + "phpbench/phpbench": "^1.4.1", + "phpunit/phpunit": "^10.5.51", + "psalm/plugin-phpunit": "^0.18.4", + "vimeo/psalm": "^5.26.1" + }, + "suggest": { + "friendsofphp/proxy-manager-lts": "ProxyManager ^2.1.1 to handle lazy initialization of services" + }, + "time": "2025-08-12T08:44:02+00:00", + "bin": [ + "bin/generate-deps-for-config-factory", + "bin/generate-factory-for-class" + ], + "type": "library", + "installation-source": "dist", + "autoload": { + "files": [ + "src/autoload.php" + ], + "psr-4": { + "Laminas\\ServiceManager\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "description": "Factory-Driven Dependency Injection Container", + "homepage": "https://laminas.dev", + "keywords": [ + "PSR-11", + "dependency-injection", + "di", + "dic", + "laminas", + "service-manager", + "servicemanager" + ], + "support": { + "chat": "https://laminas.dev/chat", + "docs": "https://docs.laminas.dev/laminas-servicemanager/", + "forum": "https://discourse.laminas.dev", + "issues": "https://github.com/laminas/laminas-servicemanager/issues", + "rss": "https://github.com/laminas/laminas-servicemanager/releases.atom", + "source": "https://github.com/laminas/laminas-servicemanager" + }, + "funding": [ + { + "url": "https://funding.communitybridge.org/projects/laminas-project", + "type": "community_bridge" + } + ], + "install-path": "../laminas/laminas-servicemanager" + }, + { + "name": "laminas/laminas-stdlib", + "version": "3.20.0", + "version_normalized": "3.20.0.0", + "source": { + "type": "git", + "url": "https://github.com/laminas/laminas-stdlib.git", + "reference": "8974a1213be42c3e2f70b2c27b17f910291ab2f4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/laminas/laminas-stdlib/zipball/8974a1213be42c3e2f70b2c27b17f910291ab2f4", + "reference": "8974a1213be42c3e2f70b2c27b17f910291ab2f4", + "shasum": "" + }, + "require": { + "php": "~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0" + }, + "conflict": { + "zendframework/zend-stdlib": "*" + }, + "require-dev": { + "laminas/laminas-coding-standard": "^3.0", + "phpbench/phpbench": "^1.3.1", + "phpunit/phpunit": "^10.5.38", + "psalm/plugin-phpunit": "^0.19.0", + "vimeo/psalm": "^5.26.1" + }, + "time": "2024-10-29T13:46:07+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "Laminas\\Stdlib\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "description": "SPL extensions, array utilities, error handlers, and more", + "homepage": "https://laminas.dev", + "keywords": [ + "laminas", + "stdlib" + ], + "support": { + "chat": "https://laminas.dev/chat", + "docs": "https://docs.laminas.dev/laminas-stdlib/", + "forum": "https://discourse.laminas.dev", + "issues": "https://github.com/laminas/laminas-stdlib/issues", + "rss": "https://github.com/laminas/laminas-stdlib/releases.atom", + "source": "https://github.com/laminas/laminas-stdlib" + }, + "funding": [ + { + "url": "https://funding.communitybridge.org/projects/laminas-project", + "type": "community_bridge" + } + ], + "install-path": "../laminas/laminas-stdlib" + }, + { + "name": "laminas/laminas-validator", + "version": "2.64.4", + "version_normalized": "2.64.4.0", + "source": { + "type": "git", + "url": "https://github.com/laminas/laminas-validator.git", + "reference": "e2e6631f599a9b0db1e23adb633c09a2f0c68bed" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/laminas/laminas-validator/zipball/e2e6631f599a9b0db1e23adb633c09a2f0c68bed", + "reference": "e2e6631f599a9b0db1e23adb633c09a2f0c68bed", + "shasum": "" + }, + "require": { + "laminas/laminas-servicemanager": "^3.21.0", + "laminas/laminas-stdlib": "^3.19", + "php": "~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0", + "psr/http-message": "^1.0.1 || ^2.0.0" + }, + "conflict": { + "zendframework/zend-validator": "*" + }, + "require-dev": { + "laminas/laminas-coding-standard": "^2.5", + "laminas/laminas-db": "^2.20", + "laminas/laminas-filter": "^2.35.2", + "laminas/laminas-i18n": "^2.26.0", + "laminas/laminas-session": "^2.20", + "laminas/laminas-uri": "^2.11.0", + "phpunit/phpunit": "^10.5.20", + "psalm/plugin-phpunit": "^0.19.0", + "psr/http-client": "^1.0.3", + "psr/http-factory": "^1.1.0", + "vimeo/psalm": "^5.24.0" + }, + "suggest": { + "laminas/laminas-db": "Laminas\\Db component, required by the (No)RecordExists validator", + "laminas/laminas-filter": "Laminas\\Filter component, required by the Digits validator", + "laminas/laminas-i18n": "Laminas\\I18n component to allow translation of validation error messages", + "laminas/laminas-i18n-resources": "Translations of validator messages", + "laminas/laminas-servicemanager": "Laminas\\ServiceManager component to allow using the ValidatorPluginManager and validator chains", + "laminas/laminas-session": "Laminas\\Session component, ^2.8; required by the Csrf validator", + "laminas/laminas-uri": "Laminas\\Uri component, required by the Uri and Sitemap\\Loc validators", + "psr/http-message": "psr/http-message, required when validating PSR-7 UploadedFileInterface instances via the Upload and UploadFile validators" + }, + "time": "2025-06-16T14:38:00+00:00", + "type": "library", + "extra": { + "laminas": { + "component": "Laminas\\Validator", + "config-provider": "Laminas\\Validator\\ConfigProvider" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Laminas\\Validator\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "description": "Validation classes for a wide range of domains, and the ability to chain validators to create complex validation criteria", + "homepage": "https://laminas.dev", + "keywords": [ + "laminas", + "validator" + ], + "support": { + "chat": "https://laminas.dev/chat", + "docs": "https://docs.laminas.dev/laminas-validator/", + "forum": "https://discourse.laminas.dev", + "issues": "https://github.com/laminas/laminas-validator/issues", + "rss": "https://github.com/laminas/laminas-validator/releases.atom", + "source": "https://github.com/laminas/laminas-validator" + }, + "funding": [ + { + "url": "https://funding.communitybridge.org/projects/laminas-project", + "type": "community_bridge" + } + ], + "install-path": "../laminas/laminas-validator" + }, + { + "name": "league/color-extractor", + "version": "0.3.2", + "version_normalized": "0.3.2.0", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/color-extractor.git", + "reference": "837086ec60f50c84c611c613963e4ad2e2aec806" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/color-extractor/zipball/837086ec60f50c84c611c613963e4ad2e2aec806", + "reference": "837086ec60f50c84c611c613963e4ad2e2aec806", + "shasum": "" + }, + "require": { + "ext-gd": "*", + "php": ">=5.4.0" + }, + "replace": { + "matthecat/colorextractor": "*" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "~2", + "phpunit/phpunit": "~5" + }, + "time": "2016-12-15T09:30:02+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mathieu Lechat", + "email": "math.lechat@gmail.com", + "homepage": "http://matthecat.com", + "role": "Developer" + } + ], + "description": "Extract colors from an image as a human would do.", + "homepage": "https://github.com/thephpleague/color-extractor", + "keywords": [ + "color", + "extract", + "human", + "image", + "palette" + ], + "support": { + "issues": "https://github.com/thephpleague/color-extractor/issues", + "source": "https://github.com/thephpleague/color-extractor/tree/master" + }, + "install-path": "../league/color-extractor" + }, + { + "name": "league/flysystem", + "version": "1.1.10", + "version_normalized": "1.1.10.0", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/flysystem.git", + "reference": "3239285c825c152bcc315fe0e87d6b55f5972ed1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/3239285c825c152bcc315fe0e87d6b55f5972ed1", + "reference": "3239285c825c152bcc315fe0e87d6b55f5972ed1", + "shasum": "" + }, + "require": { + "ext-fileinfo": "*", + "league/mime-type-detection": "^1.3", + "php": "^7.2.5 || ^8.0" + }, + "conflict": { + "league/flysystem-sftp": "<1.0.6" + }, + "require-dev": { + "phpspec/prophecy": "^1.11.1", + "phpunit/phpunit": "^8.5.8" + }, + "suggest": { + "ext-ftp": "Allows you to use FTP server storage", + "ext-openssl": "Allows you to use FTPS server storage", + "league/flysystem-aws-s3-v2": "Allows you to use S3 storage with AWS SDK v2", + "league/flysystem-aws-s3-v3": "Allows you to use S3 storage with AWS SDK v3", + "league/flysystem-azure": "Allows you to use Windows Azure Blob storage", + "league/flysystem-cached-adapter": "Flysystem adapter decorator for metadata caching", + "league/flysystem-eventable-filesystem": "Allows you to use EventableFilesystem", + "league/flysystem-rackspace": "Allows you to use Rackspace Cloud Files", + "league/flysystem-sftp": "Allows you to use SFTP server storage via phpseclib", + "league/flysystem-webdav": "Allows you to use WebDAV storage", + "league/flysystem-ziparchive": "Allows you to use ZipArchive adapter", + "spatie/flysystem-dropbox": "Allows you to use Dropbox storage", + "srmklive/flysystem-dropbox-v2": "Allows you to use Dropbox storage for PHP 5 applications" + }, + "time": "2022-10-04T09:16:37+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "League\\Flysystem\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Frank de Jonge", + "email": "info@frenky.net" + } + ], + "description": "Filesystem abstraction: Many filesystems, one API.", + "keywords": [ + "Cloud Files", + "WebDAV", + "abstraction", + "aws", + "cloud", + "copy.com", + "dropbox", + "file systems", + "files", + "filesystem", + "filesystems", + "ftp", + "rackspace", + "remote", + "s3", + "sftp", + "storage" + ], + "support": { + "issues": "https://github.com/thephpleague/flysystem/issues", + "source": "https://github.com/thephpleague/flysystem/tree/1.1.10" + }, + "funding": [ + { + "url": "https://offset.earth/frankdejonge", + "type": "other" + } + ], + "install-path": "../league/flysystem" + }, + { + "name": "league/mime-type-detection", + "version": "1.16.0", + "version_normalized": "1.16.0.0", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/mime-type-detection.git", + "reference": "2d6702ff215bf922936ccc1ad31007edc76451b9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/mime-type-detection/zipball/2d6702ff215bf922936ccc1ad31007edc76451b9", + "reference": "2d6702ff215bf922936ccc1ad31007edc76451b9", + "shasum": "" + }, + "require": { + "ext-fileinfo": "*", + "php": "^7.4 || ^8.0" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "^3.2", + "phpstan/phpstan": "^0.12.68", + "phpunit/phpunit": "^8.5.8 || ^9.3 || ^10.0" + }, + "time": "2024-09-21T08:32:55+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "League\\MimeTypeDetection\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Frank de Jonge", + "email": "info@frankdejonge.nl" + } + ], + "description": "Mime-type detection for Flysystem", + "support": { + "issues": "https://github.com/thephpleague/mime-type-detection/issues", + "source": "https://github.com/thephpleague/mime-type-detection/tree/1.16.0" + }, + "funding": [ + { + "url": "https://github.com/frankdejonge", + "type": "github" }, { - "name": "phpmailer/phpmailer", - "version": "v6.3.0", - "version_normalized": "6.3.0.0", - "source": { - "type": "git", - "url": "https://github.com/PHPMailer/PHPMailer.git", - "reference": "4a08cf4cdd2c38d12ee2b9fa69e5d235f37a6dcb" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/PHPMailer/PHPMailer/zipball/4a08cf4cdd2c38d12ee2b9fa69e5d235f37a6dcb", - "reference": "4a08cf4cdd2c38d12ee2b9fa69e5d235f37a6dcb", - "shasum": "" - }, - "require": { - "ext-ctype": "*", - "ext-filter": "*", - "ext-hash": "*", - "php": ">=5.5.0" - }, - "require-dev": { - "dealerdirect/phpcodesniffer-composer-installer": "^0.7.0", - "doctrine/annotations": "^1.2", - "phpcompatibility/php-compatibility": "^9.3.5", - "roave/security-advisories": "dev-latest", - "squizlabs/php_codesniffer": "^3.5.6", - "yoast/phpunit-polyfills": "^0.2.0" - }, - "suggest": { - "ext-mbstring": "Needed to send email in multibyte encoding charset", - "hayageek/oauth2-yahoo": "Needed for Yahoo XOAUTH2 authentication", - "league/oauth2-google": "Needed for Google XOAUTH2 authentication", - "psr/log": "For optional PSR-3 debug logging", - "stevenmaguire/oauth2-microsoft": "Needed for Microsoft XOAUTH2 authentication", - "symfony/polyfill-mbstring": "To support UTF-8 if the Mbstring PHP extension is not enabled (^1.2)" - }, - "time": "2021-02-19T15:28:08+00:00", - "type": "library", - "installation-source": "dist", - "autoload": { - "psr-4": { - "PHPMailer\\PHPMailer\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "LGPL-2.1-only" - ], - "authors": [ - { - "name": "Marcus Bointon", - "email": "phpmailer@synchromedia.co.uk" - }, - { - "name": "Jim Jagielski", - "email": "jimjag@gmail.com" - }, - { - "name": "Andy Prevost", - "email": "codeworxtech@users.sourceforge.net" - }, - { - "name": "Brent R. Matzelle" - } - ], - "description": "PHPMailer is a full-featured email creation and transfer class for PHP", - "support": { - "issues": "https://github.com/PHPMailer/PHPMailer/issues", - "source": "https://github.com/PHPMailer/PHPMailer/tree/v6.3.0" - }, - "funding": [ - { - "url": "https://github.com/Synchro", - "type": "github" - } - ], - "install-path": "../phpmailer/phpmailer" + "url": "https://tidelift.com/funding/github/packagist/league/flysystem", + "type": "tidelift" + } + ], + "install-path": "../league/mime-type-detection" + }, + { + "name": "lfkeitel/phptotp", + "version": "v1.1.0", + "version_normalized": "1.1.0.0", + "source": { + "type": "git", + "url": "https://github.com/lfkeitel/php-totp.git", + "reference": "5b1673e895f857856b3e75ccb442855771c9b9be" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/lfkeitel/php-totp/zipball/5b1673e895f857856b3e75ccb442855771c9b9be", + "reference": "5b1673e895f857856b3e75ccb442855771c9b9be", + "shasum": "" + }, + "require": { + "php": "^5.6 || ^7.0 || ^8.0" + }, + "time": "2022-04-07T20:52:00+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "lfkeitel\\phptotp\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "TOTP/HOTP library for PHP", + "keywords": [ + "Authentication", + "hotp", + "totp", + "two-factor" + ], + "support": { + "issues": "https://github.com/lfkeitel/php-totp/issues", + "source": "https://github.com/lfkeitel/php-totp/tree/v1.1.0" + }, + "install-path": "../lfkeitel/phptotp" + }, + { + "name": "mtdowling/jmespath.php", + "version": "2.8.0", + "version_normalized": "2.8.0.0", + "source": { + "type": "git", + "url": "https://github.com/jmespath/jmespath.php.git", + "reference": "a2a865e05d5f420b50cc2f85bb78d565db12a6bc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/jmespath/jmespath.php/zipball/a2a865e05d5f420b50cc2f85bb78d565db12a6bc", + "reference": "a2a865e05d5f420b50cc2f85bb78d565db12a6bc", + "shasum": "" + }, + "require": { + "php": "^7.2.5 || ^8.0", + "symfony/polyfill-mbstring": "^1.17" + }, + "require-dev": { + "composer/xdebug-handler": "^3.0.3", + "phpunit/phpunit": "^8.5.33" + }, + "time": "2024-09-04T18:46:31+00:00", + "bin": [ + "bin/jp.php" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.8-dev" + } + }, + "installation-source": "dist", + "autoload": { + "files": [ + "src/JmesPath.php" + ], + "psr-4": { + "JmesPath\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" }, { - "name": "psr/container", - "version": "1.1.2", - "version_normalized": "1.1.2.0", - "source": { - "type": "git", - "url": "https://github.com/php-fig/container.git", - "reference": "513e0666f7216c7459170d56df27dfcefe1689ea" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/php-fig/container/zipball/513e0666f7216c7459170d56df27dfcefe1689ea", - "reference": "513e0666f7216c7459170d56df27dfcefe1689ea", - "shasum": "" - }, - "require": { - "php": ">=7.4.0" - }, - "time": "2021-11-05T16:50:12+00:00", - "type": "library", - "installation-source": "dist", - "autoload": { - "psr-4": { - "Psr\\Container\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "PHP-FIG", - "homepage": "https://www.php-fig.org/" - } - ], - "description": "Common Container Interface (PHP FIG PSR-11)", - "homepage": "https://github.com/php-fig/container", - "keywords": [ - "PSR-11", - "container", - "container-interface", - "container-interop", - "psr" - ], - "support": { - "issues": "https://github.com/php-fig/container/issues", - "source": "https://github.com/php-fig/container/tree/1.1.2" - }, - "install-path": "../psr/container" + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + } + ], + "description": "Declaratively specify how to extract elements from a JSON document", + "keywords": [ + "json", + "jsonpath" + ], + "support": { + "issues": "https://github.com/jmespath/jmespath.php/issues", + "source": "https://github.com/jmespath/jmespath.php/tree/2.8.0" + }, + "install-path": "../mtdowling/jmespath.php" + }, + { + "name": "nikic/fast-route", + "version": "v1.3.0", + "version_normalized": "1.3.0.0", + "source": { + "type": "git", + "url": "https://github.com/nikic/FastRoute.git", + "reference": "181d480e08d9476e61381e04a71b34dc0432e812" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nikic/FastRoute/zipball/181d480e08d9476e61381e04a71b34dc0432e812", + "reference": "181d480e08d9476e61381e04a71b34dc0432e812", + "shasum": "" + }, + "require": { + "php": ">=5.4.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.8.35|~5.7" + }, + "time": "2018-02-13T20:26:39+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "files": [ + "src/functions.php" + ], + "psr-4": { + "FastRoute\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Nikita Popov", + "email": "nikic@php.net" + } + ], + "description": "Fast request router for PHP", + "keywords": [ + "router", + "routing" + ], + "support": { + "issues": "https://github.com/nikic/FastRoute/issues", + "source": "https://github.com/nikic/FastRoute/tree/master" + }, + "install-path": "../nikic/fast-route" + }, + { + "name": "phpmailer/phpmailer", + "version": "v6.3.0", + "version_normalized": "6.3.0.0", + "source": { + "type": "git", + "url": "https://github.com/PHPMailer/PHPMailer.git", + "reference": "4a08cf4cdd2c38d12ee2b9fa69e5d235f37a6dcb" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/PHPMailer/PHPMailer/zipball/4a08cf4cdd2c38d12ee2b9fa69e5d235f37a6dcb", + "reference": "4a08cf4cdd2c38d12ee2b9fa69e5d235f37a6dcb", + "shasum": "" + }, + "require": { + "ext-ctype": "*", + "ext-filter": "*", + "ext-hash": "*", + "php": ">=5.5.0" + }, + "require-dev": { + "dealerdirect/phpcodesniffer-composer-installer": "^0.7.0", + "doctrine/annotations": "^1.2", + "phpcompatibility/php-compatibility": "^9.3.5", + "roave/security-advisories": "dev-latest", + "squizlabs/php_codesniffer": "^3.5.6", + "yoast/phpunit-polyfills": "^0.2.0" + }, + "suggest": { + "ext-mbstring": "Needed to send email in multibyte encoding charset", + "hayageek/oauth2-yahoo": "Needed for Yahoo XOAUTH2 authentication", + "league/oauth2-google": "Needed for Google XOAUTH2 authentication", + "psr/log": "For optional PSR-3 debug logging", + "stevenmaguire/oauth2-microsoft": "Needed for Microsoft XOAUTH2 authentication", + "symfony/polyfill-mbstring": "To support UTF-8 if the Mbstring PHP extension is not enabled (^1.2)" + }, + "time": "2021-02-19T15:28:08+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "PHPMailer\\PHPMailer\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "LGPL-2.1-only" + ], + "authors": [ + { + "name": "Marcus Bointon", + "email": "phpmailer@synchromedia.co.uk" }, { - "name": "psr/http-message", - "version": "1.1", - "version_normalized": "1.1.0.0", - "source": { - "type": "git", - "url": "https://github.com/php-fig/http-message.git", - "reference": "cb6ce4845ce34a8ad9e68117c10ee90a29919eba" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/php-fig/http-message/zipball/cb6ce4845ce34a8ad9e68117c10ee90a29919eba", - "reference": "cb6ce4845ce34a8ad9e68117c10ee90a29919eba", - "shasum": "" - }, - "require": { - "php": "^7.2 || ^8.0" - }, - "time": "2023-04-04T09:50:52+00:00", - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.1.x-dev" - } - }, - "installation-source": "dist", - "autoload": { - "psr-4": { - "Psr\\Http\\Message\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "PHP-FIG", - "homepage": "http://www.php-fig.org/" - } - ], - "description": "Common interface for HTTP messages", - "homepage": "https://github.com/php-fig/http-message", - "keywords": [ - "http", - "http-message", - "psr", - "psr-7", - "request", - "response" - ], - "support": { - "source": "https://github.com/php-fig/http-message/tree/1.1" - }, - "install-path": "../psr/http-message" + "name": "Jim Jagielski", + "email": "jimjag@gmail.com" }, { - "name": "psr/log", - "version": "1.1.4", - "version_normalized": "1.1.4.0", - "source": { - "type": "git", - "url": "https://github.com/php-fig/log.git", - "reference": "d49695b909c3b7628b6289db5479a1c204601f11" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/php-fig/log/zipball/d49695b909c3b7628b6289db5479a1c204601f11", - "reference": "d49695b909c3b7628b6289db5479a1c204601f11", - "shasum": "" - }, - "require": { - "php": ">=5.3.0" - }, - "time": "2021-05-03T11:20:27+00:00", - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.1.x-dev" - } - }, - "installation-source": "dist", - "autoload": { - "psr-4": { - "Psr\\Log\\": "Psr/Log/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "PHP-FIG", - "homepage": "https://www.php-fig.org/" - } - ], - "description": "Common interface for logging libraries", - "homepage": "https://github.com/php-fig/log", - "keywords": [ - "log", - "psr", - "psr-3" - ], - "support": { - "source": "https://github.com/php-fig/log/tree/1.1.4" - }, - "install-path": "../psr/log" + "name": "Andy Prevost", + "email": "codeworxtech@users.sourceforge.net" }, { - "name": "rakit/validation", - "version": "v0.22.3", - "version_normalized": "0.22.3.0", - "source": { - "type": "git", - "url": "https://github.com/rakit/validation.git", - "reference": "61ed77b772c214faa67aaf1c4adf81502b06cd4b" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/rakit/validation/zipball/61ed77b772c214faa67aaf1c4adf81502b06cd4b", - "reference": "61ed77b772c214faa67aaf1c4adf81502b06cd4b", - "shasum": "" - }, - "require": { - "ext-mbstring": "*", - "php": ">=5.5.0" - }, - "require-dev": { - "phpunit/phpunit": "4.*" - }, - "time": "2018-11-10T03:57:56+00:00", - "type": "library", - "installation-source": "dist", - "autoload": { - "psr-4": { - "Rakit\\Validation\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Muhammad Syifa", - "email": "emsifa@gmail.com" - } - ], - "description": "PHP Laravel like standalone validation library", - "support": { - "issues": "https://github.com/rakit/validation/issues", - "source": "https://github.com/rakit/validation/tree/master" - }, - "install-path": "../rakit/validation" + "name": "Brent R. Matzelle" + } + ], + "description": "PHPMailer is a full-featured email creation and transfer class for PHP", + "support": { + "issues": "https://github.com/PHPMailer/PHPMailer/issues", + "source": "https://github.com/PHPMailer/PHPMailer/tree/v6.3.0" + }, + "funding": [ + { + "url": "https://github.com/Synchro", + "type": "github" + } + ], + "install-path": "../phpmailer/phpmailer" + }, + { + "name": "psr/container", + "version": "1.1.2", + "version_normalized": "1.1.2.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/container.git", + "reference": "513e0666f7216c7459170d56df27dfcefe1689ea" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/container/zipball/513e0666f7216c7459170d56df27dfcefe1689ea", + "reference": "513e0666f7216c7459170d56df27dfcefe1689ea", + "shasum": "" + }, + "require": { + "php": ">=7.4.0" + }, + "time": "2021-11-05T16:50:12+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "Psr\\Container\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common Container Interface (PHP FIG PSR-11)", + "homepage": "https://github.com/php-fig/container", + "keywords": [ + "PSR-11", + "container", + "container-interface", + "container-interop", + "psr" + ], + "support": { + "issues": "https://github.com/php-fig/container/issues", + "source": "https://github.com/php-fig/container/tree/1.1.2" + }, + "install-path": "../psr/container" + }, + { + "name": "psr/http-message", + "version": "1.1", + "version_normalized": "1.1.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-message.git", + "reference": "cb6ce4845ce34a8ad9e68117c10ee90a29919eba" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-message/zipball/cb6ce4845ce34a8ad9e68117c10ee90a29919eba", + "reference": "cb6ce4845ce34a8ad9e68117c10ee90a29919eba", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0" + }, + "time": "2023-04-04T09:50:52+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1.x-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Psr\\Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interface for HTTP messages", + "homepage": "https://github.com/php-fig/http-message", + "keywords": [ + "http", + "http-message", + "psr", + "psr-7", + "request", + "response" + ], + "support": { + "source": "https://github.com/php-fig/http-message/tree/1.1" + }, + "install-path": "../psr/http-message" + }, + { + "name": "psr/log", + "version": "1.1.4", + "version_normalized": "1.1.4.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/log.git", + "reference": "d49695b909c3b7628b6289db5479a1c204601f11" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/log/zipball/d49695b909c3b7628b6289db5479a1c204601f11", + "reference": "d49695b909c3b7628b6289db5479a1c204601f11", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "time": "2021-05-03T11:20:27+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1.x-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Psr\\Log\\": "Psr/Log/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for logging libraries", + "homepage": "https://github.com/php-fig/log", + "keywords": [ + "log", + "psr", + "psr-3" + ], + "support": { + "source": "https://github.com/php-fig/log/tree/1.1.4" + }, + "install-path": "../psr/log" + }, + { + "name": "rakit/validation", + "version": "v0.22.3", + "version_normalized": "0.22.3.0", + "source": { + "type": "git", + "url": "https://github.com/rakit/validation.git", + "reference": "61ed77b772c214faa67aaf1c4adf81502b06cd4b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/rakit/validation/zipball/61ed77b772c214faa67aaf1c4adf81502b06cd4b", + "reference": "61ed77b772c214faa67aaf1c4adf81502b06cd4b", + "shasum": "" + }, + "require": { + "ext-mbstring": "*", + "php": ">=5.5.0" + }, + "require-dev": { + "phpunit/phpunit": "4.*" + }, + "time": "2018-11-10T03:57:56+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "Rakit\\Validation\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Muhammad Syifa", + "email": "emsifa@gmail.com" + } + ], + "description": "PHP Laravel like standalone validation library", + "support": { + "issues": "https://github.com/rakit/validation/issues", + "source": "https://github.com/rakit/validation/tree/master" + }, + "install-path": "../rakit/validation" + }, + { + "name": "ralouphie/getallheaders", + "version": "3.0.3", + "version_normalized": "3.0.3.0", + "source": { + "type": "git", + "url": "https://github.com/ralouphie/getallheaders.git", + "reference": "120b605dfeb996808c31b6477290a714d356e822" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ralouphie/getallheaders/zipball/120b605dfeb996808c31b6477290a714d356e822", + "reference": "120b605dfeb996808c31b6477290a714d356e822", + "shasum": "" + }, + "require": { + "php": ">=5.6" + }, + "require-dev": { + "php-coveralls/php-coveralls": "^2.1", + "phpunit/phpunit": "^5 || ^6.5" + }, + "time": "2019-03-08T08:55:37+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "files": [ + "src/getallheaders.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ralph Khattar", + "email": "ralph.khattar@gmail.com" + } + ], + "description": "A polyfill for getallheaders.", + "support": { + "issues": "https://github.com/ralouphie/getallheaders/issues", + "source": "https://github.com/ralouphie/getallheaders/tree/develop" + }, + "install-path": "../ralouphie/getallheaders" + }, + { + "name": "sabre/dav", + "version": "3.2.3", + "version_normalized": "3.2.3.0", + "source": { + "type": "git", + "url": "https://github.com/sabre-io/dav.git", + "reference": "a9780ce4f35560ecbd0af524ad32d9d2c8954b80" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sabre-io/dav/zipball/a9780ce4f35560ecbd0af524ad32d9d2c8954b80", + "reference": "a9780ce4f35560ecbd0af524ad32d9d2c8954b80", + "shasum": "" + }, + "require": { + "ext-ctype": "*", + "ext-date": "*", + "ext-dom": "*", + "ext-iconv": "*", + "ext-mbstring": "*", + "ext-pcre": "*", + "ext-simplexml": "*", + "ext-spl": "*", + "lib-libxml": ">=2.7.0", + "php": ">=5.5.0", + "psr/log": "^1.0", + "sabre/event": ">=2.0.0, <4.0.0", + "sabre/http": "^4.2.1", + "sabre/uri": "^1.0.1", + "sabre/vobject": "^4.1.0", + "sabre/xml": "^1.4.0" + }, + "require-dev": { + "evert/phpdoc-md": "~0.1.0", + "monolog/monolog": "^1.18", + "phpunit/phpunit": "> 4.8, <6.0.0", + "sabre/cs": "^1.0.0" + }, + "suggest": { + "ext-curl": "*", + "ext-pdo": "*" + }, + "time": "2018-10-19T09:58:27+00:00", + "bin": [ + "bin/sabredav", + "bin/naturalselection" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.1.0-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Sabre\\DAV\\": "lib/DAV/", + "Sabre\\CalDAV\\": "lib/CalDAV/", + "Sabre\\DAVACL\\": "lib/DAVACL/", + "Sabre\\CardDAV\\": "lib/CardDAV/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Evert Pot", + "email": "me@evertpot.com", + "homepage": "http://evertpot.com/", + "role": "Developer" + } + ], + "description": "WebDAV Framework for PHP", + "homepage": "http://sabre.io/", + "keywords": [ + "CalDAV", + "CardDAV", + "WebDAV", + "framework", + "iCalendar" + ], + "support": { + "forum": "https://groups.google.com/group/sabredav-discuss", + "issues": "https://github.com/sabre-io/dav/issues", + "source": "https://github.com/fruux/sabre-dav" + }, + "install-path": "../sabre/dav" + }, + { + "name": "sabre/event", + "version": "3.0.0", + "version_normalized": "3.0.0.0", + "source": { + "type": "git", + "url": "https://github.com/sabre-io/event.git", + "reference": "831d586f5a442dceacdcf5e9c4c36a4db99a3534" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sabre-io/event/zipball/831d586f5a442dceacdcf5e9c4c36a4db99a3534", + "reference": "831d586f5a442dceacdcf5e9c4c36a4db99a3534", + "shasum": "" + }, + "require": { + "php": ">=5.5" + }, + "require-dev": { + "phpunit/phpunit": "*", + "sabre/cs": "~0.0.4" + }, + "time": "2015-11-05T20:14:39+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "files": [ + "lib/coroutine.php", + "lib/Loop/functions.php", + "lib/Promise/functions.php" + ], + "psr-4": { + "Sabre\\Event\\": "lib/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Evert Pot", + "email": "me@evertpot.com", + "homepage": "http://evertpot.com/", + "role": "Developer" + } + ], + "description": "sabre/event is a library for lightweight event-based programming", + "homepage": "http://sabre.io/event/", + "keywords": [ + "EventEmitter", + "async", + "events", + "hooks", + "plugin", + "promise", + "signal" + ], + "support": { + "forum": "https://groups.google.com/group/sabredav-discuss", + "issues": "https://github.com/sabre-io/event/issues", + "source": "https://github.com/fruux/sabre-event" + }, + "install-path": "../sabre/event" + }, + { + "name": "sabre/http", + "version": "v4.2.4", + "version_normalized": "4.2.4.0", + "source": { + "type": "git", + "url": "https://github.com/sabre-io/http.git", + "reference": "acccec4ba863959b2d10c1fa0fb902736c5c8956" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sabre-io/http/zipball/acccec4ba863959b2d10c1fa0fb902736c5c8956", + "reference": "acccec4ba863959b2d10c1fa0fb902736c5c8956", + "shasum": "" + }, + "require": { + "ext-ctype": "*", + "ext-mbstring": "*", + "php": ">=5.4", + "sabre/event": ">=1.0.0,<4.0.0", + "sabre/uri": "~1.0" + }, + "require-dev": { + "phpunit/phpunit": "~4.3", + "sabre/cs": "~0.0.1" + }, + "suggest": { + "ext-curl": " to make http requests with the Client class" + }, + "time": "2018-02-23T11:10:29+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "files": [ + "lib/functions.php" + ], + "psr-4": { + "Sabre\\HTTP\\": "lib/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Evert Pot", + "email": "me@evertpot.com", + "homepage": "http://evertpot.com/", + "role": "Developer" + } + ], + "description": "The sabre/http library provides utilities for dealing with http requests and responses. ", + "homepage": "https://github.com/fruux/sabre-http", + "keywords": [ + "http" + ], + "support": { + "forum": "https://groups.google.com/group/sabredav-discuss", + "issues": "https://github.com/sabre-io/http/issues", + "source": "https://github.com/fruux/sabre-http" + }, + "install-path": "../sabre/http" + }, + { + "name": "sabre/uri", + "version": "1.2.1", + "version_normalized": "1.2.1.0", + "source": { + "type": "git", + "url": "https://github.com/sabre-io/uri.git", + "reference": "ada354d83579565949d80b2e15593c2371225e61" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sabre-io/uri/zipball/ada354d83579565949d80b2e15593c2371225e61", + "reference": "ada354d83579565949d80b2e15593c2371225e61", + "shasum": "" + }, + "require": { + "php": ">=5.4.7" + }, + "require-dev": { + "phpunit/phpunit": ">=4.0,<6.0", + "sabre/cs": "~1.0.0" + }, + "time": "2017-02-20T19:59:28+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "files": [ + "lib/functions.php" + ], + "psr-4": { + "Sabre\\Uri\\": "lib/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Evert Pot", + "email": "me@evertpot.com", + "homepage": "http://evertpot.com/", + "role": "Developer" + } + ], + "description": "Functions for making sense out of URIs.", + "homepage": "http://sabre.io/uri/", + "keywords": [ + "rfc3986", + "uri", + "url" + ], + "support": { + "forum": "https://groups.google.com/group/sabredav-discuss", + "issues": "https://github.com/sabre-io/uri/issues", + "source": "https://github.com/fruux/sabre-uri" + }, + "install-path": "../sabre/uri" + }, + { + "name": "sabre/vobject", + "version": "4.2.2", + "version_normalized": "4.2.2.0", + "source": { + "type": "git", + "url": "https://github.com/sabre-io/vobject.git", + "reference": "449616b2d45b95c8973975de23f34a3d14f63b4b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sabre-io/vobject/zipball/449616b2d45b95c8973975de23f34a3d14f63b4b", + "reference": "449616b2d45b95c8973975de23f34a3d14f63b4b", + "shasum": "" + }, + "require": { + "ext-mbstring": "*", + "php": ">=5.5", + "sabre/xml": ">=1.5 <3.0" + }, + "require-dev": { + "phpunit/phpunit": "> 4.8.35, <6.0.0" + }, + "suggest": { + "hoa/bench": "If you would like to run the benchmark scripts" + }, + "time": "2020-01-14T10:18:45+00:00", + "bin": [ + "bin/vobject", + "bin/generate_vcards" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.0.x-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Sabre\\VObject\\": "lib/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Evert Pot", + "email": "me@evertpot.com", + "homepage": "http://evertpot.com/", + "role": "Developer" + }, + { + "name": "Dominik Tobschall", + "email": "dominik@fruux.com", + "homepage": "http://tobschall.de/", + "role": "Developer" + }, + { + "name": "Ivan Enderlin", + "email": "ivan.enderlin@hoa-project.net", + "homepage": "http://mnt.io/", + "role": "Developer" + } + ], + "description": "The VObject library for PHP allows you to easily parse and manipulate iCalendar and vCard objects", + "homepage": "http://sabre.io/vobject/", + "keywords": [ + "availability", + "freebusy", + "iCalendar", + "ical", + "ics", + "jCal", + "jCard", + "recurrence", + "rfc2425", + "rfc2426", + "rfc2739", + "rfc4770", + "rfc5545", + "rfc5546", + "rfc6321", + "rfc6350", + "rfc6351", + "rfc6474", + "rfc6638", + "rfc6715", + "rfc6868", + "vCalendar", + "vCard", + "vcf", + "xCal", + "xCard" + ], + "support": { + "forum": "https://groups.google.com/group/sabredav-discuss", + "issues": "https://github.com/sabre-io/vobject/issues", + "source": "https://github.com/fruux/sabre-vobject" + }, + "install-path": "../sabre/vobject" + }, + { + "name": "sabre/xml", + "version": "1.5.1", + "version_normalized": "1.5.1.0", + "source": { + "type": "git", + "url": "https://github.com/sabre-io/xml.git", + "reference": "a367665f1df614c3b8fefc30a54de7cd295e444e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sabre-io/xml/zipball/a367665f1df614c3b8fefc30a54de7cd295e444e", + "reference": "a367665f1df614c3b8fefc30a54de7cd295e444e", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-xmlreader": "*", + "ext-xmlwriter": "*", + "lib-libxml": ">=2.6.20", + "php": ">=5.5.5", + "sabre/uri": ">=1.0,<3.0.0" + }, + "require-dev": { + "phpunit/phpunit": "~4.8|~5.7", + "sabre/cs": "~1.0.0" + }, + "time": "2019-01-09T13:51:57+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "files": [ + "lib/Deserializer/functions.php", + "lib/Serializer/functions.php" + ], + "psr-4": { + "Sabre\\Xml\\": "lib/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Evert Pot", + "email": "me@evertpot.com", + "homepage": "http://evertpot.com/", + "role": "Developer" + }, + { + "name": "Markus Staab", + "email": "markus.staab@redaxo.de", + "role": "Developer" + } + ], + "description": "sabre/xml is an XML library that you may not hate.", + "homepage": "https://sabre.io/xml/", + "keywords": [ + "XMLReader", + "XMLWriter", + "dom", + "xml" + ], + "support": { + "forum": "https://groups.google.com/group/sabredav-discuss", + "issues": "https://github.com/sabre-io/xml/issues", + "source": "https://github.com/fruux/sabre-xml" + }, + "install-path": "../sabre/xml" + }, + { + "name": "smarty/smarty", + "version": "v3.1.39", + "version_normalized": "3.1.39.0", + "source": { + "type": "git", + "url": "https://github.com/smarty-php/smarty.git", + "reference": "e27da524f7bcd7361e3ea5cdfa99c4378a7b5419" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/smarty-php/smarty/zipball/e27da524f7bcd7361e3ea5cdfa99c4378a7b5419", + "reference": "e27da524f7bcd7361e3ea5cdfa99c4378a7b5419", + "shasum": "" + }, + "require": { + "php": ">=5.2" + }, + "require-dev": { + "phpunit/phpunit": "^7.5 || ^6.5 || ^5.7 || ^4.8", + "smarty/smarty-lexer": "^3.1" + }, + "time": "2021-02-17T21:57:51+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.1.x-dev" + } + }, + "installation-source": "dist", + "autoload": { + "classmap": [ + "libs/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "LGPL-3.0" + ], + "authors": [ + { + "name": "Monte Ohrt", + "email": "monte@ohrt.com" + }, + { + "name": "Uwe Tews", + "email": "uwe.tews@googlemail.com" }, { - "name": "ralouphie/getallheaders", - "version": "3.0.3", - "version_normalized": "3.0.3.0", - "source": { - "type": "git", - "url": "https://github.com/ralouphie/getallheaders.git", - "reference": "120b605dfeb996808c31b6477290a714d356e822" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/ralouphie/getallheaders/zipball/120b605dfeb996808c31b6477290a714d356e822", - "reference": "120b605dfeb996808c31b6477290a714d356e822", - "shasum": "" - }, - "require": { - "php": ">=5.6" - }, - "require-dev": { - "php-coveralls/php-coveralls": "^2.1", - "phpunit/phpunit": "^5 || ^6.5" - }, - "time": "2019-03-08T08:55:37+00:00", - "type": "library", - "installation-source": "dist", - "autoload": { - "files": [ - "src/getallheaders.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Ralph Khattar", - "email": "ralph.khattar@gmail.com" - } - ], - "description": "A polyfill for getallheaders.", - "support": { - "issues": "https://github.com/ralouphie/getallheaders/issues", - "source": "https://github.com/ralouphie/getallheaders/tree/develop" - }, - "install-path": "../ralouphie/getallheaders" + "name": "Rodney Rehm", + "email": "rodney.rehm@medialize.de" + } + ], + "description": "Smarty - the compiling PHP template engine", + "homepage": "http://www.smarty.net", + "keywords": [ + "templating" + ], + "support": { + "forum": "http://www.smarty.net/forums/", + "irc": "irc://irc.freenode.org/smarty", + "issues": "https://github.com/smarty-php/smarty/issues", + "source": "https://github.com/smarty-php/smarty/tree/v3.1.39" + }, + "install-path": "../smarty/smarty" + }, + { + "name": "swiss-payment-slip/swiss-payment-slip", + "version": "0.13.0", + "version_normalized": "0.13.0.0", + "source": { + "type": "git", + "url": "https://github.com/ravage84/SwissPaymentSlip.git", + "reference": "3f5e23552e59ff486318c3af66b0374fa61a176f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ravage84/SwissPaymentSlip/zipball/3f5e23552e59ff486318c3af66b0374fa61a176f", + "reference": "3f5e23552e59ff486318c3af66b0374fa61a176f", + "shasum": "" + }, + "require": { + "php": ">=5.4.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.0.0", + "squizlabs/php_codesniffer": "^2.1.0" + }, + "time": "2019-02-27T15:06:58+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "SwissPaymentSlip\\SwissPaymentSlip\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Peter Siska", + "email": "pesche@gridonic.ch", + "homepage": "http://www.gridonic.ch", + "role": "Contributor" }, { - "name": "sabre/dav", - "version": "3.2.3", - "version_normalized": "3.2.3.0", - "source": { - "type": "git", - "url": "https://github.com/sabre-io/dav.git", - "reference": "a9780ce4f35560ecbd0af524ad32d9d2c8954b80" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sabre-io/dav/zipball/a9780ce4f35560ecbd0af524ad32d9d2c8954b80", - "reference": "a9780ce4f35560ecbd0af524ad32d9d2c8954b80", - "shasum": "" - }, - "require": { - "ext-ctype": "*", - "ext-date": "*", - "ext-dom": "*", - "ext-iconv": "*", - "ext-mbstring": "*", - "ext-pcre": "*", - "ext-simplexml": "*", - "ext-spl": "*", - "lib-libxml": ">=2.7.0", - "php": ">=5.5.0", - "psr/log": "^1.0", - "sabre/event": ">=2.0.0, <4.0.0", - "sabre/http": "^4.2.1", - "sabre/uri": "^1.0.1", - "sabre/vobject": "^4.1.0", - "sabre/xml": "^1.4.0" - }, - "require-dev": { - "evert/phpdoc-md": "~0.1.0", - "monolog/monolog": "^1.18", - "phpunit/phpunit": "> 4.8, <6.0.0", - "sabre/cs": "^1.0.0" - }, - "suggest": { - "ext-curl": "*", - "ext-pdo": "*" - }, - "time": "2018-10-19T09:58:27+00:00", - "bin": [ - "bin/sabredav", - "bin/naturalselection" - ], - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.1.0-dev" - } - }, - "installation-source": "dist", - "autoload": { - "psr-4": { - "Sabre\\DAV\\": "lib/DAV/", - "Sabre\\DAVACL\\": "lib/DAVACL/", - "Sabre\\CalDAV\\": "lib/CalDAV/", - "Sabre\\CardDAV\\": "lib/CardDAV/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Evert Pot", - "email": "me@evertpot.com", - "homepage": "http://evertpot.com/", - "role": "Developer" - } - ], - "description": "WebDAV Framework for PHP", - "homepage": "http://sabre.io/", - "keywords": [ - "CalDAV", - "CardDAV", - "WebDAV", - "framework", - "iCalendar" - ], - "support": { - "forum": "https://groups.google.com/group/sabredav-discuss", - "issues": "https://github.com/sabre-io/dav/issues", - "source": "https://github.com/fruux/sabre-dav" - }, - "install-path": "../sabre/dav" + "name": "Manuel Reinhard", + "email": "manu@sprain.ch", + "homepage": "http://www.sprain.ch", + "role": "Developer of the original class" }, { - "name": "sabre/event", - "version": "3.0.0", - "version_normalized": "3.0.0.0", - "source": { - "type": "git", - "url": "https://github.com/sabre-io/event.git", - "reference": "831d586f5a442dceacdcf5e9c4c36a4db99a3534" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sabre-io/event/zipball/831d586f5a442dceacdcf5e9c4c36a4db99a3534", - "reference": "831d586f5a442dceacdcf5e9c4c36a4db99a3534", - "shasum": "" - }, - "require": { - "php": ">=5.5" - }, - "require-dev": { - "phpunit/phpunit": "*", - "sabre/cs": "~0.0.4" - }, - "time": "2015-11-05T20:14:39+00:00", - "type": "library", - "installation-source": "dist", - "autoload": { - "psr-4": { - "Sabre\\Event\\": "lib/" - }, - "files": [ - "lib/coroutine.php", - "lib/Loop/functions.php", - "lib/Promise/functions.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Evert Pot", - "email": "me@evertpot.com", - "homepage": "http://evertpot.com/", - "role": "Developer" - } - ], - "description": "sabre/event is a library for lightweight event-based programming", - "homepage": "http://sabre.io/event/", - "keywords": [ - "EventEmitter", - "async", - "events", - "hooks", - "plugin", - "promise", - "signal" - ], - "support": { - "forum": "https://groups.google.com/group/sabredav-discuss", - "issues": "https://github.com/sabre-io/event/issues", - "source": "https://github.com/fruux/sabre-event" - }, - "install-path": "../sabre/event" + "name": "Marc Würth", + "email": "ravage@bluewin.ch", + "role": "Lead developer" + } + ], + "description": "A library for creating Swiss payment slips (ESR)", + "homepage": "https://github.com/ravage84/SwissPaymentSlip", + "keywords": [ + "ESR", + "Einzahlungsschein", + "Inpayment slip", + "Payment slip" + ], + "support": { + "email": "ravage@bluewin.ch", + "issues": "https://github.com/ravage84/SwissPaymentSlip/issues", + "source": "https://github.com/ravage84/SwissPaymentSlip" + }, + "install-path": "../swiss-payment-slip/swiss-payment-slip" + }, + { + "name": "swiss-payment-slip/swiss-payment-slip-fpdf", + "version": "0.6.0", + "version_normalized": "0.6.0.0", + "source": { + "type": "git", + "url": "https://github.com/ravage84/SwissPaymentSlipFpdf.git", + "reference": "72f722188d89b2651d4751ab812146cb1f165061" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ravage84/SwissPaymentSlipFpdf/zipball/72f722188d89b2651d4751ab812146cb1f165061", + "reference": "72f722188d89b2651d4751ab812146cb1f165061", + "shasum": "" + }, + "require": { + "itbz/fpdf": "1.7.*", + "php": ">=5.3.0", + "swiss-payment-slip/swiss-payment-slip-pdf": "0.13.*" + }, + "require-dev": { + "phpunit/phpunit": "3.7.38", + "squizlabs/php_codesniffer": "2.1.*" + }, + "time": "2015-04-01T14:55:48+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "SwissPaymentSlip\\SwissPaymentSlipFpdf\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Peter Siska", + "email": "pesche@gridonic.ch", + "homepage": "http://www.gridonic.ch", + "role": "Contributor" }, { - "name": "sabre/http", - "version": "v4.2.4", - "version_normalized": "4.2.4.0", - "source": { - "type": "git", - "url": "https://github.com/sabre-io/http.git", - "reference": "acccec4ba863959b2d10c1fa0fb902736c5c8956" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sabre-io/http/zipball/acccec4ba863959b2d10c1fa0fb902736c5c8956", - "reference": "acccec4ba863959b2d10c1fa0fb902736c5c8956", - "shasum": "" - }, - "require": { - "ext-ctype": "*", - "ext-mbstring": "*", - "php": ">=5.4", - "sabre/event": ">=1.0.0,<4.0.0", - "sabre/uri": "~1.0" - }, - "require-dev": { - "phpunit/phpunit": "~4.3", - "sabre/cs": "~0.0.1" - }, - "suggest": { - "ext-curl": " to make http requests with the Client class" - }, - "time": "2018-02-23T11:10:29+00:00", - "type": "library", - "installation-source": "dist", - "autoload": { - "files": [ - "lib/functions.php" - ], - "psr-4": { - "Sabre\\HTTP\\": "lib/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Evert Pot", - "email": "me@evertpot.com", - "homepage": "http://evertpot.com/", - "role": "Developer" - } - ], - "description": "The sabre/http library provides utilities for dealing with http requests and responses. ", - "homepage": "https://github.com/fruux/sabre-http", - "keywords": [ - "http" - ], - "support": { - "forum": "https://groups.google.com/group/sabredav-discuss", - "issues": "https://github.com/sabre-io/http/issues", - "source": "https://github.com/fruux/sabre-http" - }, - "install-path": "../sabre/http" + "name": "Manuel Reinhard", + "email": "manu@sprain.ch", + "homepage": "http://www.sprain.ch", + "role": "Developer of the original class" }, { - "name": "sabre/uri", - "version": "1.2.1", - "version_normalized": "1.2.1.0", - "source": { - "type": "git", - "url": "https://github.com/sabre-io/uri.git", - "reference": "ada354d83579565949d80b2e15593c2371225e61" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sabre-io/uri/zipball/ada354d83579565949d80b2e15593c2371225e61", - "reference": "ada354d83579565949d80b2e15593c2371225e61", - "shasum": "" - }, - "require": { - "php": ">=5.4.7" - }, - "require-dev": { - "phpunit/phpunit": ">=4.0,<6.0", - "sabre/cs": "~1.0.0" - }, - "time": "2017-02-20T19:59:28+00:00", - "type": "library", - "installation-source": "dist", - "autoload": { - "files": [ - "lib/functions.php" - ], - "psr-4": { - "Sabre\\Uri\\": "lib/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Evert Pot", - "email": "me@evertpot.com", - "homepage": "http://evertpot.com/", - "role": "Developer" - } - ], - "description": "Functions for making sense out of URIs.", - "homepage": "http://sabre.io/uri/", - "keywords": [ - "rfc3986", - "uri", - "url" - ], - "support": { - "forum": "https://groups.google.com/group/sabredav-discuss", - "issues": "https://github.com/sabre-io/uri/issues", - "source": "https://github.com/fruux/sabre-uri" - }, - "install-path": "../sabre/uri" + "name": "Marc Würth", + "email": "ravage@bluewin.ch", + "homepage": "https://github.com/ravage84", + "role": "Lead developer" + } + ], + "description": "Create Swiss payment slips with reference number (ESR) or without (ES) as PDFs with FPDF", + "homepage": "https://github.com/ravage84/SwissPaymentSlipFpdf", + "keywords": [ + "ESR", + "Einzahlungsschein", + "Inpayment slip", + "Payment slip", + "es", + "fpdf", + "pdf" + ], + "support": { + "email": "ravage@bluewin.ch", + "issues": "https://github.com/ravage84/SwissPaymentSlipFpdf/issues", + "source": "https://github.com/ravage84/SwissPaymentSlipFpdf" + }, + "install-path": "../swiss-payment-slip/swiss-payment-slip-fpdf" + }, + { + "name": "swiss-payment-slip/swiss-payment-slip-pdf", + "version": "0.13.1", + "version_normalized": "0.13.1.0", + "source": { + "type": "git", + "url": "https://github.com/ravage84/SwissPaymentSlipPdf.git", + "reference": "4355743b2406875e9fed2117d8df445ba6848be4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ravage84/SwissPaymentSlipPdf/zipball/4355743b2406875e9fed2117d8df445ba6848be4", + "reference": "4355743b2406875e9fed2117d8df445ba6848be4", + "shasum": "" + }, + "require": { + "php": ">=5.3.0", + "swiss-payment-slip/swiss-payment-slip": "0.11.1" + }, + "require-dev": { + "phpunit/phpunit": "3.7.38", + "squizlabs/php_codesniffer": "2.1.*" + }, + "time": "2015-02-18T20:04:44+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "SwissPaymentSlip\\SwissPaymentSlipPdf\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Peter Siska", + "email": "pesche@gridonic.ch", + "homepage": "http://www.gridonic.ch", + "role": "Contributor" }, { - "name": "sabre/vobject", - "version": "4.2.2", - "version_normalized": "4.2.2.0", - "source": { - "type": "git", - "url": "https://github.com/sabre-io/vobject.git", - "reference": "449616b2d45b95c8973975de23f34a3d14f63b4b" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sabre-io/vobject/zipball/449616b2d45b95c8973975de23f34a3d14f63b4b", - "reference": "449616b2d45b95c8973975de23f34a3d14f63b4b", - "shasum": "" - }, - "require": { - "ext-mbstring": "*", - "php": ">=5.5", - "sabre/xml": ">=1.5 <3.0" - }, - "require-dev": { - "phpunit/phpunit": "> 4.8.35, <6.0.0" - }, - "suggest": { - "hoa/bench": "If you would like to run the benchmark scripts" - }, - "time": "2020-01-14T10:18:45+00:00", - "bin": [ - "bin/vobject", - "bin/generate_vcards" - ], - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "4.0.x-dev" - } - }, - "installation-source": "dist", - "autoload": { - "psr-4": { - "Sabre\\VObject\\": "lib/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Evert Pot", - "email": "me@evertpot.com", - "homepage": "http://evertpot.com/", - "role": "Developer" - }, - { - "name": "Dominik Tobschall", - "email": "dominik@fruux.com", - "homepage": "http://tobschall.de/", - "role": "Developer" - }, - { - "name": "Ivan Enderlin", - "email": "ivan.enderlin@hoa-project.net", - "homepage": "http://mnt.io/", - "role": "Developer" - } - ], - "description": "The VObject library for PHP allows you to easily parse and manipulate iCalendar and vCard objects", - "homepage": "http://sabre.io/vobject/", - "keywords": [ - "availability", - "freebusy", - "iCalendar", - "ical", - "ics", - "jCal", - "jCard", - "recurrence", - "rfc2425", - "rfc2426", - "rfc2739", - "rfc4770", - "rfc5545", - "rfc5546", - "rfc6321", - "rfc6350", - "rfc6351", - "rfc6474", - "rfc6638", - "rfc6715", - "rfc6868", - "vCalendar", - "vCard", - "vcf", - "xCal", - "xCard" - ], - "support": { - "forum": "https://groups.google.com/group/sabredav-discuss", - "issues": "https://github.com/sabre-io/vobject/issues", - "source": "https://github.com/fruux/sabre-vobject" - }, - "install-path": "../sabre/vobject" + "name": "Manuel Reinhard", + "email": "manu@sprain.ch", + "homepage": "http://www.sprain.ch", + "role": "Developer of the original class" }, { - "name": "sabre/xml", - "version": "1.5.1", - "version_normalized": "1.5.1.0", - "source": { - "type": "git", - "url": "https://github.com/sabre-io/xml.git", - "reference": "a367665f1df614c3b8fefc30a54de7cd295e444e" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sabre-io/xml/zipball/a367665f1df614c3b8fefc30a54de7cd295e444e", - "reference": "a367665f1df614c3b8fefc30a54de7cd295e444e", - "shasum": "" - }, - "require": { - "ext-dom": "*", - "ext-xmlreader": "*", - "ext-xmlwriter": "*", - "lib-libxml": ">=2.6.20", - "php": ">=5.5.5", - "sabre/uri": ">=1.0,<3.0.0" - }, - "require-dev": { - "phpunit/phpunit": "~4.8|~5.7", - "sabre/cs": "~1.0.0" - }, - "time": "2019-01-09T13:51:57+00:00", - "type": "library", - "installation-source": "dist", - "autoload": { - "psr-4": { - "Sabre\\Xml\\": "lib/" - }, - "files": [ - "lib/Deserializer/functions.php", - "lib/Serializer/functions.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Evert Pot", - "email": "me@evertpot.com", - "homepage": "http://evertpot.com/", - "role": "Developer" - }, - { - "name": "Markus Staab", - "email": "markus.staab@redaxo.de", - "role": "Developer" - } - ], - "description": "sabre/xml is an XML library that you may not hate.", - "homepage": "https://sabre.io/xml/", - "keywords": [ - "XMLReader", - "XMLWriter", - "dom", - "xml" - ], - "support": { - "forum": "https://groups.google.com/group/sabredav-discuss", - "issues": "https://github.com/sabre-io/xml/issues", - "source": "https://github.com/fruux/sabre-xml" - }, - "install-path": "../sabre/xml" + "name": "Marc Würth", + "email": "ravage@bluewin.ch", + "role": "Lead developer" + } + ], + "description": "An abstract base class for creating Swiss payment slips with reference number (ESR) or without (ES) using a pdf engine", + "homepage": "https://github.com/ravage84/SwissPaymentSlipPdf", + "keywords": [ + "ESR", + "Einzahlungsschein", + "Inpayment slip", + "Payment slip", + "es", + "pdf" + ], + "support": { + "email": "ravage@bluewin.ch", + "issues": "https://github.com/ravage84/SwissPaymentSlipPdf/issues", + "source": "https://github.com/ravage84/SwissPaymentSlipPdf" + }, + "install-path": "../swiss-payment-slip/swiss-payment-slip-pdf" + }, + { + "name": "symfony/polyfill-intl-idn", + "version": "v1.33.0", + "version_normalized": "1.33.0.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-intl-idn.git", + "reference": "9614ac4d8061dc257ecc64cba1b140873dce8ad3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/9614ac4d8061dc257ecc64cba1b140873dce8ad3", + "reference": "9614ac4d8061dc257ecc64cba1b140873dce8ad3", + "shasum": "" + }, + "require": { + "php": ">=7.2", + "symfony/polyfill-intl-normalizer": "^1.10" + }, + "suggest": { + "ext-intl": "For best performance" + }, + "time": "2024-09-10T14:38:51+00:00", + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "installation-source": "dist", + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Intl\\Idn\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Laurent Bassin", + "email": "laurent@bassin.info" }, { - "name": "smarty/smarty", - "version": "v3.1.39", - "version_normalized": "3.1.39.0", - "source": { - "type": "git", - "url": "https://github.com/smarty-php/smarty.git", - "reference": "e27da524f7bcd7361e3ea5cdfa99c4378a7b5419" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/smarty-php/smarty/zipball/e27da524f7bcd7361e3ea5cdfa99c4378a7b5419", - "reference": "e27da524f7bcd7361e3ea5cdfa99c4378a7b5419", - "shasum": "" - }, - "require": { - "php": ">=5.2" - }, - "require-dev": { - "phpunit/phpunit": "^7.5 || ^6.5 || ^5.7 || ^4.8", - "smarty/smarty-lexer": "^3.1" - }, - "time": "2021-02-17T21:57:51+00:00", - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.1.x-dev" - } - }, - "installation-source": "dist", - "autoload": { - "classmap": [ - "libs/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "LGPL-3.0" - ], - "authors": [ - { - "name": "Monte Ohrt", - "email": "monte@ohrt.com" - }, - { - "name": "Uwe Tews", - "email": "uwe.tews@googlemail.com" - }, - { - "name": "Rodney Rehm", - "email": "rodney.rehm@medialize.de" - } - ], - "description": "Smarty - the compiling PHP template engine", - "homepage": "http://www.smarty.net", - "keywords": [ - "templating" - ], - "support": { - "forum": "http://www.smarty.net/forums/", - "irc": "irc://irc.freenode.org/smarty", - "issues": "https://github.com/smarty-php/smarty/issues", - "source": "https://github.com/smarty-php/smarty/tree/v3.1.39" - }, - "install-path": "../smarty/smarty" + "name": "Trevor Rowbotham", + "email": "trevor.rowbotham@pm.me" }, { - "name": "swiss-payment-slip/swiss-payment-slip", - "version": "0.13.0", - "version_normalized": "0.13.0.0", - "source": { - "type": "git", - "url": "https://github.com/ravage84/SwissPaymentSlip.git", - "reference": "3f5e23552e59ff486318c3af66b0374fa61a176f" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/ravage84/SwissPaymentSlip/zipball/3f5e23552e59ff486318c3af66b0374fa61a176f", - "reference": "3f5e23552e59ff486318c3af66b0374fa61a176f", - "shasum": "" - }, - "require": { - "php": ">=5.4.0" - }, - "require-dev": { - "phpunit/phpunit": "^4.0.0", - "squizlabs/php_codesniffer": "^2.1.0" - }, - "time": "2019-02-27T15:06:58+00:00", - "type": "library", - "installation-source": "dist", - "autoload": { - "psr-4": { - "SwissPaymentSlip\\SwissPaymentSlip\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Peter Siska", - "email": "pesche@gridonic.ch", - "homepage": "http://www.gridonic.ch", - "role": "Contributor" - }, - { - "name": "Manuel Reinhard", - "email": "manu@sprain.ch", - "homepage": "http://www.sprain.ch", - "role": "Developer of the original class" - }, - { - "name": "Marc Würth", - "email": "ravage@bluewin.ch", - "role": "Lead developer" - } - ], - "description": "A library for creating Swiss payment slips (ESR)", - "homepage": "https://github.com/ravage84/SwissPaymentSlip", - "keywords": [ - "ESR", - "Einzahlungsschein", - "Inpayment slip", - "Payment slip" - ], - "support": { - "email": "ravage@bluewin.ch", - "issues": "https://github.com/ravage84/SwissPaymentSlip/issues", - "source": "https://github.com/ravage84/SwissPaymentSlip" - }, - "install-path": "../swiss-payment-slip/swiss-payment-slip" + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for intl's idn_to_ascii and idn_to_utf8 functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "idn", + "intl", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.33.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" }, { - "name": "swiss-payment-slip/swiss-payment-slip-fpdf", - "version": "0.6.0", - "version_normalized": "0.6.0.0", - "source": { - "type": "git", - "url": "https://github.com/ravage84/SwissPaymentSlipFpdf.git", - "reference": "72f722188d89b2651d4751ab812146cb1f165061" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/ravage84/SwissPaymentSlipFpdf/zipball/72f722188d89b2651d4751ab812146cb1f165061", - "reference": "72f722188d89b2651d4751ab812146cb1f165061", - "shasum": "" - }, - "require": { - "itbz/fpdf": "1.7.*", - "php": ">=5.3.0", - "swiss-payment-slip/swiss-payment-slip-pdf": "0.13.*" - }, - "require-dev": { - "phpunit/phpunit": "3.7.38", - "squizlabs/php_codesniffer": "2.1.*" - }, - "time": "2015-04-01T14:55:48+00:00", - "type": "library", - "installation-source": "dist", - "autoload": { - "psr-4": { - "SwissPaymentSlip\\SwissPaymentSlipFpdf\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Peter Siska", - "email": "pesche@gridonic.ch", - "homepage": "http://www.gridonic.ch", - "role": "Contributor" - }, - { - "name": "Manuel Reinhard", - "email": "manu@sprain.ch", - "homepage": "http://www.sprain.ch", - "role": "Developer of the original class" - }, - { - "name": "Marc Würth", - "email": "ravage@bluewin.ch", - "homepage": "https://github.com/ravage84", - "role": "Lead developer" - } - ], - "description": "Create Swiss payment slips with reference number (ESR) or without (ES) as PDFs with FPDF", - "homepage": "https://github.com/ravage84/SwissPaymentSlipFpdf", - "keywords": [ - "ESR", - "Einzahlungsschein", - "Inpayment slip", - "Payment slip", - "es", - "fpdf", - "pdf" - ], - "support": { - "email": "ravage@bluewin.ch", - "issues": "https://github.com/ravage84/SwissPaymentSlipFpdf/issues", - "source": "https://github.com/ravage84/SwissPaymentSlipFpdf" - }, - "install-path": "../swiss-payment-slip/swiss-payment-slip-fpdf" + "url": "https://github.com/fabpot", + "type": "github" }, { - "name": "swiss-payment-slip/swiss-payment-slip-pdf", - "version": "0.13.1", - "version_normalized": "0.13.1.0", - "source": { - "type": "git", - "url": "https://github.com/ravage84/SwissPaymentSlipPdf.git", - "reference": "4355743b2406875e9fed2117d8df445ba6848be4" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/ravage84/SwissPaymentSlipPdf/zipball/4355743b2406875e9fed2117d8df445ba6848be4", - "reference": "4355743b2406875e9fed2117d8df445ba6848be4", - "shasum": "" - }, - "require": { - "php": ">=5.3.0", - "swiss-payment-slip/swiss-payment-slip": "0.11.1" - }, - "require-dev": { - "phpunit/phpunit": "3.7.38", - "squizlabs/php_codesniffer": "2.1.*" - }, - "time": "2015-02-18T20:04:44+00:00", - "type": "library", - "installation-source": "dist", - "autoload": { - "psr-4": { - "SwissPaymentSlip\\SwissPaymentSlipPdf\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Peter Siska", - "email": "pesche@gridonic.ch", - "homepage": "http://www.gridonic.ch", - "role": "Contributor" - }, - { - "name": "Manuel Reinhard", - "email": "manu@sprain.ch", - "homepage": "http://www.sprain.ch", - "role": "Developer of the original class" - }, - { - "name": "Marc Würth", - "email": "ravage@bluewin.ch", - "role": "Lead developer" - } - ], - "description": "An abstract base class for creating Swiss payment slips with reference number (ESR) or without (ES) using a pdf engine", - "homepage": "https://github.com/ravage84/SwissPaymentSlipPdf", - "keywords": [ - "ESR", - "Einzahlungsschein", - "Inpayment slip", - "Payment slip", - "es", - "pdf" - ], - "support": { - "email": "ravage@bluewin.ch", - "issues": "https://github.com/ravage84/SwissPaymentSlipPdf/issues", - "source": "https://github.com/ravage84/SwissPaymentSlipPdf" - }, - "install-path": "../swiss-payment-slip/swiss-payment-slip-pdf" + "url": "https://github.com/nicolas-grekas", + "type": "github" }, { - "name": "symfony/polyfill-intl-idn", - "version": "v1.31.0", - "version_normalized": "1.31.0.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/polyfill-intl-idn.git", - "reference": "c36586dcf89a12315939e00ec9b4474adcb1d773" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/c36586dcf89a12315939e00ec9b4474adcb1d773", - "reference": "c36586dcf89a12315939e00ec9b4474adcb1d773", - "shasum": "" - }, - "require": { - "php": ">=7.2", - "symfony/polyfill-intl-normalizer": "^1.10" - }, - "suggest": { - "ext-intl": "For best performance" - }, - "time": "2024-09-09T11:45:10+00:00", - "type": "library", - "extra": { - "thanks": { - "url": "https://github.com/symfony/polyfill", - "name": "symfony/polyfill" - } - }, - "installation-source": "dist", - "autoload": { - "files": [ - "bootstrap.php" - ], - "psr-4": { - "Symfony\\Polyfill\\Intl\\Idn\\": "" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Laurent Bassin", - "email": "laurent@bassin.info" - }, - { - "name": "Trevor Rowbotham", - "email": "trevor.rowbotham@pm.me" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony polyfill for intl's idn_to_ascii and idn_to_utf8 functions", - "homepage": "https://symfony.com", - "keywords": [ - "compatibility", - "idn", - "intl", - "polyfill", - "portable", - "shim" - ], - "support": { - "source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.31.0" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "install-path": "../symfony/polyfill-intl-idn" + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "install-path": "../symfony/polyfill-intl-idn" + }, + { + "name": "symfony/polyfill-intl-normalizer", + "version": "v1.33.0", + "version_normalized": "1.33.0.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-intl-normalizer.git", + "reference": "3833d7255cc303546435cb650316bff708a1c75c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/3833d7255cc303546435cb650316bff708a1c75c", + "reference": "3833d7255cc303546435cb650316bff708a1c75c", + "shasum": "" + }, + "require": { + "php": ">=7.2" + }, + "suggest": { + "ext-intl": "For best performance" + }, + "time": "2024-09-09T11:45:10+00:00", + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "installation-source": "dist", + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Intl\\Normalizer\\": "" }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ { - "name": "symfony/polyfill-intl-normalizer", - "version": "v1.31.0", - "version_normalized": "1.31.0.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/polyfill-intl-normalizer.git", - "reference": "3833d7255cc303546435cb650316bff708a1c75c" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/3833d7255cc303546435cb650316bff708a1c75c", - "reference": "3833d7255cc303546435cb650316bff708a1c75c", - "shasum": "" - }, - "require": { - "php": ">=7.2" - }, - "suggest": { - "ext-intl": "For best performance" - }, - "time": "2024-09-09T11:45:10+00:00", - "type": "library", - "extra": { - "thanks": { - "url": "https://github.com/symfony/polyfill", - "name": "symfony/polyfill" - } - }, - "installation-source": "dist", - "autoload": { - "files": [ - "bootstrap.php" - ], - "psr-4": { - "Symfony\\Polyfill\\Intl\\Normalizer\\": "" - }, - "classmap": [ - "Resources/stubs" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony polyfill for intl's Normalizer class and related functions", - "homepage": "https://symfony.com", - "keywords": [ - "compatibility", - "intl", - "normalizer", - "polyfill", - "portable", - "shim" - ], - "support": { - "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.31.0" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "install-path": "../symfony/polyfill-intl-normalizer" + "name": "Nicolas Grekas", + "email": "p@tchwork.com" }, { - "name": "symfony/polyfill-mbstring", - "version": "v1.31.0", - "version_normalized": "1.31.0.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "85181ba99b2345b0ef10ce42ecac37612d9fd341" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/85181ba99b2345b0ef10ce42ecac37612d9fd341", - "reference": "85181ba99b2345b0ef10ce42ecac37612d9fd341", - "shasum": "" - }, - "require": { - "php": ">=7.2" - }, - "provide": { - "ext-mbstring": "*" - }, - "suggest": { - "ext-mbstring": "For best performance" - }, - "time": "2024-09-09T11:45:10+00:00", - "type": "library", - "extra": { - "thanks": { - "url": "https://github.com/symfony/polyfill", - "name": "symfony/polyfill" - } - }, - "installation-source": "dist", - "autoload": { - "files": [ - "bootstrap.php" - ], - "psr-4": { - "Symfony\\Polyfill\\Mbstring\\": "" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony polyfill for the Mbstring extension", - "homepage": "https://symfony.com", - "keywords": [ - "compatibility", - "mbstring", - "polyfill", - "portable", - "shim" - ], - "support": { - "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.31.0" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "install-path": "../symfony/polyfill-mbstring" + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for intl's Normalizer class and related functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "intl", + "normalizer", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.33.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" }, { - "name": "tecnickcom/tcpdf", - "version": "6.3.5", - "version_normalized": "6.3.5.0", - "source": { - "type": "git", - "url": "https://github.com/tecnickcom/TCPDF.git", - "reference": "19a535eaa7fb1c1cac499109deeb1a7a201b4549" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/tecnickcom/TCPDF/zipball/19a535eaa7fb1c1cac499109deeb1a7a201b4549", - "reference": "19a535eaa7fb1c1cac499109deeb1a7a201b4549", - "shasum": "" - }, - "require": { - "php": ">=5.3.0" - }, - "time": "2020-02-14T14:20:12+00:00", - "type": "library", - "installation-source": "dist", - "autoload": { - "classmap": [ - "config", - "include", - "tcpdf.php", - "tcpdf_parser.php", - "tcpdf_import.php", - "tcpdf_barcodes_1d.php", - "tcpdf_barcodes_2d.php", - "include/tcpdf_colors.php", - "include/tcpdf_filters.php", - "include/tcpdf_font_data.php", - "include/tcpdf_fonts.php", - "include/tcpdf_images.php", - "include/tcpdf_static.php", - "include/barcodes/datamatrix.php", - "include/barcodes/pdf417.php", - "include/barcodes/qrcode.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "LGPL-3.0-only" - ], - "authors": [ - { - "name": "Nicola Asuni", - "email": "info@tecnick.com", - "role": "lead" - } - ], - "description": "TCPDF is a PHP class for generating PDF documents and barcodes.", - "homepage": "http://www.tcpdf.org/", - "keywords": [ - "PDFD32000-2008", - "TCPDF", - "barcodes", - "datamatrix", - "pdf", - "pdf417", - "qrcode" - ], - "support": { - "issues": "https://github.com/tecnickcom/TCPDF/issues", - "source": "https://github.com/tecnickcom/TCPDF/tree/6.3.5" - }, - "install-path": "../tecnickcom/tcpdf" + "url": "https://github.com/fabpot", + "type": "github" }, { - "name": "webmozart/assert", - "version": "1.11.0", - "version_normalized": "1.11.0.0", - "source": { - "type": "git", - "url": "https://github.com/webmozarts/assert.git", - "reference": "11cb2199493b2f8a3b53e7f19068fc6aac760991" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/webmozarts/assert/zipball/11cb2199493b2f8a3b53e7f19068fc6aac760991", - "reference": "11cb2199493b2f8a3b53e7f19068fc6aac760991", - "shasum": "" - }, - "require": { - "ext-ctype": "*", - "php": "^7.2 || ^8.0" - }, - "conflict": { - "phpstan/phpstan": "<0.12.20", - "vimeo/psalm": "<4.6.1 || 4.6.2" - }, - "require-dev": { - "phpunit/phpunit": "^8.5.13" - }, - "time": "2022-06-03T18:03:27+00:00", - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.10-dev" - } - }, - "installation-source": "dist", - "autoload": { - "psr-4": { - "Webmozart\\Assert\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Bernhard Schussek", - "email": "bschussek@gmail.com" - } - ], - "description": "Assertions to validate method input/output with nice error messages.", - "keywords": [ - "assert", - "check", - "validate" - ], - "support": { - "issues": "https://github.com/webmozarts/assert/issues", - "source": "https://github.com/webmozarts/assert/tree/1.11.0" - }, - "install-path": "../webmozart/assert" + "url": "https://github.com/nicolas-grekas", + "type": "github" }, { - "name": "y0lk/oauth1-etsy", - "version": "1.1.0", - "version_normalized": "1.1.0.0", - "source": { - "type": "git", - "url": "https://github.com/Y0lk/oauth1-etsy.git", - "reference": "3fef9d03787e01a72ef19cdcbbc243c166a5d425" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/Y0lk/oauth1-etsy/zipball/3fef9d03787e01a72ef19cdcbbc243c166a5d425", - "reference": "3fef9d03787e01a72ef19cdcbbc243c166a5d425", - "shasum": "" - }, - "require": { - "league/oauth1-client": "^1.7.0", - "php": ">=7.0" - }, - "require-dev": { - "phpunit/phpunit": "~6.0" - }, - "time": "2021-02-03T16:15:30+00:00", - "type": "library", - "installation-source": "dist", - "autoload": { - "psr-4": { - "Y0lk\\OAuth1\\Client\\Server\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Y0lk", - "email": "gabriel@inkrebit.com", - "homepage": "https://github.com/Y0lk" - } - ], - "description": "Etsy API OAuth 1.0 Client Provider for The PHP League OAuth1-Client", - "keywords": [ - "authorisation", - "authorization", - "client", - "etsy", - "oauth", - "oauth1" - ], - "support": { - "issues": "https://github.com/Y0lk/oauth1-etsy/issues", - "source": "https://github.com/Y0lk/oauth1-etsy/tree/1.1.0" - }, - "install-path": "../y0lk/oauth1-etsy" - } - ], - "dev": true, - "dev-package-names": [] + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "install-path": "../symfony/polyfill-intl-normalizer" + }, + { + "name": "symfony/polyfill-mbstring", + "version": "v1.33.0", + "version_normalized": "1.33.0.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-mbstring.git", + "reference": "6d857f4d76bd4b343eac26d6b539585d2bc56493" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/6d857f4d76bd4b343eac26d6b539585d2bc56493", + "reference": "6d857f4d76bd4b343eac26d6b539585d2bc56493", + "shasum": "" + }, + "require": { + "ext-iconv": "*", + "php": ">=7.2" + }, + "provide": { + "ext-mbstring": "*" + }, + "suggest": { + "ext-mbstring": "For best performance" + }, + "time": "2024-12-23T08:48:59+00:00", + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "installation-source": "dist", + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Mbstring\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for the Mbstring extension", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "mbstring", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.33.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "install-path": "../symfony/polyfill-mbstring" + }, + { + "name": "tecnickcom/tcpdf", + "version": "6.3.5", + "version_normalized": "6.3.5.0", + "source": { + "type": "git", + "url": "https://github.com/tecnickcom/TCPDF.git", + "reference": "19a535eaa7fb1c1cac499109deeb1a7a201b4549" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/tecnickcom/TCPDF/zipball/19a535eaa7fb1c1cac499109deeb1a7a201b4549", + "reference": "19a535eaa7fb1c1cac499109deeb1a7a201b4549", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "time": "2020-02-14T14:20:12+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "classmap": [ + "config", + "include", + "tcpdf.php", + "tcpdf_parser.php", + "tcpdf_import.php", + "tcpdf_barcodes_1d.php", + "tcpdf_barcodes_2d.php", + "include/tcpdf_colors.php", + "include/tcpdf_filters.php", + "include/tcpdf_font_data.php", + "include/tcpdf_fonts.php", + "include/tcpdf_images.php", + "include/tcpdf_static.php", + "include/barcodes/datamatrix.php", + "include/barcodes/pdf417.php", + "include/barcodes/qrcode.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "LGPL-3.0-only" + ], + "authors": [ + { + "name": "Nicola Asuni", + "email": "info@tecnick.com", + "role": "lead" + } + ], + "description": "TCPDF is a PHP class for generating PDF documents and barcodes.", + "homepage": "http://www.tcpdf.org/", + "keywords": [ + "PDFD32000-2008", + "TCPDF", + "barcodes", + "datamatrix", + "pdf", + "pdf417", + "qrcode" + ], + "support": { + "issues": "https://github.com/tecnickcom/TCPDF/issues", + "source": "https://github.com/tecnickcom/TCPDF/tree/6.3.5" + }, + "install-path": "../tecnickcom/tcpdf" + }, + { + "name": "webmozart/assert", + "version": "1.12.1", + "version_normalized": "1.12.1.0", + "source": { + "type": "git", + "url": "https://github.com/webmozarts/assert.git", + "reference": "9be6926d8b485f55b9229203f962b51ed377ba68" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/webmozarts/assert/zipball/9be6926d8b485f55b9229203f962b51ed377ba68", + "reference": "9be6926d8b485f55b9229203f962b51ed377ba68", + "shasum": "" + }, + "require": { + "ext-ctype": "*", + "ext-date": "*", + "ext-filter": "*", + "php": "^7.2 || ^8.0" + }, + "suggest": { + "ext-intl": "", + "ext-simplexml": "", + "ext-spl": "" + }, + "time": "2025-10-29T15:56:20+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.10-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Webmozart\\Assert\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Bernhard Schussek", + "email": "bschussek@gmail.com" + } + ], + "description": "Assertions to validate method input/output with nice error messages.", + "keywords": [ + "assert", + "check", + "validate" + ], + "support": { + "issues": "https://github.com/webmozarts/assert/issues", + "source": "https://github.com/webmozarts/assert/tree/1.12.1" + }, + "install-path": "../webmozart/assert" + } + ], + "dev": true, + "dev-package-names": [] } diff --git a/vendor/composer/installed.php b/vendor/composer/installed.php index 1292bc1b3..0a6d9789e 100644 --- a/vendor/composer/installed.php +++ b/vendor/composer/installed.php @@ -113,9 +113,9 @@ ), ), 'laminas/laminas-loader' => array( - 'pretty_version' => '2.11.1', - 'version' => '2.11.1.0', - 'reference' => 'c507d5eccb969f7208434e3980680a1f6c0b1d8d', + 'pretty_version' => '2.12.0', + 'version' => '2.12.0.0', + 'reference' => 'ec8cee33fb254ee4d9c8e8908c870e5c797e1272', 'type' => 'library', 'install_path' => __DIR__ . '/../laminas/laminas-loader', 'aliases' => array(), @@ -140,9 +140,9 @@ 'dev_requirement' => false, ), 'laminas/laminas-servicemanager' => array( - 'pretty_version' => '3.23.0', - 'version' => '3.23.0.0', - 'reference' => 'a8640182b892b99767d54404d19c5c3b3699f79b', + 'pretty_version' => '3.23.1', + 'version' => '3.23.1.0', + 'reference' => '06594db3a644447521eace9b5efdb12dc8446a33', 'type' => 'library', 'install_path' => __DIR__ . '/../laminas/laminas-servicemanager', 'aliases' => array(), @@ -158,9 +158,9 @@ 'dev_requirement' => false, ), 'laminas/laminas-validator' => array( - 'pretty_version' => '2.64.2', - 'version' => '2.64.2.0', - 'reference' => '771e504760448ac7af660710237ceb93be602e08', + 'pretty_version' => '2.64.4', + 'version' => '2.64.4.0', + 'reference' => 'e2e6631f599a9b0db1e23adb633c09a2f0c68bed', 'type' => 'library', 'install_path' => __DIR__ . '/../laminas/laminas-validator', 'aliases' => array(), @@ -193,15 +193,6 @@ 'aliases' => array(), 'dev_requirement' => false, ), - 'league/oauth1-client' => array( - 'pretty_version' => 'v1.9.0', - 'version' => '1.9.0.0', - 'reference' => '1e7e6be2dc543bf466236fb171e5b20e1b06aee6', - 'type' => 'library', - 'install_path' => __DIR__ . '/../league/oauth1-client', - 'aliases' => array(), - 'dev_requirement' => false, - ), 'lfkeitel/phptotp' => array( 'pretty_version' => 'v1.1.0', 'version' => '1.1.0.0', @@ -394,17 +385,17 @@ 'dev_requirement' => false, ), 'symfony/polyfill-intl-idn' => array( - 'pretty_version' => 'v1.31.0', - 'version' => '1.31.0.0', - 'reference' => 'c36586dcf89a12315939e00ec9b4474adcb1d773', + 'pretty_version' => 'v1.33.0', + 'version' => '1.33.0.0', + 'reference' => '9614ac4d8061dc257ecc64cba1b140873dce8ad3', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/polyfill-intl-idn', 'aliases' => array(), 'dev_requirement' => false, ), 'symfony/polyfill-intl-normalizer' => array( - 'pretty_version' => 'v1.31.0', - 'version' => '1.31.0.0', + 'pretty_version' => 'v1.33.0', + 'version' => '1.33.0.0', 'reference' => '3833d7255cc303546435cb650316bff708a1c75c', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/polyfill-intl-normalizer', @@ -412,9 +403,9 @@ 'dev_requirement' => false, ), 'symfony/polyfill-mbstring' => array( - 'pretty_version' => 'v1.31.0', - 'version' => '1.31.0.0', - 'reference' => '85181ba99b2345b0ef10ce42ecac37612d9fd341', + 'pretty_version' => 'v1.33.0', + 'version' => '1.33.0.0', + 'reference' => '6d857f4d76bd4b343eac26d6b539585d2bc56493', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/polyfill-mbstring', 'aliases' => array(), @@ -430,22 +421,13 @@ 'dev_requirement' => false, ), 'webmozart/assert' => array( - 'pretty_version' => '1.11.0', - 'version' => '1.11.0.0', - 'reference' => '11cb2199493b2f8a3b53e7f19068fc6aac760991', + 'pretty_version' => '1.12.1', + 'version' => '1.12.1.0', + 'reference' => '9be6926d8b485f55b9229203f962b51ed377ba68', 'type' => 'library', 'install_path' => __DIR__ . '/../webmozart/assert', 'aliases' => array(), 'dev_requirement' => false, ), - 'y0lk/oauth1-etsy' => array( - 'pretty_version' => '1.1.0', - 'version' => '1.1.0.0', - 'reference' => '3fef9d03787e01a72ef19cdcbbc243c166a5d425', - 'type' => 'library', - 'install_path' => __DIR__ . '/../y0lk/oauth1-etsy', - 'aliases' => array(), - 'dev_requirement' => false, - ), ), ); diff --git a/vendor/datto/json-rpc-http/.gitignore b/vendor/datto/json-rpc-http/.gitignore new file mode 100644 index 000000000..d725f0fbb --- /dev/null +++ b/vendor/datto/json-rpc-http/.gitignore @@ -0,0 +1,5 @@ +/.idea/ +vendor/ +/.source +composer.lock +*.swp \ No newline at end of file diff --git a/vendor/datto/json-rpc-http/composer.json b/vendor/datto/json-rpc-http/composer.json new file mode 100644 index 000000000..10ae97365 --- /dev/null +++ b/vendor/datto/json-rpc-http/composer.json @@ -0,0 +1,26 @@ +{ + "name": "datto/json-rpc-http", + "type": "library", + "description": "HTTP client and server for JSON-RPC 2.0", + "keywords": ["php", "json", "rpc", "jsonrpc", "json-rpc", "php-json-rpc", "http", "client", "server"], + "homepage": "http://datto.com", + "license": "LGPL-3.0+", + "authors": [ + { + "name": "Spencer Mortensen", + "email": "smortensen@datto.com", + "homepage": "http://spencermortensen.com", + "role": "Developer" + } + ], + "require": { + "php": ">=7.0.0", + "datto/json-rpc": "~6.1" + }, + "autoload": { + "psr-4": { + "Datto\\JsonRpc\\Http\\Examples\\": "examples/src", + "Datto\\JsonRpc\\Http\\": "src" + } + } +} diff --git a/vendor/datto/json-rpc/.gitignore b/vendor/datto/json-rpc/.gitignore new file mode 100644 index 000000000..041bcb86e --- /dev/null +++ b/vendor/datto/json-rpc/.gitignore @@ -0,0 +1,6 @@ +.git/ +vendor/ +coverage/ +.idea/ +.source +composer.lock diff --git a/vendor/datto/json-rpc/composer.json b/vendor/datto/json-rpc/composer.json new file mode 100644 index 000000000..27ec6a81a --- /dev/null +++ b/vendor/datto/json-rpc/composer.json @@ -0,0 +1,33 @@ +{ + "name": "datto/json-rpc", + "type": "library", + "description": "Fully unit-tested JSON-RPC 2.0 for PHP", + "keywords": ["php", "json", "rpc", "jsonrpc", "json-rpc", "php-json-rpc"], + "homepage": "http://datto.com", + "license": "LGPL-3.0+", + "authors": [ + { + "name": "Spencer Mortensen", + "email": "smortensen@datto.com", + "homepage": "http://spencermortensen.com", + "role": "Developer" + } + ], + "require": { + "php": ">=7.0.0" + }, + "require-dev": { + "phpunit/phpunit": "^6.5" + }, + "autoload": { + "psr-4": { + "Datto\\JsonRpc\\": "src" + } + }, + "autoload-dev": { + "psr-4": { + "Datto\\JsonRpc\\Examples\\": "examples/src", + "Datto\\JsonRpc\\Tests\\": "tests" + } + } +} diff --git a/vendor/datto/json-rpc/tests/Api.php b/vendor/datto/json-rpc/tests/Api.php new file mode 100644 index 000000000..5b6083cea --- /dev/null +++ b/vendor/datto/json-rpc/tests/Api.php @@ -0,0 +1,94 @@ +. + * + * @author Spencer Mortensen + * @license http://www.gnu.org/licenses/lgpl-3.0.html LGPL-3.0 + * @copyright 2015 Datto, Inc. + */ + +namespace Datto\JsonRpc\Tests; + +use Datto\JsonRpc\Evaluator; +use Datto\JsonRpc\Exceptions; + +class Api implements Evaluator +{ + public function evaluate($method, $arguments) + { + switch ($method) { + case 'subtract': + return self::subtract($arguments); + + case 'implementation error': + return self::implementationError($arguments); + + case 'invalid implementation error': + return self::invalidImplementationError(); + + case 'application error': + return self::applicationError($arguments); + + case 'invalid application error': + return self::invalidApplicationError(); + + default: + throw new Exceptions\MethodException(); + } + } + + private static function subtract($arguments) + { + if (isset($arguments[0])) { + @list($a, $b) = $arguments; + } else { + $a = @$arguments['minuend']; + $b = @$arguments['subtrahend']; + } + + if (!is_int($a) || !is_int($b) || (count($arguments) !== 2)) { + throw new Exceptions\ArgumentException(); + } + + return $a - $b; + } + + private static function implementationError($arguments) + { + throw new Exceptions\ImplementationException(-32099, @$arguments[0]); + } + + private static function invalidImplementationError() + { + $invalid = new \StdClass(); + + throw new Exceptions\ImplementationException($invalid, $invalid); + } + + private static function applicationError($arguments) + { + throw new Exceptions\ApplicationException("Application error", 1, @$arguments[0]); + } + + private static function invalidApplicationError() + { + $invalid = new \StdClass(); + + throw new Exceptions\ApplicationException($invalid, $invalid, $invalid); + } +} diff --git a/vendor/datto/json-rpc/tests/ClientTest.php b/vendor/datto/json-rpc/tests/ClientTest.php new file mode 100644 index 000000000..ce6481c1b --- /dev/null +++ b/vendor/datto/json-rpc/tests/ClientTest.php @@ -0,0 +1,114 @@ +. + * + * @author Spencer Mortensen + * @license http://www.gnu.org/licenses/lgpl-3.0.html LGPL-3.0 + * @copyright 2015 Datto, Inc. + */ + +namespace Datto\JsonRpc\Tests; + +use PHPUnit\Framework\TestCase; +use Datto\JsonRpc\Client; +use Datto\JsonRpc\Responses\ResultResponse; +use Datto\JsonRpc\Responses\ErrorResponse; + +class ClientTest extends TestCase +{ + public function testNotification() + { + $client = new Client(); + $client->notify('subtract', array(3, 2)); + + $this->compare($client, '{"jsonrpc":"2.0","method":"subtract","params":[3,2]}'); + } + + public function testQuery() + { + $client = new Client(); + $client->query(1, 'subtract', array(3, 2)); + + $this->compare($client, '{"jsonrpc":"2.0","id":1,"method":"subtract","params":[3,2]}'); + } + + public function testBatch() + { + $client = new Client(); + $client->query(1, 'subtract', array(3, 2)); + $client->notify('subtract', array(4, 3)); + + $this->compare($client, '[{"jsonrpc":"2.0","id":1,"method":"subtract","params":[3,2]},{"jsonrpc":"2.0","method":"subtract","params":[4,3]}]'); + } + + public function testEmpty() + { + $client = new Client(); + + $this->compare($client, null); + } + + public function testReset() + { + $client = new Client(); + $client->notify('subtract', array(3, 2)); + $client->encode(); + + $this->compare($client, null); + } + + public function testDecodeResult() + { + $reply = '{"jsonrpc":"2.0","result":2,"id":1}'; + + $client = new Client(); + $actualOutput = $client->decode($reply); + $expectedOutput = [new ResultResponse(1, 2)]; + + $this->assertSameValues($expectedOutput, $actualOutput); + } + + public function testDecodeError() + { + $reply = '{"jsonrpc":"2.0","id":1,"error":{"code":-32601,"message":"Method not found"}}'; + + $client = new Client(); + $actualOutput = $client->decode($reply); + $expectedOutput = [new ErrorResponse(1, 'Method not found', -32601)]; + + $this->assertSameValues($expectedOutput, $actualOutput); + } + + private function assertSameValues($expected, $actual) + { + $expectedPhp = var_export($expected, true); + $actualPhp = var_export($actual, true); + + $this->assertSame($expectedPhp, $actualPhp); + } + + private function compare(Client $client, $expectedJsonOutput) + { + $actualJsonOutput = $client->encode(); + + $expectedOutput = @json_decode($expectedJsonOutput, true); + $actualOutput = @json_decode($actualJsonOutput, true); + + $this->assertEquals($expectedOutput, $actualOutput); + } +} diff --git a/vendor/datto/json-rpc/tests/ServerTest.php b/vendor/datto/json-rpc/tests/ServerTest.php new file mode 100644 index 000000000..181456c96 --- /dev/null +++ b/vendor/datto/json-rpc/tests/ServerTest.php @@ -0,0 +1,304 @@ +. + * + * @author Spencer Mortensen + * @license http://www.gnu.org/licenses/lgpl-3.0.html LGPL-3.0 + * @copyright 2015 Datto, Inc. + */ + +namespace Datto\JsonRpc\Tests; + +use PHPUnit\Framework\TestCase; +use Datto\JsonRpc\Server; + +class ServerTest extends TestCase +{ + public function testArgumentsPositionalA() + { + $input = '{"jsonrpc": "2.0", "id": 1, "method": "subtract", "params": [3, 2]}'; + + $output = '{"jsonrpc": "2.0", "id": 1, "result": 1}'; + + $this->compare($input, $output); + } + + public function testArgumentsPositionalB() + { + $input = '{"jsonrpc": "2.0", "id": 1, "method": "subtract", "params": [2, 3]}'; + + $output = '{"jsonrpc": "2.0", "id": 1, "result": -1}'; + + $this->compare($input, $output); + } + + public function testArgumentsNamedA() + { + $input = '{"jsonrpc": "2.0", "id": 1, "method": "subtract", "params": {"minuend": 3, "subtrahend": 2}}'; + + $output = '{"jsonrpc": "2.0", "id": 1, "result": 1}'; + + $this->compare($input, $output); + } + + public function testArgumentsInvalid() + { + $input = '{"jsonrpc": "2.0", "id": 1, "method": "subtract", "params": []}'; + + $output = '{"jsonrpc": "2.0", "id": 1, "error": {"code": -32602, "message": "Invalid params"}}'; + + $this->compare($input, $output); + } + + public function testArgumentsNamedB() + { + $input = '{"jsonrpc": "2.0", "id": 1, "method": "subtract", "params": {"subtrahend": 2, "minuend": 3}}'; + + $output = '{"jsonrpc": "2.0", "id": 1, "result": 1}'; + + $this->compare($input, $output); + } + + public function testNotificationArguments() + { + $input = '{"jsonrpc": "2.0", "method": "subtract", "params": [3, 2]}'; + + $output = 'null'; + + $this->compare($input, $output); + } + + public function testNotification() + { + $input = '{"jsonrpc": "2.0", "method": "subtract"}'; + + $output = 'null'; + + $this->compare($input, $output); + } + + public function testUndefinedMethod() + { + $input ='{"jsonrpc": "2.0", "id": 1, "method": "undefined"}'; + + $output = '{"jsonrpc": "2.0", "id": 1, "error": {"code": -32601, "message": "Method not found"}}'; + + $this->compare($input, $output); + } + + public function testInvalidJson() + { + $input = '{"jsonrpc": "2.0", "method": "foobar", "params": "bar", "baz]'; + + $output = '{"jsonrpc": "2.0", "id": null, "error": {"code": -32700, "message": "Parse error"}}'; + + $this->compare($input, $output); + } + + public function testMissingJsonrpcVersion() + { + $input = '{"method": "subtract", "params": [3, 2], "id": 1}'; + + $output = '{"jsonrpc": "2.0", "id": 1, "error": {"code": -32600, "message": "Invalid Request"}}'; + + $this->compare($input, $output); + } + + public function testInvalidJsonrpcVersion() + { + $input = '{"jsonrpc": "2.1", "id": 1, "method": "subtract", "params": [3, 2]}'; + + $output = '{"jsonrpc": "2.0", "id": 1, "error": {"code": -32600, "message": "Invalid Request"}}'; + + $this->compare($input, $output); + } + + public function testInvalidMethod() + { + $input = '{"jsonrpc": "2.0", "method": 1, "params": [1, 2]}'; + + $output = '{"jsonrpc": "2.0", "id": null, "error": {"code": -32600, "message": "Invalid Request"}}'; + + $this->compare($input, $output); + } + + public function testInvalidParams() + { + $input = '{"jsonrpc": "2.0", "method": "foobar", "params": "bar"}'; + + $output = '{"jsonrpc": "2.0", "id": null, "error": {"code": -32600, "message": "Invalid Request"}}'; + + $this->compare($input, $output); + } + + public function testImplementationError() + { + $input = '{"jsonrpc": "2.0", "id": 1, "method": "implementation error"}'; + + $output = '{"jsonrpc": "2.0", "id": 1, "error": {"code": -32099, "message": "Server error"}}'; + + $this->compare($input, $output); + } + + public function testImplementationErrorData() + { + $input = '{"jsonrpc": "2.0", "id": 1, "method": "implementation error", "params": ["details"]}'; + + $output = '{"jsonrpc": "2.0", "id": 1, "error": {"code": -32099, "message": "Server error", "data": "details"}}'; + + $this->compare($input, $output); + } + + public function testImplementationErrorInvalid() + { + $input = '{"jsonrpc": "2.0", "id": 1, "method": "invalid implementation error"}'; + + $output = '{"jsonrpc": "2.0", "id": 1, "error": {"code": -32099, "message": "Server error"}}'; + + $this->compare($input, $output); + } + + public function testApplicationError() + { + $input = '{"jsonrpc": "2.0", "id": 1, "method": "application error"}'; + + $output = '{"jsonrpc": "2.0", "id": 1, "error": {"code": 1, "message": "Application error"}}'; + + $this->compare($input, $output); + } + + public function testApplicationErrorData() + { + $input = '{"jsonrpc": "2.0", "id": 1, "method": "application error", "params": ["details"]}'; + + $output = '{"jsonrpc": "2.0", "id": 1, "error": {"code": 1, "message": "Application error", "data": "details"}}'; + + $this->compare($input, $output); + } + + public function testApplicationErrorInvalid() + { + $input = '{"jsonrpc": "2.0", "id": 1, "method": "invalid application error"}'; + + $output = '{"jsonrpc": "2.0", "id": 1, "error": {"code": 1, "message": ""}}'; + + $this->compare($input, $output); + } + + public function testInvalidId() + { + $input = '{"jsonrpc": "2.0", "method": "foobar", "params": [1, 2], "id": [1]}'; + + $output = '{"jsonrpc": "2.0", "id": null, "error": {"code": -32600, "message": "Invalid Request"}}'; + + $this->compare($input, $output); + } + + public function testBatchInvalidJson() + { + $input = ' [ + {"jsonrpc": "2.0", "method": "subtract", "params": [1, 2, 4], "id": "1"}, + {"jsonrpc": "2.0", "method" + ]'; + + $output = '{"jsonrpc": "2.0", "id": null, "error": {"code": -32700, "message": "Parse error"}}'; + + $this->compare($input, $output); + } + + public function testBatchEmpty() + { + $input = '[ + ]'; + + $output = '{"jsonrpc": "2.0", "id": null, "error": {"code": -32600, "message": "Invalid Request"}}'; + + $this->compare($input, $output); + } + + public function testBatchInvalidElement() + { + $input = '[ + 1 + ]'; + + $output = '[ + {"jsonrpc": "2.0", "id": null, "error": {"code": -32600, "message": "Invalid Request"}} + ]'; + + $this->compare($input, $output); + } + + public function testBatchInvalidElements() + { + $input = '[ + 1, + 2, + 3 + ]'; + + $output = '[ + {"jsonrpc": "2.0", "id": null, "error": {"code": -32600, "message": "Invalid Request"}}, + {"jsonrpc": "2.0", "id": null, "error": {"code": -32600, "message": "Invalid Request"}}, + {"jsonrpc": "2.0", "id": null, "error": {"code": -32600, "message": "Invalid Request"}} + ]'; + + $this->compare($input, $output); + } + + public function testBatch() + { + $input = '[ + {"jsonrpc": "2.0", "method": "subtract", "params": [1, -1], "id": "1"}, + {"jsonrpc": "2.0", "method": "subtract", "params": [1, -1]}, + {"foo": "boo"}, + {"jsonrpc": "2.0", "method": "undefined", "params": {"name": "myself"}, "id": "5"} + ]'; + + $output = '[ + {"jsonrpc": "2.0", "id": "1", "result": 2}, + {"jsonrpc": "2.0", "id": null, "error": {"code": -32600, "message": "Invalid Request"}}, + {"jsonrpc": "2.0", "id": "5", "error": {"code": -32601, "message": "Method not found"}} + ]'; + + $this->compare($input, $output); + } + + public function testBatchNotifications() + { + $input = '[ + {"jsonrpc": "2.0", "method": "subtract", "params": [4, 2]}, + {"jsonrpc": "2.0", "method": "subtract", "params": [3, 7]} + ]'; + + $output = 'null'; + + $this->compare($input, $output); + } + + private function compare($input, $expectedJsonOutput) + { + $server = new Server(new Api()); + $actualJsonOutput = $server->reply($input); + + $expectedOutput = json_decode($expectedJsonOutput, true); + $actualOutput = json_decode($actualJsonOutput, true); + + $this->assertSame($expectedOutput, $actualOutput); + } +} diff --git a/vendor/ezyang/htmlpurifier/composer.json b/vendor/ezyang/htmlpurifier/composer.json new file mode 100644 index 000000000..0ff86b5df --- /dev/null +++ b/vendor/ezyang/htmlpurifier/composer.json @@ -0,0 +1,28 @@ +{ + "name": "ezyang/htmlpurifier", + "description": "Standards compliant HTML filter written in PHP", + "type": "library", + "keywords": ["html"], + "homepage": "http://htmlpurifier.org/", + "license": "LGPL-2.1-or-later", + "authors": [ + { + "name": "Edward Z. Yang", + "email": "admin@htmlpurifier.org", + "homepage": "http://ezyang.com" + } + ], + "require": { + "php": ">=5.2" + }, + "require-dev": { + "simpletest/simpletest": "dev-master#72de02a7b80c6bb8864ef9bf66d41d2f58f826bd" + }, + "autoload": { + "psr-0": { "HTMLPurifier": "library/" }, + "files": ["library/HTMLPurifier.composer.php"], + "exclude-from-classmap": [ + "/library/HTMLPurifier/Language/" + ] + } +} diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/DefinitionCache/Serializer/README b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/DefinitionCache/Serializer/README old mode 100644 new mode 100755 diff --git a/vendor/fiskaly/fiskaly-sdk-php/.gitignore b/vendor/fiskaly/fiskaly-sdk-php/.gitignore new file mode 100644 index 000000000..774d7733d --- /dev/null +++ b/vendor/fiskaly/fiskaly-sdk-php/.gitignore @@ -0,0 +1,7 @@ +vendor/ +.idea/ +composer.lock +com.fiskaly.service* +env.php +.php_cs.cache +*.log diff --git a/vendor/fiskaly/fiskaly-sdk-php/.php_cs b/vendor/fiskaly/fiskaly-sdk-php/.php_cs new file mode 100644 index 000000000..18226d07c --- /dev/null +++ b/vendor/fiskaly/fiskaly-sdk-php/.php_cs @@ -0,0 +1,14 @@ +notPath('vendor') + ->in(__DIR__); + +return PhpCsFixer\Config::create() + ->setRules([ + '@PSR2' => true, + 'array_syntax' => ['syntax' => 'short'], + 'ordered_imports' => ['sortAlgorithm' => 'alpha'], + 'no_unused_imports' => true, + ]) + ->setFinder($finder); diff --git a/vendor/fiskaly/fiskaly-sdk-php/composer.json b/vendor/fiskaly/fiskaly-sdk-php/composer.json new file mode 100644 index 000000000..10bcea0a1 --- /dev/null +++ b/vendor/fiskaly/fiskaly-sdk-php/composer.json @@ -0,0 +1,28 @@ +{ + "name": "fiskaly/fiskaly-sdk-php", + "description": "fiskaly Cloud-TSE SDK for PHP", + "keywords": ["fiskaly", "php", "src"], + "type": "library", + "homepage": "https://github.com/fiskaly/fiskaly-sdk-php", + "license": "MIT", + "version": "1.2.100", + "require": { + "php": ">=7.1", + "datto/json-rpc-http": "*", + "ext-json": "*" + }, + "autoload": { + "psr-4": { + "FiskalyClient\\": "src" + } + }, + "require-dev": { + "phpunit/phpunit": "^9.1", + "friendsofphp/php-cs-fixer": "^2.16" + }, + "scripts": { + "format": [ + "vendor/bin/php-cs-fixer fix" + ] + } +} diff --git a/vendor/fiskaly/fiskaly-sdk-php/examples/composer.json b/vendor/fiskaly/fiskaly-sdk-php/examples/composer.json new file mode 100644 index 000000000..a34e816b2 --- /dev/null +++ b/vendor/fiskaly/fiskaly-sdk-php/examples/composer.json @@ -0,0 +1,12 @@ +{ + "name": "fiskaly-sdk-php-example", + "description": "fiskaly Cloud-TSE SDK for PHP", + "keywords": ["fiskaly", "php", "src", "example"], + "type": "project", + "license": "MIT", + "version": "1.0.0", + "require": { + "php": ">=7.1", + "fiskaly/fiskaly-sdk-php": "*" + } +} diff --git a/vendor/fiskaly/fiskaly-sdk-php/tests/ErrorTest.php b/vendor/fiskaly/fiskaly-sdk-php/tests/ErrorTest.php new file mode 100644 index 000000000..493d65eab --- /dev/null +++ b/vendor/fiskaly/fiskaly-sdk-php/tests/ErrorTest.php @@ -0,0 +1,40 @@ +createClient(); + $this->expectException(FiskalyHttpException::class); + + $response = $client->request( + 'PUT', + '/tss/ecb75169' + ); + + $this->assertNotNull($response); + $this->assertNotNull($response->getContext()); + $this->assertNotNull($response->getResponse()); + } +} diff --git a/vendor/fiskaly/fiskaly-sdk-php/tests/FiskalyClientParametersTest.php b/vendor/fiskaly/fiskaly-sdk-php/tests/FiskalyClientParametersTest.php new file mode 100644 index 000000000..13c5ad81c --- /dev/null +++ b/vendor/fiskaly/fiskaly-sdk-php/tests/FiskalyClientParametersTest.php @@ -0,0 +1,83 @@ +assertEquals('fiskaly_service must be provided', $e->getMessage()); + } + } + + /** + * @test + */ + public function testClientInitApiKeyParameter() + { + try { + return FiskalyClient::createUsingCredentials($_ENV["FISKALY_SERVICE_URL"], null, null, null); + } catch (Exception $e) { + $this->assertEquals('api_key must be provided', $e->getMessage()); + } + } + + /** + * @test + */ + public function testClientInitApiSecretParameter() + { + try { + return FiskalyClient::createUsingCredentials($_ENV["FISKALY_SERVICE_URL"], $_ENV["FISKALY_API_KEY"], null, null); + } catch (Exception $e) { + $this->assertEquals('api_secret must be provided', $e->getMessage()); + } + } + + /** + * @test + */ + public function testClientInitBaseUrlParameter() + { + try { + return FiskalyClient::createUsingCredentials($_ENV["FISKALY_SERVICE_URL"], $_ENV["FISKALY_API_KEY"], $_ENV["FISKALY_API_SECRET"], null); + } catch (Exception $e) { + $this->assertEquals('base_url must be provided', $e->getMessage()); + } + } + + /** + * @test + */ + public function testClientServiceParameterInitUsingContext() + { + try { + return FiskalyClient::createUsingContext(null, null); + } catch (Exception $e) { + $this->assertEquals('fiskaly_service must be provided', $e->getMessage()); + } + } + + /** + * @test + */ + public function testClientContextParameterInitUsingContext() + { + try { + return FiskalyClient::createUsingContext($_ENV["FISKALY_SERVICE_URL"], null); + } catch (Exception $e) { + $this->assertEquals('context must be provided', $e->getMessage()); + } + } +} diff --git a/vendor/fiskaly/fiskaly-sdk-php/tests/FiskalyClientTest.php b/vendor/fiskaly/fiskaly-sdk-php/tests/FiskalyClientTest.php new file mode 100644 index 000000000..a86ca650a --- /dev/null +++ b/vendor/fiskaly/fiskaly-sdk-php/tests/FiskalyClientTest.php @@ -0,0 +1,198 @@ +createClient(); + $this->assertNotNull($client); + $this->assertTrue($client instanceof FiskalyClient); + } + + /** + * @test + */ + public function testClientUsingContext() + { + $client = $this->createClientUsingContext(); + $this->assertNotNull($client); + $this->assertTrue($client instanceof FiskalyClient); + } + + /** + * @test + */ + public function testContext() + { + $client = $this->createClient(); + $this->assertNotEquals('', $client->getContext()); + } + + /** + * @test + */ + public function testVersion() + { + try { + $client = $this->createClient(); + $version = $client->getVersion(); + + $this->assertNotNull($version); + $this->assertTrue($version instanceof VersionResponse); + $this->assertNotNull($version->getClientVersion()); + $this->assertNotNull($version->getSmaersVersion()); + $this->assertNotNull($version->getClientCommitHash()); + $this->assertNotNull($version->getClientSourceHash()); + } catch (Exception $e) { + $this->assertTrue(false); + } + } + + /** + * @test + */ + public function testSelfTest() + { + try { + $client = $this->createClient(); + $selftest = $client->selfTest(); + + $this->assertNotNull($selftest); + $this->assertTrue($selftest instanceof SelfTestResponse); + $this->assertNotNull($selftest->getProxy()); + $this->assertNotNull($selftest->getBackend()); + $this->assertNotNull($selftest->getSmaers()); + } catch (Exception $e) { + $this->assertTrue(false); + } + } + + /** + * @test + */ + public function testGetConfig() + { + try { + $client = $this->createClient(); + $config = $client->getConfig(); + + $this->assertNotNull($config); + $this->assertTrue($config instanceof ClientConfiguration); + $this->assertNotNull($config->getClientTimeout()); + $this->assertNotNull($config->getDebugFile()); + $this->assertNotNull($config->getDebugLevel()); + $this->assertNotNull($config->getSmearsTimeout()); + } catch (Exception $e) { + $this->assertTrue(false); + } + } + + /** + * @test + */ + public function testConfigure() + { + try { + $client = $this->createClient(); + + try { + $config_params = [ + 'debug_level' => 4, + 'debug_file' => __DIR__ . '/../fiskaly.log', + 'client_timeout' => 5000, + 'smaers_timeout' => 2000, + 'http_proxy' => "" + ]; + $config = $client->configure($config_params); + } catch (Exception $e) { + exit($e); + } + + $this->assertNotNull($config); + $this->assertTrue($config instanceof ClientConfiguration); + $this->assertNotNull($config->getClientTimeout()); + $this->assertNotNull($config->getDebugFile()); + $this->assertNotNull($config->getDebugLevel()); + $this->assertNotNull($config->getSmearsTimeout()); + $this->assertNotNull($config->getHttpProxy()); + + $this->assertEquals($config_params['debug_level'], $config->getDebugLevel()); + $this->assertEquals($config_params['debug_file'], $config->getDebugFile()); + $this->assertEquals($config_params['client_timeout'], $config->getClientTimeout()); + $this->assertEquals($config_params['smaers_timeout'], $config->getSmearsTimeout()); + $this->assertEquals($config_params['http_proxy'], $config->getHttpProxy()); + } catch (Exception $e) { + $this->assertTrue(false); + } + } + + /** + * @test + */ + public function testRequest() + { + try { + $client = $this->createClient(); + $response = $client->request( + 'PUT', + '/tss/ecb75169-680f-48d1-93b2-52cc10abb9f/tx/9cbe6566-e24c-42ac-97fe-6a0112fb3c6', + ["last_revision" => "0"], + ["Content-Type" => "application/json"], + 'eyJzdGF0ZSI6ICJBQ1RJVkUiLCJjbGllbnRfaWQiOiAiYTYyNzgwYjAtMTFiYi00MThhLTk3MzYtZjQ3Y2E5NzVlNTE1In0=' + ); + + $context = $client->getContext(); + + $this->assertNotNull($response); + $this->assertTrue($response instanceof RequestResponse); + $this->assertNotNull($response->getContext()); + $this->assertNotNull($response->getResponse()); + + // Check if context updated + $this->assertNotEquals($context, $response->getContext()); + } catch (Exception $e) { + // echo "Exception: " . $e->getMessage() . "\n"; + $this->assertTrue($e instanceof FiskalyException); + // $this->assertTrue(false); + } + } +} diff --git a/vendor/fiskaly/fiskaly-sdk-php/tests/JsonRPCTest.php b/vendor/fiskaly/fiskaly-sdk-php/tests/JsonRPCTest.php new file mode 100644 index 000000000..aabb12497 --- /dev/null +++ b/vendor/fiskaly/fiskaly-sdk-php/tests/JsonRPCTest.php @@ -0,0 +1,59 @@ +json_rpc = new Client($_ENV['FISKALY_SERVICE_URL']); + } + + public function testInit() + { + $this->assertNotNull($this->json_rpc); + } + + public function testInitWithoutParams() + { + $this->json_rpc = new Client(null); + + $this->assertNotNull($this->json_rpc); + $this->assertTrue($this->json_rpc instanceof Client); + $this->assertNotNull($this->json_rpc); + $this->assertEquals('close', $this->json_rpc->getHeaders()['Connection']); + } + + public function testWrongMethodQuery() + { + $this->json_rpc->query('wrong-method-name', null, $response)->send(); + + $this->assertNotNull($response); + $this->assertTrue($response instanceof ErrorResponse); + $this->assertEquals(-32601, $response->getCode()); + $this->assertEquals('Method not found', $response->getMessage()); + } + + public function testWrongDataQuery() + { + $this->json_rpc->query('create-context', null, $response)->send(); + + $this->assertNotNull($response); + $this->assertTrue($response instanceof ErrorResponse); + $this->assertEquals(-32603, $response->getCode()); + $this->assertEquals('Internal error', $response->getMessage()); + } + + public function testUndefinedResponseQuery() + { + $this->expectErrorMessage('Cannot pass parameter 3 by reference'); + $this->json_rpc->query('create-context', null, null)->send(); + } +} diff --git a/vendor/fiskaly/fiskaly-sdk-php/tests/readme.md b/vendor/fiskaly/fiskaly-sdk-php/tests/readme.md new file mode 100644 index 000000000..7b0fea5ad --- /dev/null +++ b/vendor/fiskaly/fiskaly-sdk-php/tests/readme.md @@ -0,0 +1,6 @@ +# How to run the tests? + +1. Go to [https://developer.fiskaly.com/downloads#service](https://developer.fiskaly.com/downloads#service) +2. Download the appropriate service build for your platform +3. Start the service +4. Run the tests \ No newline at end of file diff --git a/vendor/laminas/laminas-loader/composer.json b/vendor/laminas/laminas-loader/composer.json index 4e69ed12c..6cd38fb20 100644 --- a/vendor/laminas/laminas-loader/composer.json +++ b/vendor/laminas/laminas-loader/composer.json @@ -23,7 +23,7 @@ }, "abandoned": true, "require": { - "php": "~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0" + "php": "^8.0.0" }, "require-dev": { "laminas/laminas-coding-standard": "~2.4.0", diff --git a/vendor/laminas/laminas-loader/composer.lock b/vendor/laminas/laminas-loader/composer.lock index 9ff91be61..e3725edd4 100644 --- a/vendor/laminas/laminas-loader/composer.lock +++ b/vendor/laminas/laminas-loader/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "b2aa769d634ef91ad48c86aa033edd20", + "content-hash": "397df6711f260409037a70f2163edaff", "packages": [], "packages-dev": [ { @@ -2101,12 +2101,12 @@ ], "aliases": [], "minimum-stability": "stable", - "stability-flags": [], + "stability-flags": {}, "prefer-stable": false, "prefer-lowest": false, "platform": { - "php": "~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0" + "php": "^8.0.0" }, - "platform-dev": [], - "plugin-api-version": "2.6.0" + "platform-dev": {}, + "plugin-api-version": "2.9.0" } diff --git a/vendor/laminas/laminas-servicemanager/composer.json b/vendor/laminas/laminas-servicemanager/composer.json index 82718a394..f797a3003 100644 --- a/vendor/laminas/laminas-servicemanager/composer.json +++ b/vendor/laminas/laminas-servicemanager/composer.json @@ -28,12 +28,12 @@ "require-dev": { "composer/package-versions-deprecated": "^1.11.99.5", "friendsofphp/proxy-manager-lts": "^1.0.18", - "laminas/laminas-code": "^4.14.0", + "laminas/laminas-code": "^4.16.0", "laminas/laminas-coding-standard": "~2.5.0", "laminas/laminas-container-config-test": "^0.8", "mikey179/vfsstream": "^1.6.12", - "phpbench/phpbench": "^1.3.1", - "phpunit/phpunit": "^10.5.36", + "phpbench/phpbench": "^1.4.1", + "phpunit/phpunit": "^10.5.51", "psalm/plugin-phpunit": "^0.18.4", "vimeo/psalm": "^5.26.1" }, diff --git a/vendor/laminas/laminas-servicemanager/composer.lock b/vendor/laminas/laminas-servicemanager/composer.lock index f0663fbaa..c455e88d6 100644 --- a/vendor/laminas/laminas-servicemanager/composer.lock +++ b/vendor/laminas/laminas-servicemanager/composer.lock @@ -4,34 +4,34 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "1d889aba00805cbc9a32e834f5be6282", + "content-hash": "b52b4517d0655e13ac5be1ce85f56d19", "packages": [ { "name": "laminas/laminas-stdlib", - "version": "3.19.0", + "version": "3.20.0", "source": { "type": "git", "url": "https://github.com/laminas/laminas-stdlib.git", - "reference": "6a192dd0882b514e45506f533b833b623b78fff3" + "reference": "8974a1213be42c3e2f70b2c27b17f910291ab2f4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laminas/laminas-stdlib/zipball/6a192dd0882b514e45506f533b833b623b78fff3", - "reference": "6a192dd0882b514e45506f533b833b623b78fff3", + "url": "https://api.github.com/repos/laminas/laminas-stdlib/zipball/8974a1213be42c3e2f70b2c27b17f910291ab2f4", + "reference": "8974a1213be42c3e2f70b2c27b17f910291ab2f4", "shasum": "" }, "require": { - "php": "~8.1.0 || ~8.2.0 || ~8.3.0" + "php": "~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0" }, "conflict": { "zendframework/zend-stdlib": "*" }, "require-dev": { - "laminas/laminas-coding-standard": "^2.5", - "phpbench/phpbench": "^1.2.15", - "phpunit/phpunit": "^10.5.8", - "psalm/plugin-phpunit": "^0.18.4", - "vimeo/psalm": "^5.20.0" + "laminas/laminas-coding-standard": "^3.0", + "phpbench/phpbench": "^1.3.1", + "phpunit/phpunit": "^10.5.38", + "psalm/plugin-phpunit": "^0.19.0", + "vimeo/psalm": "^5.26.1" }, "type": "library", "autoload": { @@ -63,7 +63,7 @@ "type": "community_bridge" } ], - "time": "2024-01-19T12:39:49+00:00" + "time": "2024-10-29T13:46:07+00:00" }, { "name": "psr/container", @@ -350,16 +350,16 @@ }, { "name": "composer/pcre", - "version": "3.3.1", + "version": "3.3.2", "source": { "type": "git", "url": "https://github.com/composer/pcre.git", - "reference": "63aaeac21d7e775ff9bc9d45021e1745c97521c4" + "reference": "b2bed4734f0cc156ee1fe9c0da2550420d99a21e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/pcre/zipball/63aaeac21d7e775ff9bc9d45021e1745c97521c4", - "reference": "63aaeac21d7e775ff9bc9d45021e1745c97521c4", + "url": "https://api.github.com/repos/composer/pcre/zipball/b2bed4734f0cc156ee1fe9c0da2550420d99a21e", + "reference": "b2bed4734f0cc156ee1fe9c0da2550420d99a21e", "shasum": "" }, "require": { @@ -369,19 +369,19 @@ "phpstan/phpstan": "<1.11.10" }, "require-dev": { - "phpstan/phpstan": "^1.11.10", - "phpstan/phpstan-strict-rules": "^1.1", + "phpstan/phpstan": "^1.12 || ^2", + "phpstan/phpstan-strict-rules": "^1 || ^2", "phpunit/phpunit": "^8 || ^9" }, "type": "library", "extra": { - "branch-alias": { - "dev-main": "3.x-dev" - }, "phpstan": { "includes": [ "extension.neon" ] + }, + "branch-alias": { + "dev-main": "3.x-dev" } }, "autoload": { @@ -409,7 +409,7 @@ ], "support": { "issues": "https://github.com/composer/pcre/issues", - "source": "https://github.com/composer/pcre/tree/3.3.1" + "source": "https://github.com/composer/pcre/tree/3.3.2" }, "funding": [ { @@ -425,7 +425,7 @@ "type": "tidelift" } ], - "time": "2024-08-27T18:44:43+00:00" + "time": "2024-11-12T16:29:46+00:00" }, { "name": "composer/semver", @@ -1034,8 +1034,8 @@ "type": "library", "extra": { "thanks": { - "name": "ocramius/proxy-manager", - "url": "https://github.com/Ocramius/ProxyManager" + "url": "https://github.com/Ocramius/ProxyManager", + "name": "ocramius/proxy-manager" } }, "autoload": { @@ -1085,27 +1085,27 @@ }, { "name": "laminas/laminas-code", - "version": "4.14.0", + "version": "4.16.0", "source": { "type": "git", "url": "https://github.com/laminas/laminas-code.git", - "reference": "562e02b7d85cb9142b5116cc76c4c7c162a11a1c" + "reference": "1793e78dad4108b594084d05d1fb818b85b110af" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laminas/laminas-code/zipball/562e02b7d85cb9142b5116cc76c4c7c162a11a1c", - "reference": "562e02b7d85cb9142b5116cc76c4c7c162a11a1c", + "url": "https://api.github.com/repos/laminas/laminas-code/zipball/1793e78dad4108b594084d05d1fb818b85b110af", + "reference": "1793e78dad4108b594084d05d1fb818b85b110af", "shasum": "" }, "require": { - "php": "~8.1.0 || ~8.2.0 || ~8.3.0" + "php": "~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0" }, "require-dev": { "doctrine/annotations": "^2.0.1", "ext-phar": "*", - "laminas/laminas-coding-standard": "^2.5.0", - "laminas/laminas-stdlib": "^3.17.0", - "phpunit/phpunit": "^10.3.3", + "laminas/laminas-coding-standard": "^3.0.0", + "laminas/laminas-stdlib": "^3.18.0", + "phpunit/phpunit": "^10.5.37", "psalm/plugin-phpunit": "^0.19.0", "vimeo/psalm": "^5.15.0" }, @@ -1144,7 +1144,7 @@ "type": "community_bridge" } ], - "time": "2024-06-17T08:50:25+00:00" + "time": "2024-11-20T13:15:13+00:00" }, { "name": "laminas/laminas-coding-standard", @@ -1323,16 +1323,16 @@ }, { "name": "myclabs/deep-copy", - "version": "1.12.0", + "version": "1.13.4", "source": { "type": "git", "url": "https://github.com/myclabs/DeepCopy.git", - "reference": "3a6b9a42cd8f8771bd4295d13e1423fa7f3d942c" + "reference": "07d290f0c47959fd5eed98c95ee5602db07e0b6a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/3a6b9a42cd8f8771bd4295d13e1423fa7f3d942c", - "reference": "3a6b9a42cd8f8771bd4295d13e1423fa7f3d942c", + "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/07d290f0c47959fd5eed98c95ee5602db07e0b6a", + "reference": "07d290f0c47959fd5eed98c95ee5602db07e0b6a", "shasum": "" }, "require": { @@ -1371,7 +1371,7 @@ ], "support": { "issues": "https://github.com/myclabs/DeepCopy/issues", - "source": "https://github.com/myclabs/DeepCopy/tree/1.12.0" + "source": "https://github.com/myclabs/DeepCopy/tree/1.13.4" }, "funding": [ { @@ -1379,7 +1379,7 @@ "type": "tidelift" } ], - "time": "2024-06-12T14:39:25+00:00" + "time": "2025-08-01T08:46:24+00:00" }, { "name": "netresearch/jsonmapper", @@ -1657,70 +1657,18 @@ }, "time": "2023-10-30T13:38:26+00:00" }, - { - "name": "phpbench/dom", - "version": "0.3.3", - "source": { - "type": "git", - "url": "https://github.com/phpbench/dom.git", - "reference": "786a96db538d0def931f5b19225233ec42ec7a72" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpbench/dom/zipball/786a96db538d0def931f5b19225233ec42ec7a72", - "reference": "786a96db538d0def931f5b19225233ec42ec7a72", - "shasum": "" - }, - "require": { - "ext-dom": "*", - "php": "^7.3||^8.0" - }, - "require-dev": { - "friendsofphp/php-cs-fixer": "^3.14", - "phpstan/phpstan": "^1.10", - "phpunit/phpunit": "^8.0||^9.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0-dev" - } - }, - "autoload": { - "psr-4": { - "PhpBench\\Dom\\": "lib/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Daniel Leech", - "email": "daniel@dantleech.com" - } - ], - "description": "DOM wrapper to simplify working with the PHP DOM implementation", - "support": { - "issues": "https://github.com/phpbench/dom/issues", - "source": "https://github.com/phpbench/dom/tree/0.3.3" - }, - "abandoned": true, - "time": "2023-03-06T23:46:57+00:00" - }, { "name": "phpbench/phpbench", - "version": "1.3.1", + "version": "1.4.1", "source": { "type": "git", "url": "https://github.com/phpbench/phpbench.git", - "reference": "a3e1ef08d9d7736d43a7fbd444893d6a073c0ca0" + "reference": "78cd98a9aa34e0f8f80ca01972a8b88d2c30194b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpbench/phpbench/zipball/a3e1ef08d9d7736d43a7fbd444893d6a073c0ca0", - "reference": "a3e1ef08d9d7736d43a7fbd444893d6a073c0ca0", + "url": "https://api.github.com/repos/phpbench/phpbench/zipball/78cd98a9aa34e0f8f80ca01972a8b88d2c30194b", + "reference": "78cd98a9aa34e0f8f80ca01972a8b88d2c30194b", "shasum": "" }, "require": { @@ -1733,7 +1681,6 @@ "ext-tokenizer": "*", "php": "^8.1", "phpbench/container": "^2.2", - "phpbench/dom": "~0.3.3", "psr/log": "^1.1 || ^2.0 || ^3.0", "seld/jsonlint": "^1.1", "symfony/console": "^6.1 || ^7.0", @@ -1752,8 +1699,8 @@ "phpstan/extension-installer": "^1.1", "phpstan/phpstan": "^1.0", "phpstan/phpstan-phpunit": "^1.0", - "phpunit/phpunit": "^10.4", - "rector/rector": "^0.18.11 || ^1.0.0", + "phpunit/phpunit": "^10.4 || ^11.0", + "rector/rector": "^1.2", "symfony/error-handler": "^6.1 || ^7.0", "symfony/var-dumper": "^6.1 || ^7.0" }, @@ -1798,7 +1745,7 @@ ], "support": { "issues": "https://github.com/phpbench/phpbench/issues", - "source": "https://github.com/phpbench/phpbench/tree/1.3.1" + "source": "https://github.com/phpbench/phpbench/tree/1.4.1" }, "funding": [ { @@ -1806,7 +1753,7 @@ "type": "github" } ], - "time": "2024-06-30T11:04:37+00:00" + "time": "2025-03-12T08:01:40+00:00" }, { "name": "phpdocumentor/reflection-common", @@ -2340,16 +2287,16 @@ }, { "name": "phpunit/phpunit", - "version": "10.5.36", + "version": "10.5.51", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "aa0a8ce701ea7ee314b0dfaa8970dc94f3f8c870" + "reference": "ace160e31aaa317a99c411410c40c502b4be42a4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/aa0a8ce701ea7ee314b0dfaa8970dc94f3f8c870", - "reference": "aa0a8ce701ea7ee314b0dfaa8970dc94f3f8c870", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/ace160e31aaa317a99c411410c40c502b4be42a4", + "reference": "ace160e31aaa317a99c411410c40c502b4be42a4", "shasum": "" }, "require": { @@ -2359,7 +2306,7 @@ "ext-mbstring": "*", "ext-xml": "*", "ext-xmlwriter": "*", - "myclabs/deep-copy": "^1.12.0", + "myclabs/deep-copy": "^1.13.4", "phar-io/manifest": "^2.0.4", "phar-io/version": "^3.2.1", "php": ">=8.1", @@ -2370,13 +2317,13 @@ "phpunit/php-timer": "^6.0.0", "sebastian/cli-parser": "^2.0.1", "sebastian/code-unit": "^2.0.0", - "sebastian/comparator": "^5.0.2", + "sebastian/comparator": "^5.0.3", "sebastian/diff": "^5.1.1", "sebastian/environment": "^6.1.0", "sebastian/exporter": "^5.1.2", "sebastian/global-state": "^6.0.2", "sebastian/object-enumerator": "^5.0.0", - "sebastian/recursion-context": "^5.0.0", + "sebastian/recursion-context": "^5.0.1", "sebastian/type": "^4.0.0", "sebastian/version": "^4.0.1" }, @@ -2421,7 +2368,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", "security": "https://github.com/sebastianbergmann/phpunit/security/policy", - "source": "https://github.com/sebastianbergmann/phpunit/tree/10.5.36" + "source": "https://github.com/sebastianbergmann/phpunit/tree/10.5.51" }, "funding": [ { @@ -2432,12 +2379,20 @@ "url": "https://github.com/sebastianbergmann", "type": "github" }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, { "url": "https://tidelift.com/funding/github/packagist/phpunit/phpunit", "type": "tidelift" } ], - "time": "2024-10-08T15:36:51+00:00" + "time": "2025-08-12T07:31:25+00:00" }, { "name": "psalm/plugin-phpunit", @@ -2768,16 +2723,16 @@ }, { "name": "sebastian/comparator", - "version": "5.0.2", + "version": "5.0.3", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/comparator.git", - "reference": "2d3e04c3b4c1e84a5e7382221ad8883c8fbc4f53" + "reference": "a18251eb0b7a2dcd2f7aa3d6078b18545ef0558e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/2d3e04c3b4c1e84a5e7382221ad8883c8fbc4f53", - "reference": "2d3e04c3b4c1e84a5e7382221ad8883c8fbc4f53", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/a18251eb0b7a2dcd2f7aa3d6078b18545ef0558e", + "reference": "a18251eb0b7a2dcd2f7aa3d6078b18545ef0558e", "shasum": "" }, "require": { @@ -2788,7 +2743,7 @@ "sebastian/exporter": "^5.0" }, "require-dev": { - "phpunit/phpunit": "^10.4" + "phpunit/phpunit": "^10.5" }, "type": "library", "extra": { @@ -2833,7 +2788,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/comparator/issues", "security": "https://github.com/sebastianbergmann/comparator/security/policy", - "source": "https://github.com/sebastianbergmann/comparator/tree/5.0.2" + "source": "https://github.com/sebastianbergmann/comparator/tree/5.0.3" }, "funding": [ { @@ -2841,7 +2796,7 @@ "type": "github" } ], - "time": "2024-08-12T06:03:08+00:00" + "time": "2024-10-18T14:56:07+00:00" }, { "name": "sebastian/complexity", @@ -3344,23 +3299,23 @@ }, { "name": "sebastian/recursion-context", - "version": "5.0.0", + "version": "5.0.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/recursion-context.git", - "reference": "05909fb5bc7df4c52992396d0116aed689f93712" + "reference": "47e34210757a2f37a97dcd207d032e1b01e64c7a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/05909fb5bc7df4c52992396d0116aed689f93712", - "reference": "05909fb5bc7df4c52992396d0116aed689f93712", + "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/47e34210757a2f37a97dcd207d032e1b01e64c7a", + "reference": "47e34210757a2f37a97dcd207d032e1b01e64c7a", "shasum": "" }, "require": { "php": ">=8.1" }, "require-dev": { - "phpunit/phpunit": "^10.0" + "phpunit/phpunit": "^10.5" }, "type": "library", "extra": { @@ -3395,15 +3350,28 @@ "homepage": "https://github.com/sebastianbergmann/recursion-context", "support": { "issues": "https://github.com/sebastianbergmann/recursion-context/issues", - "source": "https://github.com/sebastianbergmann/recursion-context/tree/5.0.0" + "security": "https://github.com/sebastianbergmann/recursion-context/security/policy", + "source": "https://github.com/sebastianbergmann/recursion-context/tree/5.0.1" }, "funding": [ { "url": "https://github.com/sebastianbergmann", "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/sebastian/recursion-context", + "type": "tidelift" } ], - "time": "2023-02-03T07:05:40+00:00" + "time": "2025-08-10T07:50:56+00:00" }, { "name": "sebastian/type", @@ -3641,16 +3609,16 @@ }, { "name": "spatie/array-to-xml", - "version": "3.3.0", + "version": "3.4.0", "source": { "type": "git", "url": "https://github.com/spatie/array-to-xml.git", - "reference": "f56b220fe2db1ade4c88098d83413ebdfc3bf876" + "reference": "7dcfc67d60b0272926dabad1ec01f6b8a5fb5e67" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/spatie/array-to-xml/zipball/f56b220fe2db1ade4c88098d83413ebdfc3bf876", - "reference": "f56b220fe2db1ade4c88098d83413ebdfc3bf876", + "url": "https://api.github.com/repos/spatie/array-to-xml/zipball/7dcfc67d60b0272926dabad1ec01f6b8a5fb5e67", + "reference": "7dcfc67d60b0272926dabad1ec01f6b8a5fb5e67", "shasum": "" }, "require": { @@ -3693,7 +3661,7 @@ "xml" ], "support": { - "source": "https://github.com/spatie/array-to-xml/tree/3.3.0" + "source": "https://github.com/spatie/array-to-xml/tree/3.4.0" }, "funding": [ { @@ -3705,20 +3673,20 @@ "type": "github" } ], - "time": "2024-05-01T10:20:27+00:00" + "time": "2024-12-16T12:45:15+00:00" }, { "name": "squizlabs/php_codesniffer", - "version": "3.10.3", + "version": "3.13.2", "source": { "type": "git", "url": "https://github.com/PHPCSStandards/PHP_CodeSniffer.git", - "reference": "62d32998e820bddc40f99f8251958aed187a5c9c" + "reference": "5b5e3821314f947dd040c70f7992a64eac89025c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/PHPCSStandards/PHP_CodeSniffer/zipball/62d32998e820bddc40f99f8251958aed187a5c9c", - "reference": "62d32998e820bddc40f99f8251958aed187a5c9c", + "url": "https://api.github.com/repos/PHPCSStandards/PHP_CodeSniffer/zipball/5b5e3821314f947dd040c70f7992a64eac89025c", + "reference": "5b5e3821314f947dd040c70f7992a64eac89025c", "shasum": "" }, "require": { @@ -3783,22 +3751,26 @@ { "url": "https://opencollective.com/php_codesniffer", "type": "open_collective" + }, + { + "url": "https://thanks.dev/u/gh/phpcsstandards", + "type": "thanks_dev" } ], - "time": "2024-09-18T10:38:58+00:00" + "time": "2025-06-17T22:17:01+00:00" }, { "name": "symfony/console", - "version": "v6.4.12", + "version": "v6.4.24", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "72d080eb9edf80e36c19be61f72c98ed8273b765" + "reference": "59266a5bf6a596e3e0844fd95e6ad7ea3c1d3350" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/72d080eb9edf80e36c19be61f72c98ed8273b765", - "reference": "72d080eb9edf80e36c19be61f72c98ed8273b765", + "url": "https://api.github.com/repos/symfony/console/zipball/59266a5bf6a596e3e0844fd95e6ad7ea3c1d3350", + "reference": "59266a5bf6a596e3e0844fd95e6ad7ea3c1d3350", "shasum": "" }, "require": { @@ -3863,7 +3835,7 @@ "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v6.4.12" + "source": "https://github.com/symfony/console/tree/v6.4.24" }, "funding": [ { @@ -3874,25 +3846,29 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2024-09-20T08:15:52+00:00" + "time": "2025-07-30T10:38:54+00:00" }, { "name": "symfony/deprecation-contracts", - "version": "v3.5.0", + "version": "v3.6.0", "source": { "type": "git", "url": "https://github.com/symfony/deprecation-contracts.git", - "reference": "0e0d29ce1f20deffb4ab1b016a7257c4f1e789a1" + "reference": "63afe740e99a13ba87ec199bb07bbdee937a5b62" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/0e0d29ce1f20deffb4ab1b016a7257c4f1e789a1", - "reference": "0e0d29ce1f20deffb4ab1b016a7257c4f1e789a1", + "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/63afe740e99a13ba87ec199bb07bbdee937a5b62", + "reference": "63afe740e99a13ba87ec199bb07bbdee937a5b62", "shasum": "" }, "require": { @@ -3900,12 +3876,12 @@ }, "type": "library", "extra": { - "branch-alias": { - "dev-main": "3.5-dev" - }, "thanks": { - "name": "symfony/contracts", - "url": "https://github.com/symfony/contracts" + "url": "https://github.com/symfony/contracts", + "name": "symfony/contracts" + }, + "branch-alias": { + "dev-main": "3.6-dev" } }, "autoload": { @@ -3930,7 +3906,7 @@ "description": "A generic function and convention to trigger deprecation notices", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/deprecation-contracts/tree/v3.5.0" + "source": "https://github.com/symfony/deprecation-contracts/tree/v3.6.0" }, "funding": [ { @@ -3946,20 +3922,20 @@ "type": "tidelift" } ], - "time": "2024-04-18T09:32:20+00:00" + "time": "2024-09-25T14:21:43+00:00" }, { "name": "symfony/filesystem", - "version": "v6.4.12", + "version": "v6.4.24", "source": { "type": "git", "url": "https://github.com/symfony/filesystem.git", - "reference": "f810e3cbdf7fdc35983968523d09f349fa9ada12" + "reference": "75ae2edb7cdcc0c53766c30b0a2512b8df574bd8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/f810e3cbdf7fdc35983968523d09f349fa9ada12", - "reference": "f810e3cbdf7fdc35983968523d09f349fa9ada12", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/75ae2edb7cdcc0c53766c30b0a2512b8df574bd8", + "reference": "75ae2edb7cdcc0c53766c30b0a2512b8df574bd8", "shasum": "" }, "require": { @@ -3996,7 +3972,7 @@ "description": "Provides basic utilities for the filesystem", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/filesystem/tree/v6.4.12" + "source": "https://github.com/symfony/filesystem/tree/v6.4.24" }, "funding": [ { @@ -4007,25 +3983,29 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2024-09-16T16:01:33+00:00" + "time": "2025-07-10T08:14:14+00:00" }, { "name": "symfony/finder", - "version": "v6.4.11", + "version": "v6.4.24", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "d7eb6daf8cd7e9ac4976e9576b32042ef7253453" + "reference": "73089124388c8510efb8d2d1689285d285937b08" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/d7eb6daf8cd7e9ac4976e9576b32042ef7253453", - "reference": "d7eb6daf8cd7e9ac4976e9576b32042ef7253453", + "url": "https://api.github.com/repos/symfony/finder/zipball/73089124388c8510efb8d2d1689285d285937b08", + "reference": "73089124388c8510efb8d2d1689285d285937b08", "shasum": "" }, "require": { @@ -4060,7 +4040,7 @@ "description": "Finds files and directories via an intuitive fluent interface", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/finder/tree/v6.4.11" + "source": "https://github.com/symfony/finder/tree/v6.4.24" }, "funding": [ { @@ -4071,25 +4051,29 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2024-08-13T14:27:37+00:00" + "time": "2025-07-15T12:02:45+00:00" }, { "name": "symfony/options-resolver", - "version": "v6.4.8", + "version": "v6.4.24", "source": { "type": "git", "url": "https://github.com/symfony/options-resolver.git", - "reference": "22ab9e9101ab18de37839074f8a1197f55590c1b" + "reference": "baee5736ddf7a0486dd68ca05aa4fd7e64458d3d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/options-resolver/zipball/22ab9e9101ab18de37839074f8a1197f55590c1b", - "reference": "22ab9e9101ab18de37839074f8a1197f55590c1b", + "url": "https://api.github.com/repos/symfony/options-resolver/zipball/baee5736ddf7a0486dd68ca05aa4fd7e64458d3d", + "reference": "baee5736ddf7a0486dd68ca05aa4fd7e64458d3d", "shasum": "" }, "require": { @@ -4127,7 +4111,7 @@ "options" ], "support": { - "source": "https://github.com/symfony/options-resolver/tree/v6.4.8" + "source": "https://github.com/symfony/options-resolver/tree/v6.4.24" }, "funding": [ { @@ -4138,16 +4122,20 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2024-05-31T14:49:08+00:00" + "time": "2025-07-14T16:38:25+00:00" }, { "name": "symfony/polyfill-ctype", - "version": "v1.31.0", + "version": "v1.32.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-ctype.git", @@ -4171,8 +4159,8 @@ "type": "library", "extra": { "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" } }, "autoload": { @@ -4206,7 +4194,7 @@ "portable" ], "support": { - "source": "https://github.com/symfony/polyfill-ctype/tree/v1.31.0" + "source": "https://github.com/symfony/polyfill-ctype/tree/v1.32.0" }, "funding": [ { @@ -4226,7 +4214,7 @@ }, { "name": "symfony/polyfill-intl-grapheme", - "version": "v1.31.0", + "version": "v1.32.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-grapheme.git", @@ -4247,8 +4235,8 @@ "type": "library", "extra": { "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" } }, "autoload": { @@ -4284,7 +4272,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.31.0" + "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.32.0" }, "funding": [ { @@ -4304,7 +4292,7 @@ }, { "name": "symfony/polyfill-intl-normalizer", - "version": "v1.31.0", + "version": "v1.32.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-normalizer.git", @@ -4325,8 +4313,8 @@ "type": "library", "extra": { "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" } }, "autoload": { @@ -4365,7 +4353,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.31.0" + "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.32.0" }, "funding": [ { @@ -4385,19 +4373,20 @@ }, { "name": "symfony/polyfill-mbstring", - "version": "v1.31.0", + "version": "v1.32.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "85181ba99b2345b0ef10ce42ecac37612d9fd341" + "reference": "6d857f4d76bd4b343eac26d6b539585d2bc56493" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/85181ba99b2345b0ef10ce42ecac37612d9fd341", - "reference": "85181ba99b2345b0ef10ce42ecac37612d9fd341", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/6d857f4d76bd4b343eac26d6b539585d2bc56493", + "reference": "6d857f4d76bd4b343eac26d6b539585d2bc56493", "shasum": "" }, "require": { + "ext-iconv": "*", "php": ">=7.2" }, "provide": { @@ -4409,8 +4398,8 @@ "type": "library", "extra": { "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" } }, "autoload": { @@ -4445,7 +4434,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.31.0" + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.32.0" }, "funding": [ { @@ -4461,20 +4450,20 @@ "type": "tidelift" } ], - "time": "2024-09-09T11:45:10+00:00" + "time": "2024-12-23T08:48:59+00:00" }, { "name": "symfony/process", - "version": "v6.4.12", + "version": "v6.4.24", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "3f94e5f13ff58df371a7ead461b6e8068900fbb3" + "reference": "8eb6dc555bfb49b2703438d5de65cc9f138ff50b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/3f94e5f13ff58df371a7ead461b6e8068900fbb3", - "reference": "3f94e5f13ff58df371a7ead461b6e8068900fbb3", + "url": "https://api.github.com/repos/symfony/process/zipball/8eb6dc555bfb49b2703438d5de65cc9f138ff50b", + "reference": "8eb6dc555bfb49b2703438d5de65cc9f138ff50b", "shasum": "" }, "require": { @@ -4506,7 +4495,7 @@ "description": "Executes commands in sub-processes", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/process/tree/v6.4.12" + "source": "https://github.com/symfony/process/tree/v6.4.24" }, "funding": [ { @@ -4517,25 +4506,29 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2024-09-17T12:47:12+00:00" + "time": "2025-07-10T08:14:14+00:00" }, { "name": "symfony/service-contracts", - "version": "v3.5.0", + "version": "v3.6.0", "source": { "type": "git", "url": "https://github.com/symfony/service-contracts.git", - "reference": "bd1d9e59a81d8fa4acdcea3f617c581f7475a80f" + "reference": "f021b05a130d35510bd6b25fe9053c2a8a15d5d4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/service-contracts/zipball/bd1d9e59a81d8fa4acdcea3f617c581f7475a80f", - "reference": "bd1d9e59a81d8fa4acdcea3f617c581f7475a80f", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/f021b05a130d35510bd6b25fe9053c2a8a15d5d4", + "reference": "f021b05a130d35510bd6b25fe9053c2a8a15d5d4", "shasum": "" }, "require": { @@ -4548,12 +4541,12 @@ }, "type": "library", "extra": { - "branch-alias": { - "dev-main": "3.5-dev" - }, "thanks": { - "name": "symfony/contracts", - "url": "https://github.com/symfony/contracts" + "url": "https://github.com/symfony/contracts", + "name": "symfony/contracts" + }, + "branch-alias": { + "dev-main": "3.6-dev" } }, "autoload": { @@ -4589,7 +4582,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/service-contracts/tree/v3.5.0" + "source": "https://github.com/symfony/service-contracts/tree/v3.6.0" }, "funding": [ { @@ -4605,20 +4598,20 @@ "type": "tidelift" } ], - "time": "2024-04-18T09:32:20+00:00" + "time": "2025-04-25T09:37:31+00:00" }, { "name": "symfony/string", - "version": "v6.4.12", + "version": "v6.4.24", "source": { "type": "git", "url": "https://github.com/symfony/string.git", - "reference": "f8a1ccebd0997e16112dfecfd74220b78e5b284b" + "reference": "f0ce0bd36a3accb4a225435be077b4b4875587f4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/f8a1ccebd0997e16112dfecfd74220b78e5b284b", - "reference": "f8a1ccebd0997e16112dfecfd74220b78e5b284b", + "url": "https://api.github.com/repos/symfony/string/zipball/f0ce0bd36a3accb4a225435be077b4b4875587f4", + "reference": "f0ce0bd36a3accb4a225435be077b4b4875587f4", "shasum": "" }, "require": { @@ -4675,7 +4668,7 @@ "utf8" ], "support": { - "source": "https://github.com/symfony/string/tree/v6.4.12" + "source": "https://github.com/symfony/string/tree/v6.4.24" }, "funding": [ { @@ -4686,12 +4679,16 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2024-09-20T08:15:52+00:00" + "time": "2025-07-10T08:14:14+00:00" }, { "name": "theseer/tokenizer", @@ -4818,11 +4815,11 @@ "type": "project", "extra": { "branch-alias": { - "dev-master": "5.x-dev", - "dev-4.x": "4.x-dev", - "dev-3.x": "3.x-dev", + "dev-1.x": "1.x-dev", "dev-2.x": "2.x-dev", - "dev-1.x": "1.x-dev" + "dev-3.x": "3.x-dev", + "dev-4.x": "4.x-dev", + "dev-master": "5.x-dev" } }, "autoload": { @@ -5018,13 +5015,13 @@ ], "aliases": [], "minimum-stability": "stable", - "stability-flags": [], + "stability-flags": {}, "prefer-stable": false, "prefer-lowest": false, "platform": { "php": "~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0" }, - "platform-dev": [], + "platform-dev": {}, "platform-overrides": { "php": "8.1.99" }, diff --git a/vendor/laminas/laminas-servicemanager/src/ServiceManager.php b/vendor/laminas/laminas-servicemanager/src/ServiceManager.php index d63e26312..c1d08e39a 100644 --- a/vendor/laminas/laminas-servicemanager/src/ServiceManager.php +++ b/vendor/laminas/laminas-servicemanager/src/ServiceManager.php @@ -718,8 +718,7 @@ private function mergeDelegators(array $config): array { foreach ($config as $key => $delegators) { if (! array_key_exists($key, $this->delegators)) { - $this->delegators[$key] = $delegators; - continue; + $this->delegators[$key] = []; } foreach ($delegators as $delegator) { diff --git a/vendor/laminas/laminas-validator/composer.lock b/vendor/laminas/laminas-validator/composer.lock index e08eca977..129176b0b 100644 --- a/vendor/laminas/laminas-validator/composer.lock +++ b/vendor/laminas/laminas-validator/composer.lock @@ -8,21 +8,21 @@ "packages": [ { "name": "laminas/laminas-servicemanager", - "version": "3.22.1", + "version": "3.23.0", "source": { "type": "git", "url": "https://github.com/laminas/laminas-servicemanager.git", - "reference": "de98d297d4743956a0558a6d71616979ff779328" + "reference": "a8640182b892b99767d54404d19c5c3b3699f79b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laminas/laminas-servicemanager/zipball/de98d297d4743956a0558a6d71616979ff779328", - "reference": "de98d297d4743956a0558a6d71616979ff779328", + "url": "https://api.github.com/repos/laminas/laminas-servicemanager/zipball/a8640182b892b99767d54404d19c5c3b3699f79b", + "reference": "a8640182b892b99767d54404d19c5c3b3699f79b", "shasum": "" }, "require": { - "laminas/laminas-stdlib": "^3.17", - "php": "~8.1.0 || ~8.2.0 || ~8.3.0", + "laminas/laminas-stdlib": "^3.19", + "php": "~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0", "psr/container": "^1.0" }, "conflict": { @@ -39,15 +39,15 @@ }, "require-dev": { "composer/package-versions-deprecated": "^1.11.99.5", - "friendsofphp/proxy-manager-lts": "^1.0.14", - "laminas/laminas-code": "^4.10.0", + "friendsofphp/proxy-manager-lts": "^1.0.18", + "laminas/laminas-code": "^4.14.0", "laminas/laminas-coding-standard": "~2.5.0", "laminas/laminas-container-config-test": "^0.8", - "mikey179/vfsstream": "^1.6.11", - "phpbench/phpbench": "^1.2.9", - "phpunit/phpunit": "^10.4", + "mikey179/vfsstream": "^1.6.12", + "phpbench/phpbench": "^1.3.1", + "phpunit/phpunit": "^10.5.36", "psalm/plugin-phpunit": "^0.18.4", - "vimeo/psalm": "^5.8.0" + "vimeo/psalm": "^5.26.1" }, "suggest": { "friendsofphp/proxy-manager-lts": "ProxyManager ^2.1.1 to handle lazy initialization of services" @@ -94,34 +94,34 @@ "type": "community_bridge" } ], - "time": "2023-10-24T11:19:47+00:00" + "time": "2024-10-28T21:32:16+00:00" }, { "name": "laminas/laminas-stdlib", - "version": "3.19.0", + "version": "3.20.0", "source": { "type": "git", "url": "https://github.com/laminas/laminas-stdlib.git", - "reference": "6a192dd0882b514e45506f533b833b623b78fff3" + "reference": "8974a1213be42c3e2f70b2c27b17f910291ab2f4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laminas/laminas-stdlib/zipball/6a192dd0882b514e45506f533b833b623b78fff3", - "reference": "6a192dd0882b514e45506f533b833b623b78fff3", + "url": "https://api.github.com/repos/laminas/laminas-stdlib/zipball/8974a1213be42c3e2f70b2c27b17f910291ab2f4", + "reference": "8974a1213be42c3e2f70b2c27b17f910291ab2f4", "shasum": "" }, "require": { - "php": "~8.1.0 || ~8.2.0 || ~8.3.0" + "php": "~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0" }, "conflict": { "zendframework/zend-stdlib": "*" }, "require-dev": { - "laminas/laminas-coding-standard": "^2.5", - "phpbench/phpbench": "^1.2.15", - "phpunit/phpunit": "^10.5.8", - "psalm/plugin-phpunit": "^0.18.4", - "vimeo/psalm": "^5.20.0" + "laminas/laminas-coding-standard": "^3.0", + "phpbench/phpbench": "^1.3.1", + "phpunit/phpunit": "^10.5.38", + "psalm/plugin-phpunit": "^0.19.0", + "vimeo/psalm": "^5.26.1" }, "type": "library", "autoload": { @@ -153,7 +153,7 @@ "type": "community_bridge" } ], - "time": "2024-01-19T12:39:49+00:00" + "time": "2024-10-29T13:46:07+00:00" }, { "name": "psr/container", @@ -493,38 +493,38 @@ }, { "name": "composer/pcre", - "version": "3.2.0", + "version": "3.3.2", "source": { "type": "git", "url": "https://github.com/composer/pcre.git", - "reference": "ea4ab6f9580a4fd221e0418f2c357cdd39102a90" + "reference": "b2bed4734f0cc156ee1fe9c0da2550420d99a21e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/pcre/zipball/ea4ab6f9580a4fd221e0418f2c357cdd39102a90", - "reference": "ea4ab6f9580a4fd221e0418f2c357cdd39102a90", + "url": "https://api.github.com/repos/composer/pcre/zipball/b2bed4734f0cc156ee1fe9c0da2550420d99a21e", + "reference": "b2bed4734f0cc156ee1fe9c0da2550420d99a21e", "shasum": "" }, "require": { "php": "^7.4 || ^8.0" }, "conflict": { - "phpstan/phpstan": "<1.11.8" + "phpstan/phpstan": "<1.11.10" }, "require-dev": { - "phpstan/phpstan": "^1.11.8", - "phpstan/phpstan-strict-rules": "^1.1", + "phpstan/phpstan": "^1.12 || ^2", + "phpstan/phpstan-strict-rules": "^1 || ^2", "phpunit/phpunit": "^8 || ^9" }, "type": "library", "extra": { - "branch-alias": { - "dev-main": "3.x-dev" - }, "phpstan": { "includes": [ "extension.neon" ] + }, + "branch-alias": { + "dev-main": "3.x-dev" } }, "autoload": { @@ -552,7 +552,7 @@ ], "support": { "issues": "https://github.com/composer/pcre/issues", - "source": "https://github.com/composer/pcre/tree/3.2.0" + "source": "https://github.com/composer/pcre/tree/3.3.2" }, "funding": [ { @@ -568,28 +568,28 @@ "type": "tidelift" } ], - "time": "2024-07-25T09:36:02+00:00" + "time": "2024-11-12T16:29:46+00:00" }, { "name": "composer/semver", - "version": "3.4.2", + "version": "3.4.3", "source": { "type": "git", "url": "https://github.com/composer/semver.git", - "reference": "c51258e759afdb17f1fd1fe83bc12baaef6309d6" + "reference": "4313d26ada5e0c4edfbd1dc481a92ff7bff91f12" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/semver/zipball/c51258e759afdb17f1fd1fe83bc12baaef6309d6", - "reference": "c51258e759afdb17f1fd1fe83bc12baaef6309d6", + "url": "https://api.github.com/repos/composer/semver/zipball/4313d26ada5e0c4edfbd1dc481a92ff7bff91f12", + "reference": "4313d26ada5e0c4edfbd1dc481a92ff7bff91f12", "shasum": "" }, "require": { "php": "^5.3.2 || ^7.0 || ^8.0" }, "require-dev": { - "phpstan/phpstan": "^1.4", - "symfony/phpunit-bridge": "^4.2 || ^5" + "phpstan/phpstan": "^1.11", + "symfony/phpunit-bridge": "^3 || ^7" }, "type": "library", "extra": { @@ -633,7 +633,7 @@ "support": { "irc": "ircs://irc.libera.chat:6697/composer", "issues": "https://github.com/composer/semver/issues", - "source": "https://github.com/composer/semver/tree/3.4.2" + "source": "https://github.com/composer/semver/tree/3.4.3" }, "funding": [ { @@ -649,7 +649,7 @@ "type": "tidelift" } ], - "time": "2024-07-12T11:35:52+00:00" + "time": "2024-09-19T14:15:21+00:00" }, { "name": "composer/xdebug-handler", @@ -876,16 +876,16 @@ }, { "name": "felixfbecker/language-server-protocol", - "version": "v1.5.2", + "version": "v1.5.3", "source": { "type": "git", "url": "https://github.com/felixfbecker/php-language-server-protocol.git", - "reference": "6e82196ffd7c62f7794d778ca52b69feec9f2842" + "reference": "a9e113dbc7d849e35b8776da39edaf4313b7b6c9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/felixfbecker/php-language-server-protocol/zipball/6e82196ffd7c62f7794d778ca52b69feec9f2842", - "reference": "6e82196ffd7c62f7794d778ca52b69feec9f2842", + "url": "https://api.github.com/repos/felixfbecker/php-language-server-protocol/zipball/a9e113dbc7d849e35b8776da39edaf4313b7b6c9", + "reference": "a9e113dbc7d849e35b8776da39edaf4313b7b6c9", "shasum": "" }, "require": { @@ -926,22 +926,22 @@ ], "support": { "issues": "https://github.com/felixfbecker/php-language-server-protocol/issues", - "source": "https://github.com/felixfbecker/php-language-server-protocol/tree/v1.5.2" + "source": "https://github.com/felixfbecker/php-language-server-protocol/tree/v1.5.3" }, - "time": "2022-03-02T22:36:06+00:00" + "time": "2024-04-30T00:40:11+00:00" }, { "name": "fidry/cpu-core-counter", - "version": "1.1.0", + "version": "1.2.0", "source": { "type": "git", "url": "https://github.com/theofidry/cpu-core-counter.git", - "reference": "f92996c4d5c1a696a6a970e20f7c4216200fcc42" + "reference": "8520451a140d3f46ac33042715115e290cf5785f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/theofidry/cpu-core-counter/zipball/f92996c4d5c1a696a6a970e20f7c4216200fcc42", - "reference": "f92996c4d5c1a696a6a970e20f7c4216200fcc42", + "url": "https://api.github.com/repos/theofidry/cpu-core-counter/zipball/8520451a140d3f46ac33042715115e290cf5785f", + "reference": "8520451a140d3f46ac33042715115e290cf5785f", "shasum": "" }, "require": { @@ -981,7 +981,7 @@ ], "support": { "issues": "https://github.com/theofidry/cpu-core-counter/issues", - "source": "https://github.com/theofidry/cpu-core-counter/tree/1.1.0" + "source": "https://github.com/theofidry/cpu-core-counter/tree/1.2.0" }, "funding": [ { @@ -989,7 +989,7 @@ "type": "github" } ], - "time": "2024-02-07T09:43:46+00:00" + "time": "2024-08-06T10:04:20+00:00" }, { "name": "laminas/laminas-coding-standard", @@ -1120,33 +1120,32 @@ }, { "name": "laminas/laminas-escaper", - "version": "2.13.0", + "version": "2.17.0", "source": { "type": "git", "url": "https://github.com/laminas/laminas-escaper.git", - "reference": "af459883f4018d0f8a0c69c7a209daef3bf973ba" + "reference": "df1ef9503299a8e3920079a16263b578eaf7c3ba" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laminas/laminas-escaper/zipball/af459883f4018d0f8a0c69c7a209daef3bf973ba", - "reference": "af459883f4018d0f8a0c69c7a209daef3bf973ba", + "url": "https://api.github.com/repos/laminas/laminas-escaper/zipball/df1ef9503299a8e3920079a16263b578eaf7c3ba", + "reference": "df1ef9503299a8e3920079a16263b578eaf7c3ba", "shasum": "" }, "require": { "ext-ctype": "*", "ext-mbstring": "*", - "php": "~8.1.0 || ~8.2.0 || ~8.3.0" + "php": "~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0" }, "conflict": { "zendframework/zend-escaper": "*" }, "require-dev": { - "infection/infection": "^0.27.0", - "laminas/laminas-coding-standard": "~2.5.0", - "maglnet/composer-require-checker": "^3.8.0", - "phpunit/phpunit": "^9.6.7", - "psalm/plugin-phpunit": "^0.18.4", - "vimeo/psalm": "^5.9" + "infection/infection": "^0.29.8", + "laminas/laminas-coding-standard": "~3.0.1", + "phpunit/phpunit": "^10.5.45", + "psalm/plugin-phpunit": "^0.19.2", + "vimeo/psalm": "^6.6.2" }, "type": "library", "autoload": { @@ -1178,37 +1177,37 @@ "type": "community_bridge" } ], - "time": "2023-10-10T08:35:13+00:00" + "time": "2025-05-06T19:29:36+00:00" }, { "name": "laminas/laminas-eventmanager", - "version": "3.13.1", + "version": "3.14.0", "source": { "type": "git", "url": "https://github.com/laminas/laminas-eventmanager.git", - "reference": "933d1b5cf03fa4cf3016cebfd0555fa2ba3f2024" + "reference": "1837cafaaaee74437f6d8ec9ff7da03e6f81d809" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laminas/laminas-eventmanager/zipball/933d1b5cf03fa4cf3016cebfd0555fa2ba3f2024", - "reference": "933d1b5cf03fa4cf3016cebfd0555fa2ba3f2024", + "url": "https://api.github.com/repos/laminas/laminas-eventmanager/zipball/1837cafaaaee74437f6d8ec9ff7da03e6f81d809", + "reference": "1837cafaaaee74437f6d8ec9ff7da03e6f81d809", "shasum": "" }, "require": { - "php": "~8.1.0 || ~8.2.0 || ~8.3.0" + "php": "~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0" }, "conflict": { "container-interop/container-interop": "<1.2", "zendframework/zend-eventmanager": "*" }, "require-dev": { - "laminas/laminas-coding-standard": "~2.5.0", - "laminas/laminas-stdlib": "^3.18", - "phpbench/phpbench": "^1.2.15", - "phpunit/phpunit": "^10.5.5", - "psalm/plugin-phpunit": "^0.18.4", + "laminas/laminas-coding-standard": "~3.0.0", + "laminas/laminas-stdlib": "^3.20", + "phpbench/phpbench": "^1.3.1", + "phpunit/phpunit": "^10.5.38", + "psalm/plugin-phpunit": "^0.19.0", "psr/container": "^1.1.2 || ^2.0.2", - "vimeo/psalm": "^5.18" + "vimeo/psalm": "^5.26.1" }, "suggest": { "laminas/laminas-stdlib": "^2.7.3 || ^3.0, to use the FilterChain feature", @@ -1246,42 +1245,42 @@ "type": "community_bridge" } ], - "time": "2024-06-24T14:01:06+00:00" + "time": "2024-11-21T11:31:22+00:00" }, { "name": "laminas/laminas-filter", - "version": "2.36.0", + "version": "2.41.0", "source": { "type": "git", "url": "https://github.com/laminas/laminas-filter.git", - "reference": "307afc21ada0648e84cdcf9e14cd84bd43ee9d13" + "reference": "eaa00111231bf6669826ae84d3abe85b94477585" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laminas/laminas-filter/zipball/307afc21ada0648e84cdcf9e14cd84bd43ee9d13", - "reference": "307afc21ada0648e84cdcf9e14cd84bd43ee9d13", + "url": "https://api.github.com/repos/laminas/laminas-filter/zipball/eaa00111231bf6669826ae84d3abe85b94477585", + "reference": "eaa00111231bf6669826ae84d3abe85b94477585", "shasum": "" }, "require": { "ext-mbstring": "*", "laminas/laminas-servicemanager": "^3.21.0", - "laminas/laminas-stdlib": "^3.13.0", - "php": "~8.1.0 || ~8.2.0 || ~8.3.0" + "laminas/laminas-stdlib": "^3.19.0", + "php": "~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0" }, "conflict": { "laminas/laminas-validator": "<2.10.1", "zendframework/zend-filter": "*" }, "require-dev": { - "laminas/laminas-coding-standard": "~2.5.0", - "laminas/laminas-crypt": "^3.11", - "laminas/laminas-i18n": "^2.26.0", - "laminas/laminas-uri": "^2.11", + "laminas/laminas-coding-standard": "~3.0", + "laminas/laminas-crypt": "^3.12", + "laminas/laminas-i18n": "^2.28.1", + "laminas/laminas-uri": "^2.12", "pear/archive_tar": "^1.5.0", - "phpunit/phpunit": "^10.5.20", + "phpunit/phpunit": "^10.5.36", "psalm/plugin-phpunit": "^0.19.0", "psr/http-factory": "^1.1.0", - "vimeo/psalm": "^5.24.0" + "vimeo/psalm": "^5.26.1" }, "suggest": { "laminas/laminas-crypt": "Laminas\\Crypt component, for encryption filters", @@ -1325,20 +1324,20 @@ "type": "community_bridge" } ], - "time": "2024-06-13T10:31:36+00:00" + "time": "2025-05-05T02:02:31+00:00" }, { "name": "laminas/laminas-i18n", - "version": "2.28.0", + "version": "2.30.0", "source": { "type": "git", "url": "https://github.com/laminas/laminas-i18n.git", - "reference": "e1e312650232e5ef26c28ea08f3c4c18633f48c3" + "reference": "397907ee061e147939364df9d6c485ac1e0fed87" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laminas/laminas-i18n/zipball/e1e312650232e5ef26c28ea08f3c4c18633f48c3", - "reference": "e1e312650232e5ef26c28ea08f3c4c18633f48c3", + "url": "https://api.github.com/repos/laminas/laminas-i18n/zipball/397907ee061e147939364df9d6c485ac1e0fed87", + "reference": "397907ee061e147939364df9d6c485ac1e0fed87", "shasum": "" }, "require": { @@ -1346,25 +1345,25 @@ "laminas/laminas-servicemanager": "^3.21.0", "laminas/laminas-stdlib": "^3.0", "laminas/laminas-translator": "^1.0", - "php": "~8.1.0 || ~8.2.0 || ~8.3.0" + "php": "~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0" }, "conflict": { "laminas/laminas-view": "<2.20.0", "zendframework/zend-i18n": "*" }, "require-dev": { - "laminas/laminas-cache": "^3.12.1", - "laminas/laminas-cache-storage-adapter-memory": "^2.3.0", - "laminas/laminas-cache-storage-deprecated-factory": "^1.2", + "laminas/laminas-cache": "^3.13.0", + "laminas/laminas-cache-storage-adapter-memory": "^2.4.0", + "laminas/laminas-cache-storage-deprecated-factory": "^1.3", "laminas/laminas-coding-standard": "~2.5.0", - "laminas/laminas-config": "^3.9.0", - "laminas/laminas-eventmanager": "^3.13", - "laminas/laminas-filter": "^2.34", - "laminas/laminas-validator": "^2.49", - "laminas/laminas-view": "^2.34", - "phpunit/phpunit": "^10.5.11", - "psalm/plugin-phpunit": "^0.19.0", - "vimeo/psalm": "^5.22.2" + "laminas/laminas-config": "^3.10.1", + "laminas/laminas-eventmanager": "^3.14.0", + "laminas/laminas-filter": "^2.40", + "laminas/laminas-validator": "^2.64.2", + "laminas/laminas-view": "^2.36", + "phpunit/phpunit": "^10.5.45", + "psalm/plugin-phpunit": "^0.19.5", + "vimeo/psalm": "^6.10.0" }, "suggest": { "laminas/laminas-cache": "You should install this package to cache the translations", @@ -1411,43 +1410,44 @@ "type": "community_bridge" } ], - "time": "2024-07-15T12:54:14+00:00" + "time": "2025-04-15T09:07:02+00:00" }, { "name": "laminas/laminas-session", - "version": "2.21.0", + "version": "2.24.0", "source": { "type": "git", "url": "https://github.com/laminas/laminas-session.git", - "reference": "b8cd890f7682a255b335c2ca45df9a7cbc58873d" + "reference": "487b6debacd3e029e27cbed7ce495b1328908dab" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laminas/laminas-session/zipball/b8cd890f7682a255b335c2ca45df9a7cbc58873d", - "reference": "b8cd890f7682a255b335c2ca45df9a7cbc58873d", + "url": "https://api.github.com/repos/laminas/laminas-session/zipball/487b6debacd3e029e27cbed7ce495b1328908dab", + "reference": "487b6debacd3e029e27cbed7ce495b1328908dab", "shasum": "" }, "require": { "laminas/laminas-eventmanager": "^3.12", "laminas/laminas-servicemanager": "^3.22", "laminas/laminas-stdlib": "^3.18", - "php": "~8.1.0 || ~8.2.0 || ~8.3.0" + "php": "~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0" }, "conflict": { + "amphp/amp": "<2.6.4", "zendframework/zend-session": "*" }, "require-dev": { "ext-xdebug": "*", "laminas/laminas-cache": "^3.12.2", "laminas/laminas-cache-storage-adapter-memory": "^2.3", - "laminas/laminas-coding-standard": "~2.5.0", + "laminas/laminas-coding-standard": "~3.0.1", "laminas/laminas-db": "^2.20.0", - "laminas/laminas-http": "^2.19", - "laminas/laminas-validator": "^2.57.0", - "mongodb/mongodb": "~1.17.1", - "phpunit/phpunit": "^9.6.19", + "laminas/laminas-http": "^2.20", + "laminas/laminas-validator": "^2.64.1", + "mongodb/mongodb": "~1.20.0", + "phpunit/phpunit": "^10.5.38", "psalm/plugin-phpunit": "^0.19.0", - "vimeo/psalm": "^5.24.0" + "vimeo/psalm": "^5.26.1" }, "suggest": { "laminas/laminas-cache": "Laminas\\Cache component", @@ -1493,27 +1493,27 @@ "type": "community_bridge" } ], - "time": "2024-06-19T14:36:45+00:00" + "time": "2025-02-05T10:39:08+00:00" }, { "name": "laminas/laminas-translator", - "version": "1.0.0", + "version": "1.1.0", "source": { "type": "git", "url": "https://github.com/laminas/laminas-translator.git", - "reference": "86d176c01a96b0ef205192b776cb69e8d4ca06b1" + "reference": "12897e710e21413c1f93fc38fe9dead6b51c5218" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laminas/laminas-translator/zipball/86d176c01a96b0ef205192b776cb69e8d4ca06b1", - "reference": "86d176c01a96b0ef205192b776cb69e8d4ca06b1", + "url": "https://api.github.com/repos/laminas/laminas-translator/zipball/12897e710e21413c1f93fc38fe9dead6b51c5218", + "reference": "12897e710e21413c1f93fc38fe9dead6b51c5218", "shasum": "" }, "require": { - "php": "~8.1.0 || ~8.2.0 || ~8.3.0" + "php": "~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0" }, "require-dev": { - "laminas/laminas-coding-standard": "~2.5.0", + "laminas/laminas-coding-standard": "~3.0.0", "vimeo/psalm": "^5.24.0" }, "type": "library", @@ -1546,33 +1546,33 @@ "type": "community_bridge" } ], - "time": "2024-06-18T15:09:24+00:00" + "time": "2024-10-21T15:33:01+00:00" }, { "name": "laminas/laminas-uri", - "version": "2.11.0", + "version": "2.13.0", "source": { "type": "git", "url": "https://github.com/laminas/laminas-uri.git", - "reference": "e662c685125061d3115906e5eb30f966842cc226" + "reference": "de53600ae8153b3605bb6edce8aeeef524eaafba" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laminas/laminas-uri/zipball/e662c685125061d3115906e5eb30f966842cc226", - "reference": "e662c685125061d3115906e5eb30f966842cc226", + "url": "https://api.github.com/repos/laminas/laminas-uri/zipball/de53600ae8153b3605bb6edce8aeeef524eaafba", + "reference": "de53600ae8153b3605bb6edce8aeeef524eaafba", "shasum": "" }, "require": { "laminas/laminas-escaper": "^2.9", - "laminas/laminas-validator": "^2.39", - "php": "~8.1.0 || ~8.2.0 || ~8.3.0" + "laminas/laminas-validator": "^2.39 || ^3.0", + "php": "~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0" }, "conflict": { "zendframework/zend-uri": "*" }, "require-dev": { "laminas/laminas-coding-standard": "~2.4.0", - "phpunit/phpunit": "^9.5.25" + "phpunit/phpunit": "^9.6.20" }, "type": "library", "autoload": { @@ -1604,20 +1604,20 @@ "type": "community_bridge" } ], - "time": "2023-10-18T09:56:55+00:00" + "time": "2024-12-03T12:27:51+00:00" }, { "name": "myclabs/deep-copy", - "version": "1.12.0", + "version": "1.13.1", "source": { "type": "git", "url": "https://github.com/myclabs/DeepCopy.git", - "reference": "3a6b9a42cd8f8771bd4295d13e1423fa7f3d942c" + "reference": "1720ddd719e16cf0db4eb1c6eca108031636d46c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/3a6b9a42cd8f8771bd4295d13e1423fa7f3d942c", - "reference": "3a6b9a42cd8f8771bd4295d13e1423fa7f3d942c", + "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/1720ddd719e16cf0db4eb1c6eca108031636d46c", + "reference": "1720ddd719e16cf0db4eb1c6eca108031636d46c", "shasum": "" }, "require": { @@ -1656,7 +1656,7 @@ ], "support": { "issues": "https://github.com/myclabs/DeepCopy/issues", - "source": "https://github.com/myclabs/DeepCopy/tree/1.12.0" + "source": "https://github.com/myclabs/DeepCopy/tree/1.13.1" }, "funding": [ { @@ -1664,20 +1664,20 @@ "type": "tidelift" } ], - "time": "2024-06-12T14:39:25+00:00" + "time": "2025-04-29T12:36:36+00:00" }, { "name": "netresearch/jsonmapper", - "version": "v4.4.1", + "version": "v4.5.0", "source": { "type": "git", "url": "https://github.com/cweiske/jsonmapper.git", - "reference": "132c75c7dd83e45353ebb9c6c9f591952995bbf0" + "reference": "8e76efb98ee8b6afc54687045e1b8dba55ac76e5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/cweiske/jsonmapper/zipball/132c75c7dd83e45353ebb9c6c9f591952995bbf0", - "reference": "132c75c7dd83e45353ebb9c6c9f591952995bbf0", + "url": "https://api.github.com/repos/cweiske/jsonmapper/zipball/8e76efb98ee8b6afc54687045e1b8dba55ac76e5", + "reference": "8e76efb98ee8b6afc54687045e1b8dba55ac76e5", "shasum": "" }, "require": { @@ -1713,22 +1713,22 @@ "support": { "email": "cweiske@cweiske.de", "issues": "https://github.com/cweiske/jsonmapper/issues", - "source": "https://github.com/cweiske/jsonmapper/tree/v4.4.1" + "source": "https://github.com/cweiske/jsonmapper/tree/v4.5.0" }, - "time": "2024-01-31T06:18:54+00:00" + "time": "2024-09-08T10:13:13+00:00" }, { "name": "nikic/php-parser", - "version": "v4.19.1", + "version": "v4.19.4", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "4e1b88d21c69391150ace211e9eaf05810858d0b" + "reference": "715f4d25e225bc47b293a8b997fe6ce99bf987d2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/4e1b88d21c69391150ace211e9eaf05810858d0b", - "reference": "4e1b88d21c69391150ace211e9eaf05810858d0b", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/715f4d25e225bc47b293a8b997fe6ce99bf987d2", + "reference": "715f4d25e225bc47b293a8b997fe6ce99bf987d2", "shasum": "" }, "require": { @@ -1737,7 +1737,7 @@ }, "require-dev": { "ircmaxell/php-yacc": "^0.0.7", - "phpunit/phpunit": "^6.5 || ^7.0 || ^8.0 || ^9.0" + "phpunit/phpunit": "^7.0 || ^8.0 || ^9.0" }, "bin": [ "bin/php-parse" @@ -1769,9 +1769,9 @@ ], "support": { "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/v4.19.1" + "source": "https://github.com/nikic/PHP-Parser/tree/v4.19.4" }, - "time": "2024-03-17T08:10:35+00:00" + "time": "2024-09-29T15:01:53+00:00" }, { "name": "phar-io/manifest", @@ -2102,32 +2102,32 @@ }, { "name": "phpunit/php-code-coverage", - "version": "10.1.15", + "version": "10.1.16", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "5da8b1728acd1e6ffdf2ff32ffbdfd04307f26ae" + "reference": "7e308268858ed6baedc8704a304727d20bc07c77" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/5da8b1728acd1e6ffdf2ff32ffbdfd04307f26ae", - "reference": "5da8b1728acd1e6ffdf2ff32ffbdfd04307f26ae", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/7e308268858ed6baedc8704a304727d20bc07c77", + "reference": "7e308268858ed6baedc8704a304727d20bc07c77", "shasum": "" }, "require": { "ext-dom": "*", "ext-libxml": "*", "ext-xmlwriter": "*", - "nikic/php-parser": "^4.18 || ^5.0", + "nikic/php-parser": "^4.19.1 || ^5.1.0", "php": ">=8.1", - "phpunit/php-file-iterator": "^4.0", - "phpunit/php-text-template": "^3.0", - "sebastian/code-unit-reverse-lookup": "^3.0", - "sebastian/complexity": "^3.0", - "sebastian/environment": "^6.0", - "sebastian/lines-of-code": "^2.0", - "sebastian/version": "^4.0", - "theseer/tokenizer": "^1.2.0" + "phpunit/php-file-iterator": "^4.1.0", + "phpunit/php-text-template": "^3.0.1", + "sebastian/code-unit-reverse-lookup": "^3.0.0", + "sebastian/complexity": "^3.2.0", + "sebastian/environment": "^6.1.0", + "sebastian/lines-of-code": "^2.0.2", + "sebastian/version": "^4.0.1", + "theseer/tokenizer": "^1.2.3" }, "require-dev": { "phpunit/phpunit": "^10.1" @@ -2139,7 +2139,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "10.1-dev" + "dev-main": "10.1.x-dev" } }, "autoload": { @@ -2168,7 +2168,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", "security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy", - "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/10.1.15" + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/10.1.16" }, "funding": [ { @@ -2176,7 +2176,7 @@ "type": "github" } ], - "time": "2024-06-29T08:25:15+00:00" + "time": "2024-08-22T04:31:57+00:00" }, { "name": "phpunit/php-file-iterator", @@ -2423,16 +2423,16 @@ }, { "name": "phpunit/phpunit", - "version": "10.5.29", + "version": "10.5.46", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "8e9e80872b4e8064401788ee8a32d40b4455318f" + "reference": "8080be387a5be380dda48c6f41cee4a13aadab3d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/8e9e80872b4e8064401788ee8a32d40b4455318f", - "reference": "8e9e80872b4e8064401788ee8a32d40b4455318f", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/8080be387a5be380dda48c6f41cee4a13aadab3d", + "reference": "8080be387a5be380dda48c6f41cee4a13aadab3d", "shasum": "" }, "require": { @@ -2442,18 +2442,18 @@ "ext-mbstring": "*", "ext-xml": "*", "ext-xmlwriter": "*", - "myclabs/deep-copy": "^1.12.0", + "myclabs/deep-copy": "^1.13.1", "phar-io/manifest": "^2.0.4", "phar-io/version": "^3.2.1", "php": ">=8.1", - "phpunit/php-code-coverage": "^10.1.15", + "phpunit/php-code-coverage": "^10.1.16", "phpunit/php-file-iterator": "^4.1.0", "phpunit/php-invoker": "^4.0.0", "phpunit/php-text-template": "^3.0.1", "phpunit/php-timer": "^6.0.0", "sebastian/cli-parser": "^2.0.1", "sebastian/code-unit": "^2.0.0", - "sebastian/comparator": "^5.0.1", + "sebastian/comparator": "^5.0.3", "sebastian/diff": "^5.1.1", "sebastian/environment": "^6.1.0", "sebastian/exporter": "^5.1.2", @@ -2504,7 +2504,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", "security": "https://github.com/sebastianbergmann/phpunit/security/policy", - "source": "https://github.com/sebastianbergmann/phpunit/tree/10.5.29" + "source": "https://github.com/sebastianbergmann/phpunit/tree/10.5.46" }, "funding": [ { @@ -2515,12 +2515,20 @@ "url": "https://github.com/sebastianbergmann", "type": "github" }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, { "url": "https://tidelift.com/funding/github/packagist/phpunit/phpunit", "type": "tidelift" } ], - "time": "2024-07-30T11:08:00+00:00" + "time": "2025-05-02T06:46:24+00:00" }, { "name": "psalm/plugin-phpunit", @@ -2691,16 +2699,16 @@ }, { "name": "psr/log", - "version": "3.0.0", + "version": "3.0.2", "source": { "type": "git", "url": "https://github.com/php-fig/log.git", - "reference": "fe5ea303b0887d5caefd3d431c3e61ad47037001" + "reference": "f16e1d5863e37f8d8c2a01719f5b34baa2b714d3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/log/zipball/fe5ea303b0887d5caefd3d431c3e61ad47037001", - "reference": "fe5ea303b0887d5caefd3d431c3e61ad47037001", + "url": "https://api.github.com/repos/php-fig/log/zipball/f16e1d5863e37f8d8c2a01719f5b34baa2b714d3", + "reference": "f16e1d5863e37f8d8c2a01719f5b34baa2b714d3", "shasum": "" }, "require": { @@ -2735,9 +2743,9 @@ "psr-3" ], "support": { - "source": "https://github.com/php-fig/log/tree/3.0.0" + "source": "https://github.com/php-fig/log/tree/3.0.2" }, - "time": "2021-07-14T16:46:02+00:00" + "time": "2024-09-11T13:17:53+00:00" }, { "name": "sebastian/cli-parser", @@ -2909,16 +2917,16 @@ }, { "name": "sebastian/comparator", - "version": "5.0.1", + "version": "5.0.3", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/comparator.git", - "reference": "2db5010a484d53ebf536087a70b4a5423c102372" + "reference": "a18251eb0b7a2dcd2f7aa3d6078b18545ef0558e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/2db5010a484d53ebf536087a70b4a5423c102372", - "reference": "2db5010a484d53ebf536087a70b4a5423c102372", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/a18251eb0b7a2dcd2f7aa3d6078b18545ef0558e", + "reference": "a18251eb0b7a2dcd2f7aa3d6078b18545ef0558e", "shasum": "" }, "require": { @@ -2929,7 +2937,7 @@ "sebastian/exporter": "^5.0" }, "require-dev": { - "phpunit/phpunit": "^10.3" + "phpunit/phpunit": "^10.5" }, "type": "library", "extra": { @@ -2974,7 +2982,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/comparator/issues", "security": "https://github.com/sebastianbergmann/comparator/security/policy", - "source": "https://github.com/sebastianbergmann/comparator/tree/5.0.1" + "source": "https://github.com/sebastianbergmann/comparator/tree/5.0.3" }, "funding": [ { @@ -2982,7 +2990,7 @@ "type": "github" } ], - "time": "2023-08-14T13:18:12+00:00" + "time": "2024-10-18T14:56:07+00:00" }, { "name": "sebastian/complexity", @@ -3718,16 +3726,16 @@ }, { "name": "spatie/array-to-xml", - "version": "3.3.0", + "version": "3.4.0", "source": { "type": "git", "url": "https://github.com/spatie/array-to-xml.git", - "reference": "f56b220fe2db1ade4c88098d83413ebdfc3bf876" + "reference": "7dcfc67d60b0272926dabad1ec01f6b8a5fb5e67" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/spatie/array-to-xml/zipball/f56b220fe2db1ade4c88098d83413ebdfc3bf876", - "reference": "f56b220fe2db1ade4c88098d83413ebdfc3bf876", + "url": "https://api.github.com/repos/spatie/array-to-xml/zipball/7dcfc67d60b0272926dabad1ec01f6b8a5fb5e67", + "reference": "7dcfc67d60b0272926dabad1ec01f6b8a5fb5e67", "shasum": "" }, "require": { @@ -3770,7 +3778,7 @@ "xml" ], "support": { - "source": "https://github.com/spatie/array-to-xml/tree/3.3.0" + "source": "https://github.com/spatie/array-to-xml/tree/3.4.0" }, "funding": [ { @@ -3782,20 +3790,20 @@ "type": "github" } ], - "time": "2024-05-01T10:20:27+00:00" + "time": "2024-12-16T12:45:15+00:00" }, { "name": "squizlabs/php_codesniffer", - "version": "3.10.2", + "version": "3.13.1", "source": { "type": "git", "url": "https://github.com/PHPCSStandards/PHP_CodeSniffer.git", - "reference": "86e5f5dd9a840c46810ebe5ff1885581c42a3017" + "reference": "1b71b4dd7e7ef651ac749cea67e513c0c832f4bd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/PHPCSStandards/PHP_CodeSniffer/zipball/86e5f5dd9a840c46810ebe5ff1885581c42a3017", - "reference": "86e5f5dd9a840c46810ebe5ff1885581c42a3017", + "url": "https://api.github.com/repos/PHPCSStandards/PHP_CodeSniffer/zipball/1b71b4dd7e7ef651ac749cea67e513c0c832f4bd", + "reference": "1b71b4dd7e7ef651ac749cea67e513c0c832f4bd", "shasum": "" }, "require": { @@ -3860,22 +3868,26 @@ { "url": "https://opencollective.com/php_codesniffer", "type": "open_collective" + }, + { + "url": "https://thanks.dev/u/gh/phpcsstandards", + "type": "thanks_dev" } ], - "time": "2024-07-21T23:26:44+00:00" + "time": "2025-06-12T15:04:34+00:00" }, { "name": "symfony/console", - "version": "v6.4.10", + "version": "v6.4.22", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "504974cbe43d05f83b201d6498c206f16fc0cdbc" + "reference": "7d29659bc3c9d8e9a34e2c3414ef9e9e003e6cf3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/504974cbe43d05f83b201d6498c206f16fc0cdbc", - "reference": "504974cbe43d05f83b201d6498c206f16fc0cdbc", + "url": "https://api.github.com/repos/symfony/console/zipball/7d29659bc3c9d8e9a34e2c3414ef9e9e003e6cf3", + "reference": "7d29659bc3c9d8e9a34e2c3414ef9e9e003e6cf3", "shasum": "" }, "require": { @@ -3940,7 +3952,7 @@ "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v6.4.10" + "source": "https://github.com/symfony/console/tree/v6.4.22" }, "funding": [ { @@ -3956,20 +3968,20 @@ "type": "tidelift" } ], - "time": "2024-07-26T12:30:32+00:00" + "time": "2025-05-07T07:05:04+00:00" }, { "name": "symfony/deprecation-contracts", - "version": "v3.5.0", + "version": "v3.6.0", "source": { "type": "git", "url": "https://github.com/symfony/deprecation-contracts.git", - "reference": "0e0d29ce1f20deffb4ab1b016a7257c4f1e789a1" + "reference": "63afe740e99a13ba87ec199bb07bbdee937a5b62" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/0e0d29ce1f20deffb4ab1b016a7257c4f1e789a1", - "reference": "0e0d29ce1f20deffb4ab1b016a7257c4f1e789a1", + "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/63afe740e99a13ba87ec199bb07bbdee937a5b62", + "reference": "63afe740e99a13ba87ec199bb07bbdee937a5b62", "shasum": "" }, "require": { @@ -3977,12 +3989,12 @@ }, "type": "library", "extra": { - "branch-alias": { - "dev-main": "3.5-dev" - }, "thanks": { - "name": "symfony/contracts", - "url": "https://github.com/symfony/contracts" + "url": "https://github.com/symfony/contracts", + "name": "symfony/contracts" + }, + "branch-alias": { + "dev-main": "3.6-dev" } }, "autoload": { @@ -4007,7 +4019,7 @@ "description": "A generic function and convention to trigger deprecation notices", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/deprecation-contracts/tree/v3.5.0" + "source": "https://github.com/symfony/deprecation-contracts/tree/v3.6.0" }, "funding": [ { @@ -4023,20 +4035,20 @@ "type": "tidelift" } ], - "time": "2024-04-18T09:32:20+00:00" + "time": "2024-09-25T14:21:43+00:00" }, { "name": "symfony/filesystem", - "version": "v6.4.9", + "version": "v6.4.13", "source": { "type": "git", "url": "https://github.com/symfony/filesystem.git", - "reference": "b51ef8059159330b74a4d52f68e671033c0fe463" + "reference": "4856c9cf585d5a0313d8d35afd681a526f038dd3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/b51ef8059159330b74a4d52f68e671033c0fe463", - "reference": "b51ef8059159330b74a4d52f68e671033c0fe463", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/4856c9cf585d5a0313d8d35afd681a526f038dd3", + "reference": "4856c9cf585d5a0313d8d35afd681a526f038dd3", "shasum": "" }, "require": { @@ -4073,7 +4085,7 @@ "description": "Provides basic utilities for the filesystem", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/filesystem/tree/v6.4.9" + "source": "https://github.com/symfony/filesystem/tree/v6.4.13" }, "funding": [ { @@ -4089,24 +4101,24 @@ "type": "tidelift" } ], - "time": "2024-06-28T09:49:33+00:00" + "time": "2024-10-25T15:07:50+00:00" }, { "name": "symfony/polyfill-ctype", - "version": "v1.30.0", + "version": "v1.32.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-ctype.git", - "reference": "0424dff1c58f028c451efff2045f5d92410bd540" + "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/0424dff1c58f028c451efff2045f5d92410bd540", - "reference": "0424dff1c58f028c451efff2045f5d92410bd540", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/a3cc8b044a6ea513310cbd48ef7333b384945638", + "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638", "shasum": "" }, "require": { - "php": ">=7.1" + "php": ">=7.2" }, "provide": { "ext-ctype": "*" @@ -4117,8 +4129,8 @@ "type": "library", "extra": { "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" } }, "autoload": { @@ -4152,7 +4164,7 @@ "portable" ], "support": { - "source": "https://github.com/symfony/polyfill-ctype/tree/v1.30.0" + "source": "https://github.com/symfony/polyfill-ctype/tree/v1.32.0" }, "funding": [ { @@ -4168,24 +4180,24 @@ "type": "tidelift" } ], - "time": "2024-05-31T15:07:36+00:00" + "time": "2024-09-09T11:45:10+00:00" }, { "name": "symfony/polyfill-intl-grapheme", - "version": "v1.30.0", + "version": "v1.32.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-grapheme.git", - "reference": "64647a7c30b2283f5d49b874d84a18fc22054b7a" + "reference": "b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/64647a7c30b2283f5d49b874d84a18fc22054b7a", - "reference": "64647a7c30b2283f5d49b874d84a18fc22054b7a", + "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe", + "reference": "b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe", "shasum": "" }, "require": { - "php": ">=7.1" + "php": ">=7.2" }, "suggest": { "ext-intl": "For best performance" @@ -4193,8 +4205,8 @@ "type": "library", "extra": { "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" } }, "autoload": { @@ -4230,7 +4242,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.30.0" + "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.32.0" }, "funding": [ { @@ -4246,24 +4258,24 @@ "type": "tidelift" } ], - "time": "2024-05-31T15:07:36+00:00" + "time": "2024-09-09T11:45:10+00:00" }, { "name": "symfony/polyfill-intl-normalizer", - "version": "v1.30.0", + "version": "v1.32.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-normalizer.git", - "reference": "a95281b0be0d9ab48050ebd988b967875cdb9fdb" + "reference": "3833d7255cc303546435cb650316bff708a1c75c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/a95281b0be0d9ab48050ebd988b967875cdb9fdb", - "reference": "a95281b0be0d9ab48050ebd988b967875cdb9fdb", + "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/3833d7255cc303546435cb650316bff708a1c75c", + "reference": "3833d7255cc303546435cb650316bff708a1c75c", "shasum": "" }, "require": { - "php": ">=7.1" + "php": ">=7.2" }, "suggest": { "ext-intl": "For best performance" @@ -4271,8 +4283,8 @@ "type": "library", "extra": { "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" } }, "autoload": { @@ -4311,7 +4323,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.30.0" + "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.32.0" }, "funding": [ { @@ -4327,24 +4339,25 @@ "type": "tidelift" } ], - "time": "2024-05-31T15:07:36+00:00" + "time": "2024-09-09T11:45:10+00:00" }, { "name": "symfony/polyfill-mbstring", - "version": "v1.30.0", + "version": "v1.32.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "fd22ab50000ef01661e2a31d850ebaa297f8e03c" + "reference": "6d857f4d76bd4b343eac26d6b539585d2bc56493" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/fd22ab50000ef01661e2a31d850ebaa297f8e03c", - "reference": "fd22ab50000ef01661e2a31d850ebaa297f8e03c", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/6d857f4d76bd4b343eac26d6b539585d2bc56493", + "reference": "6d857f4d76bd4b343eac26d6b539585d2bc56493", "shasum": "" }, "require": { - "php": ">=7.1" + "ext-iconv": "*", + "php": ">=7.2" }, "provide": { "ext-mbstring": "*" @@ -4355,8 +4368,8 @@ "type": "library", "extra": { "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" } }, "autoload": { @@ -4391,7 +4404,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.30.0" + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.32.0" }, "funding": [ { @@ -4407,20 +4420,20 @@ "type": "tidelift" } ], - "time": "2024-06-19T12:30:46+00:00" + "time": "2024-12-23T08:48:59+00:00" }, { "name": "symfony/service-contracts", - "version": "v3.5.0", + "version": "v3.6.0", "source": { "type": "git", "url": "https://github.com/symfony/service-contracts.git", - "reference": "bd1d9e59a81d8fa4acdcea3f617c581f7475a80f" + "reference": "f021b05a130d35510bd6b25fe9053c2a8a15d5d4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/service-contracts/zipball/bd1d9e59a81d8fa4acdcea3f617c581f7475a80f", - "reference": "bd1d9e59a81d8fa4acdcea3f617c581f7475a80f", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/f021b05a130d35510bd6b25fe9053c2a8a15d5d4", + "reference": "f021b05a130d35510bd6b25fe9053c2a8a15d5d4", "shasum": "" }, "require": { @@ -4433,12 +4446,12 @@ }, "type": "library", "extra": { - "branch-alias": { - "dev-main": "3.5-dev" - }, "thanks": { - "name": "symfony/contracts", - "url": "https://github.com/symfony/contracts" + "url": "https://github.com/symfony/contracts", + "name": "symfony/contracts" + }, + "branch-alias": { + "dev-main": "3.6-dev" } }, "autoload": { @@ -4474,7 +4487,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/service-contracts/tree/v3.5.0" + "source": "https://github.com/symfony/service-contracts/tree/v3.6.0" }, "funding": [ { @@ -4490,20 +4503,20 @@ "type": "tidelift" } ], - "time": "2024-04-18T09:32:20+00:00" + "time": "2025-04-25T09:37:31+00:00" }, { "name": "symfony/string", - "version": "v6.4.10", + "version": "v6.4.21", "source": { "type": "git", "url": "https://github.com/symfony/string.git", - "reference": "ccf9b30251719567bfd46494138327522b9a9446" + "reference": "73e2c6966a5aef1d4892873ed5322245295370c6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/ccf9b30251719567bfd46494138327522b9a9446", - "reference": "ccf9b30251719567bfd46494138327522b9a9446", + "url": "https://api.github.com/repos/symfony/string/zipball/73e2c6966a5aef1d4892873ed5322245295370c6", + "reference": "73e2c6966a5aef1d4892873ed5322245295370c6", "shasum": "" }, "require": { @@ -4560,7 +4573,7 @@ "utf8" ], "support": { - "source": "https://github.com/symfony/string/tree/v6.4.10" + "source": "https://github.com/symfony/string/tree/v6.4.21" }, "funding": [ { @@ -4576,7 +4589,7 @@ "type": "tidelift" } ], - "time": "2024-07-22T10:21:14+00:00" + "time": "2025-04-18T15:23:29+00:00" }, { "name": "theseer/tokenizer", @@ -4630,16 +4643,16 @@ }, { "name": "vimeo/psalm", - "version": "5.25.0", + "version": "5.26.1", "source": { "type": "git", "url": "https://github.com/vimeo/psalm.git", - "reference": "01a8eb06b9e9cc6cfb6a320bf9fb14331919d505" + "reference": "d747f6500b38ac4f7dfc5edbcae6e4b637d7add0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/vimeo/psalm/zipball/01a8eb06b9e9cc6cfb6a320bf9fb14331919d505", - "reference": "01a8eb06b9e9cc6cfb6a320bf9fb14331919d505", + "url": "https://api.github.com/repos/vimeo/psalm/zipball/d747f6500b38ac4f7dfc5edbcae6e4b637d7add0", + "reference": "d747f6500b38ac4f7dfc5edbcae6e4b637d7add0", "shasum": "" }, "require": { @@ -4660,7 +4673,7 @@ "felixfbecker/language-server-protocol": "^1.5.2", "fidry/cpu-core-counter": "^0.4.1 || ^0.5.1 || ^1.0.0", "netresearch/jsonmapper": "^1.0 || ^2.0 || ^3.0 || ^4.0", - "nikic/php-parser": "^4.16", + "nikic/php-parser": "^4.17", "php": "^7.4 || ~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0", "sebastian/diff": "^4.0 || ^5.0 || ^6.0", "spatie/array-to-xml": "^2.17.0 || ^3.0", @@ -4703,11 +4716,11 @@ "type": "project", "extra": { "branch-alias": { - "dev-master": "5.x-dev", - "dev-4.x": "4.x-dev", - "dev-3.x": "3.x-dev", + "dev-1.x": "1.x-dev", "dev-2.x": "2.x-dev", - "dev-1.x": "1.x-dev" + "dev-3.x": "3.x-dev", + "dev-4.x": "4.x-dev", + "dev-master": "5.x-dev" } }, "autoload": { @@ -4736,25 +4749,25 @@ "issues": "https://github.com/vimeo/psalm/issues", "source": "https://github.com/vimeo/psalm" }, - "time": "2024-06-16T15:08:35+00:00" + "time": "2024-09-08T18:53:08+00:00" }, { "name": "webimpress/coding-standard", - "version": "1.3.2", + "version": "1.4.0", "source": { "type": "git", "url": "https://github.com/webimpress/coding-standard.git", - "reference": "710f71ac95d36d931e76b47132b599c39abfab11" + "reference": "6f6a1a90bd9e18fc8bee0660dd1d1ce68cf9fc53" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/webimpress/coding-standard/zipball/710f71ac95d36d931e76b47132b599c39abfab11", - "reference": "710f71ac95d36d931e76b47132b599c39abfab11", + "url": "https://api.github.com/repos/webimpress/coding-standard/zipball/6f6a1a90bd9e18fc8bee0660dd1d1ce68cf9fc53", + "reference": "6f6a1a90bd9e18fc8bee0660dd1d1ce68cf9fc53", "shasum": "" }, "require": { "php": "^7.3 || ^8.0", - "squizlabs/php_codesniffer": "^3.7.2" + "squizlabs/php_codesniffer": "^3.10.3" }, "require-dev": { "phpunit/phpunit": "^9.6.15" @@ -4783,7 +4796,7 @@ ], "support": { "issues": "https://github.com/webimpress/coding-standard/issues", - "source": "https://github.com/webimpress/coding-standard/tree/1.3.2" + "source": "https://github.com/webimpress/coding-standard/tree/1.4.0" }, "funding": [ { @@ -4791,7 +4804,7 @@ "type": "github" } ], - "time": "2023-12-18T07:25:41+00:00" + "time": "2024-10-16T06:55:17+00:00" }, { "name": "webmozart/assert", @@ -4854,13 +4867,13 @@ ], "aliases": [], "minimum-stability": "stable", - "stability-flags": [], + "stability-flags": {}, "prefer-stable": false, "prefer-lowest": false, "platform": { "php": "~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0" }, - "platform-dev": [], + "platform-dev": {}, "platform-overrides": { "php": "8.1.99" }, diff --git a/vendor/laminas/laminas-validator/src/Hostname.php b/vendor/laminas/laminas-validator/src/Hostname.php index f37c3ed95..d5374e56d 100644 --- a/vendor/laminas/laminas-validator/src/Hostname.php +++ b/vendor/laminas/laminas-validator/src/Hostname.php @@ -1714,6 +1714,7 @@ class Hostname extends AbstractValidator 3 => '/^[\x{002d}0-9a-zșț]{1,63}$/iu', ], 'SJ' => [1 => '/^[\x{002d}0-9a-zàáä-éêñ-ôöøüčđńŋšŧž]{1,63}$/iu'], + 'SWISS' => [1 => '/^[\x{002d}0-9a-zà-öø-ÿœ]{1,63}$/iu'], 'TH' => [1 => '/^[\x{002d}0-9a-z\x{0E01}-\x{0E3A}\x{0E40}-\x{0E4D}\x{0E50}-\x{0E59}]{1,63}$/iu'], 'TM' => [1 => '/^[\x{002d}0-9a-zà-öø-ÿāăąćĉċčďđēėęěĝġģĥħīįĵķĺļľŀłńņňŋőœŕŗřśŝşšţťŧūŭůűųŵŷźżž]{1,63}$/iu'], 'TW' => 'Hostname/Cn.php', @@ -1969,14 +1970,6 @@ public function isValid($value) return true; } - // Handle Regex compilation failure that may happen on .biz domain with has @ character, eg: tapi4457@hsoqvf.biz - // Technically, hostname with '@' character is invalid, so mark as invalid immediately - // @see https://github.com/laminas/laminas-validator/issues/8 - if (str_contains($value, '@')) { - $this->error(self::INVALID_HOSTNAME); - return false; - } - // Local hostnames are allowed to be partial (ending '.') if ($this->getAllow() & self::ALLOW_LOCAL) { if (str_ends_with($value, '.')) { diff --git a/vendor/laminas/laminas-validator/src/Hostname/Biz.php b/vendor/laminas/laminas-validator/src/Hostname/Biz.php index f852cf1c2..a7c96de40 100644 --- a/vendor/laminas/laminas-validator/src/Hostname/Biz.php +++ b/vendor/laminas/laminas-validator/src/Hostname/Biz.php @@ -729,2169 +729,306 @@ . '\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', + . '\x{49B6}\x{49B7}\x{4C77}\x{4C9F}-\x{4CA3}\x{4D13}-\x{4D19}\x{4DAE}' + . '\x{4E00}-\x{4E11}\x{4E13}-\x{4E28}\x{4E2A}-\x{4E54}\x{4E56}-\x{4E67}' + . '\x{4E69}-\x{4E78}\x{4E7A}-\x{4E89}\x{4E8B}-\x{4E95}\x{4E97}-\x{4EA2}' + . '\x{4EA4}-\x{4EBB}\x{4EBD}-\x{4ECB}\x{4ECD}-\x{4EE6}\x{4EE8}-\x{4EEC}' + . '\x{4EEF}-\x{4EF7}\x{4EFB}\x{4EFD}\x{4EFF}-\x{4F06}\x{4F08}-\x{4F15}' + . '\x{4F17}-\x{4F27}\x{4F29}-\x{4F30}\x{4F32}-\x{4F34}\x{4F36}\x{4F38}-\x{4F3F}' + . '\x{4F41}-\x{4F43}\x{4F45}-\x{4F70}\x{4F72}-\x{4F8B}\x{4F8D}\x{4F8F}-\x{4FA1}' + . '\x{4FA3}-\x{4FAC}\x{4FAE}-\x{4FBC}\x{4FBE}-\x{4FC5}\x{4FC7}\x{4FC9}-\x{4FCB}' + . '\x{4FCD}-\x{4FE1}\x{4FE3}-\x{4FFB}\x{4FFE}-\x{500F}\x{5011}-\x{5033}' + . '\x{5035}-\x{5037}\x{5039}-\x{503C}\x{503E}-\x{5041}\x{5043}-\x{504F}\x{5051}' + . '\x{5053}-\x{5057}\x{5059}-\x{507B}\x{507D}-\x{5080}\x{5082}-\x{5092}' + . '\x{5094}-\x{5096}\x{5098}-\x{509E}\x{50A2}-\x{50B8}\x{50BA}-\x{50C2}' + . '\x{50C4}-\x{50D7}\x{50D9}-\x{50DE}\x{50E0}\x{50E3}-\x{50EA}\x{50EC}-\x{50F3}' + . '\x{50F5}\x{50F6}\x{50F8}-\x{511A}\x{511C}-\x{5127}\x{5129}\x{512A}' + . '\x{512C}-\x{5141}\x{5143}-\x{5149}\x{514B}-\x{514E}\x{5150}-\x{5152}' + . '\x{5154}-\x{5157}\x{5159}-\x{515F}\x{5161}-\x{5163}\x{5165}-\x{5171}' + . '\x{5173}-\x{517D}\x{517F}-\x{5182}\x{5185}-\x{518D}\x{518F}-\x{51A0}\x{51A2}' + . '\x{51A4}-\x{51A8}\x{51AA}-\x{51AC}\x{51AE}-\x{51B3}\x{51B5}-\x{51B7}\x{51B9}' + . '\x{51BB}-\x{51C1}\x{51C3}-\x{51D1}\x{51D4}-\x{51DE}\x{51E0}-\x{51E5}' + . '\x{51E7}-\x{51EB}\x{51ED}\x{51EF}-\x{51F1}\x{51F3}-\x{5226}\x{5228}-\x{524E}' + . '\x{5250}-\x{5252}\x{5254}-\x{5265}\x{5267}-\x{5270}\x{5272}-\x{5278}' + . '\x{527A}-\x{5284}\x{5286}-\x{528D}\x{528F}-\x{52A3}\x{52A5}-\x{52C3}\x{52C6}' + . '\x{52C7}\x{52C9}-\x{52CB}\x{52CD}\x{52CF}\x{52D0}\x{52D2}\x{52D3}' + . '\x{52D5}-\x{52E0}\x{52E2}-\x{52E4}\x{52E6}-\x{52ED}\x{52EF}-\x{5302}' + . '\x{5305}-\x{5317}\x{5319}\x{531A}\x{531C}\x{531D}\x{531F}-\x{5326}\x{5328}' + . '\x{532A}-\x{5331}\x{5333}\x{5334}\x{5337}\x{5339}-\x{5341}\x{5343}-\x{535A}' + . '\x{535C}\x{535E}-\x{5367}\x{5369}\x{536B}\x{536C}\x{536E}-\x{537F}' + . '\x{5381}-\x{53A0}\x{53A2}-\x{53A9}\x{53AC}-\x{53AE}\x{53B0}-\x{53B9}' + . '\x{53BB}-\x{53C4}\x{53C6}-\x{53CE}\x{53D0}-\x{53D9}\x{53DB}\x{53DC}' + . '\x{53DF}-\x{53E6}\x{53E8}-\x{53FE}\x{5401}-\x{5419}\x{541B}-\x{5421}' + . '\x{5423}-\x{544B}\x{544D}-\x{545C}\x{545E}-\x{5468}\x{546A}-\x{5489}' + . '\x{548B}-\x{54B4}\x{54B6}-\x{54F5}\x{54F7}-\x{5514}\x{5516}\x{5517}' + . '\x{551A}-\x{5546}\x{5548}-\x{555F}\x{5561}-\x{5579}\x{557B}-\x{55DF}' + . '\x{55E1}-\x{55F7}\x{55F9}-\x{5604}\x{5606}-\x{5609}\x{560C}-\x{561F}' + . '\x{5621}-\x{562A}\x{562C}-\x{5636}\x{5638}-\x{563B}\x{563D}-\x{5643}' + . '\x{5645}-\x{564A}\x{564C}-\x{5650}\x{5652}-\x{5655}\x{5657}-\x{565E}\x{5660}' + . '\x{5662}-\x{5674}\x{5676}-\x{567C}\x{567E}-\x{5687}\x{568A}\x{568C}-\x{5695}' + . '\x{5697}-\x{569D}\x{569F}-\x{56A1}\x{56A3}-\x{56B9}\x{56BB}-\x{56CE}' + . '\x{56D0}-\x{56D8}\x{56DA}-\x{56E5}\x{56E7}-\x{56F5}\x{56F7}\x{56F9}\x{56FA}' + . '\x{56FD}-\x{5704}\x{5706}-\x{5710}\x{5712}-\x{5716}\x{5718}-\x{5720}\x{5722}' + . '\x{5723}\x{5725}-\x{573C}\x{573E}-\x{5742}\x{5744}-\x{5747}\x{5749}-\x{5754}' + . '\x{5757}\x{5759}-\x{5762}\x{5764}-\x{576D}\x{576F}-\x{5777}\x{5779}-\x{5780}' + . '\x{5782}-\x{5786}\x{5788}-\x{5795}\x{5797}-\x{57A7}\x{57A9}-\x{57C9}' + . '\x{57CB}-\x{57D0}\x{57D2}-\x{57D6}\x{57D8}-\x{57DA}\x{57DC}\x{57DD}' + . '\x{57DF}-\x{5816}\x{5819}-\x{5840}\x{5842}-\x{584F}\x{5851}-\x{5855}' + . '\x{5857}-\x{585F}\x{5861}-\x{5865}\x{5868}-\x{5876}\x{5878}-\x{5894}' + . '\x{5896}-\x{58A9}\x{58AB}-\x{58B4}\x{58B7}-\x{58BF}\x{58C1}\x{58C2}' + . '\x{58C5}-\x{58CB}\x{58CE}\x{58CF}\x{58D1}-\x{58DB}\x{58DD}-\x{58E0}' + . '\x{58E2}-\x{58E5}\x{58E7}-\x{58F4}\x{58F6}-\x{5900}\x{5902}-\x{5904}\x{5906}' + . '\x{5907}\x{5909}-\x{5910}\x{5912}\x{5914}-\x{5922}\x{5924}-\x{5932}\x{5934}' + . '\x{5935}\x{5937}-\x{5958}\x{595A}\x{595C}-\x{599A}\x{599C}-\x{59B6}' + . '\x{59B8}-\x{59E6}\x{59E8}-\x{5A23}\x{5A25}\x{5A27}-\x{5A2B}\x{5A2D}-\x{5A2F}' + . '\x{5A31}-\x{5A53}\x{5A55}-\x{5A58}\x{5A5A}-\x{5A6E}\x{5A70}\x{5A72}-\x{5A86}' + . '\x{5A88}-\x{5A8C}\x{5A8E}-\x{5AAA}\x{5AAC}-\x{5ACF}\x{5AD1}\x{5AD2}' + . '\x{5AD4}-\x{5AEE}\x{5AF1}-\x{5B09}\x{5B0B}\x{5B0C}\x{5B0E}-\x{5B38}' + . '\x{5B3A}-\x{5B45}\x{5B47}-\x{5B4E}\x{5B50}\x{5B51}\x{5B53}-\x{5B5F}' + . '\x{5B62}-\x{5B6E}\x{5B70}-\x{5B78}\x{5B7A}-\x{5B7D}\x{5B7F}-\x{5B85}' + . '\x{5B87}-\x{5B8F}\x{5B91}-\x{5BA8}\x{5BAA}-\x{5BB1}\x{5BB3}-\x{5BB6}' + . '\x{5BB8}-\x{5BBB}\x{5BBD}-\x{5BC7}\x{5BCA}-\x{5BD6}\x{5BD8}\x{5BD9}' + . '\x{5BDB}-\x{5BFD}\x{5BFF}\x{5C01}\x{5C03}-\x{5C1A}\x{5C1C}-\x{5C22}\x{5C24}' + . '\x{5C25}\x{5C27}\x{5C28}\x{5C2A}-\x{5C35}\x{5C37}-\x{5C59}\x{5C5B}-\x{5C84}' + . '\x{5C86}-\x{5CB3}\x{5CB5}-\x{5CB8}\x{5CBA}-\x{5CBF}\x{5CC1}-\x{5CD4}' + . '\x{5CD6}-\x{5CDC}\x{5CDE}-\x{5CF4}\x{5CF6}-\x{5D2A}\x{5D2C}-\x{5D2E}' + . '\x{5D30}-\x{5D3A}\x{5D3C}-\x{5D52}\x{5D54}-\x{5D56}\x{5D58}-\x{5D5B}' + . '\x{5D5D}-\x{5D5F}\x{5D61}-\x{5D82}\x{5D84}-\x{5D95}\x{5D97}-\x{5DA2}' + . '\x{5DA5}-\x{5DAA}\x{5DAC}-\x{5DB2}\x{5DB4}-\x{5DB8}\x{5DBA}-\x{5DC3}' + . '\x{5DC5}-\x{5DD6}\x{5DD8}\x{5DD9}\x{5DDB}\x{5DDD}-\x{5DF5}\x{5DF7}-\x{5E11}' + . '\x{5E13}-\x{5E3E}\x{5E40}-\x{5E47}\x{5E49}-\x{5E50}\x{5E52}-\x{5E91}' + . '\x{5E93}-\x{5EB9}\x{5EBB}-\x{5EBF}\x{5EC1}-\x{5EEA}\x{5EEC}-\x{5EF8}' + . '\x{5EFA}-\x{5F08}\x{5F0A}-\x{5F0D}\x{5F0F}\x{5F11}-\x{5F3A}\x{5F3C}' + . '\x{5F3E}-\x{5F8E}\x{5F90}-\x{5F99}\x{5F9B}-\x{5FA2}\x{5FA5}-\x{5FAF}' + . '\x{5FB1}-\x{5FC1}\x{5FC3}-\x{5FCD}\x{5FCF}-\x{5FDA}\x{5FDC}-\x{5FDE}\x{5FE0}' + . '\x{5FE1}\x{5FE3}-\x{5FEB}\x{5FED}-\x{5FFB}\x{5FFD}-\x{6022}\x{6024}-\x{6055}' + . '\x{6057}-\x{605F}\x{6062}-\x{6070}\x{6072}\x{6073}\x{6075}-\x{6090}\x{6092}' + . '\x{6094}-\x{60A4}\x{60A6}-\x{60A8}\x{60AA}-\x{60D1}\x{60D3}-\x{60D5}' + . '\x{60D7}-\x{60DD}\x{60DF}-\x{60E2}\x{60E4}\x{60E6}-\x{60FC}\x{60FE}-\x{6101}' + . '\x{6103}-\x{6106}\x{6108}-\x{6110}\x{6112}-\x{611D}\x{611F}\x{6120}' + . '\x{6122}-\x{6130}\x{6132}\x{6134}\x{6136}\x{6137}\x{613A}-\x{615F}' + . '\x{6161}-\x{616E}\x{6170}-\x{617A}\x{617C}\x{617E}\x{6180}-\x{6185}' + . '\x{6187}-\x{6196}\x{6198}-\x{619B}\x{619D}-\x{61B8}\x{61BA}\x{61BC}-\x{61D2}' + . '\x{61D4}\x{61D6}-\x{61EB}\x{61ED}\x{61EE}\x{61F0}-\x{61F3}\x{61F5}-\x{6204}' + . '\x{6206}-\x{6234}\x{6236}-\x{6238}\x{623A}-\x{6256}\x{6258}-\x{6281}' + . '\x{6283}-\x{628C}\x{628E}-\x{629C}\x{629E}-\x{62A5}\x{62A7}-\x{62DD}' + . '\x{62DF}-\x{62E9}\x{62EB}-\x{6309}\x{630B}-\x{6316}\x{6318}-\x{6330}' + . '\x{6332}-\x{6334}\x{6336}\x{6338}-\x{633E}\x{6340}-\x{635A}\x{635C}-\x{637E}' + . '\x{6380}-\x{638A}\x{638C}-\x{6392}\x{6394}-\x{63BA}\x{63BC}-\x{63D0}' + . '\x{63D2}-\x{6406}\x{6408}-\x{643A}\x{643D}-\x{6441}\x{6443}-\x{6448}' + . '\x{644A}-\x{6459}\x{645B}-\x{647D}\x{647F}-\x{6485}\x{6487}-\x{64A0}' + . '\x{64A2}-\x{64AE}\x{64B0}-\x{64B5}\x{64B7}-\x{64C7}\x{64C9}-\x{64D4}' + . '\x{64D6}-\x{64E0}\x{64E2}-\x{64E4}\x{64E6}-\x{64ED}\x{64EF}-\x{64F4}' + . '\x{64F6}-\x{64F8}\x{64FA}-\x{6501}\x{6503}-\x{6509}\x{650B}-\x{651E}' + . '\x{6520}-\x{6527}\x{6529}-\x{653F}\x{6541}\x{6543}-\x{6559}\x{655B}-\x{655E}' + . '\x{6560}-\x{656C}\x{656E}-\x{657C}\x{657E}-\x{6589}\x{658B}-\x{6599}' + . '\x{659B}-\x{65B4}\x{65B6}-\x{65BD}\x{65BF}-\x{65C7}\x{65CA}-\x{65D0}' + . '\x{65D2}-\x{65D7}\x{65DA}\x{65DB}\x{65DD}-\x{65E3}\x{65E5}-\x{65E9}' + . '\x{65EB}-\x{65F8}\x{65FA}-\x{65FD}\x{6600}-\x{6616}\x{6618}-\x{661D}' + . '\x{661F}-\x{662B}\x{662D}-\x{6636}\x{6639}\x{663A}\x{663C}-\x{663E}' + . '\x{6640}-\x{6647}\x{6649}-\x{664C}\x{664E}-\x{665F}\x{6661}\x{6662}' + . '\x{6664}-\x{6666}\x{6668}-\x{6691}\x{6693}-\x{669B}\x{669D}\x{669F}-\x{66AB}' + . '\x{66AE}-\x{66CF}\x{66D1}\x{66D2}\x{66D4}-\x{66D6}\x{66D8}-\x{66DE}' + . '\x{66E0}-\x{66EE}\x{66F0}-\x{66FC}\x{66FE}-\x{6701}\x{6703}-\x{6706}' + . '\x{6708}-\x{6718}\x{671A}-\x{6723}\x{6725}-\x{6728}\x{672A}-\x{6766}' + . '\x{6768}-\x{6787}\x{6789}-\x{6795}\x{6797}-\x{67A8}\x{67AA}-\x{67BC}\x{67BE}' + . '\x{67C0}-\x{67D4}\x{67D6}\x{67D8}-\x{67F8}\x{67FA}-\x{6800}\x{6802}-\x{6814}' + . '\x{6816}-\x{681D}\x{681F}-\x{6826}\x{6828}-\x{682F}\x{6831}-\x{6857}\x{685B}' + . '\x{685D}\x{6860}-\x{6879}\x{687B}-\x{6894}\x{6896}-\x{6898}\x{689A}-\x{68A4}' + . '\x{68A6}-\x{68B7}\x{68B9}\x{68BB}-\x{68C2}\x{68C4}\x{68C6}-\x{68D8}' + . '\x{68DA}-\x{68E1}\x{68E3}\x{68E4}\x{68E6}-\x{68FF}\x{6901}-\x{6908}' + . '\x{690A}-\x{693D}\x{693F}-\x{694C}\x{694E}-\x{699E}\x{69A0}\x{69A1}' + . '\x{69A3}-\x{69BF}\x{69C1}-\x{69D0}\x{69D3}\x{69D4}\x{69D8}-\x{69F8}' + . '\x{69FA}-\x{6A02}\x{6A04}-\x{6A0B}\x{6A0D}-\x{6A1B}\x{6A1D}-\x{6A23}' + . '\x{6A25}-\x{6A36}\x{6A38}-\x{6A49}\x{6A4B}-\x{6A52}\x{6A54}-\x{6A5B}' + . '\x{6A5D}-\x{6A6D}\x{6A6F}\x{6A71}-\x{6A85}\x{6A87}-\x{6A89}\x{6A8B}-\x{6A8E}' + . '\x{6A90}-\x{6A98}\x{6A9A}-\x{6A9C}\x{6A9E}-\x{6AA9}\x{6AAB}-\x{6AB0}' + . '\x{6AB2}-\x{6ABD}\x{6ABF}\x{6AC1}-\x{6AC3}\x{6AC5}-\x{6AC7}\x{6ACA}-\x{6AD7}' + . '\x{6AD9}-\x{6AE8}\x{6AEA}-\x{6B0D}\x{6B0F}-\x{6B1A}\x{6B1C}-\x{6B2D}' + . '\x{6B2F}-\x{6B34}\x{6B36}-\x{6B3F}\x{6B41}-\x{6B56}\x{6B59}-\x{6B5C}' + . '\x{6B5E}-\x{6B67}\x{6B69}-\x{6B6B}\x{6B6D}\x{6B6F}\x{6B70}\x{6B72}-\x{6B74}' + . '\x{6B76}-\x{6B7C}\x{6B7E}-\x{6BB0}\x{6BB2}-\x{6BB7}\x{6BB9}-\x{6BE8}' + . '\x{6BEA}-\x{6BF0}\x{6BF2}\x{6BF3}\x{6BF5}-\x{6BF9}\x{6BFB}-\x{6C09}' + . '\x{6C0B}-\x{6C16}\x{6C18}-\x{6C1B}\x{6C1D}-\x{6C2C}\x{6C2E}-\x{6C38}\x{6C3A}' + . '\x{6C3B}\x{6C3D}-\x{6C44}\x{6C46}-\x{6C6B}\x{6C6D}\x{6C6F}-\x{6C9F}' + . '\x{6CA1}-\x{6CD7}\x{6CD9}-\x{6CF3}\x{6CF5}-\x{6D01}\x{6D03}-\x{6D1B}' + . '\x{6D1D}-\x{6D23}\x{6D25}-\x{6D70}\x{6D72}-\x{6D80}\x{6D82}-\x{6D95}' + . '\x{6D97}-\x{6D9B}\x{6D9D}-\x{6DAF}\x{6DB2}-\x{6DB5}\x{6DB7}-\x{6DFD}\x{6E00}' + . '\x{6E03}-\x{6E05}\x{6E07}-\x{6E11}\x{6E14}-\x{6E17}\x{6E19}-\x{6E29}' + . '\x{6E2B}-\x{6E4B}\x{6E4D}-\x{6E6B}\x{6E6D}-\x{6E75}\x{6E77}-\x{6E79}' + . '\x{6E7E}-\x{6E8A}\x{6E8D}-\x{6E94}\x{6E96}-\x{6EDA}\x{6EDC}\x{6EDE}-\x{6EE2}' + . '\x{6EE4}-\x{6F03}\x{6F05}-\x{6F0A}\x{6F0C}-\x{6F41}\x{6F43}-\x{6F47}\x{6F49}' + . '\x{6F4B}-\x{6F78}\x{6F7A}-\x{6F97}\x{6F99}\x{6F9B}-\x{6F9E}\x{6FA0}-\x{6FB6}' + . '\x{6FB8}-\x{6FC4}\x{6FC6}-\x{6FCF}\x{6FD1}\x{6FD2}\x{6FD4}-\x{6FF4}' + . '\x{6FF6}-\x{6FFC}\x{6FFE}-\x{700F}\x{7011}\x{7012}\x{7014}-\x{701D}' + . '\x{701F}-\x{7046}\x{7048}-\x{704A}\x{704C}\x{704D}\x{704F}-\x{7071}' + . '\x{7074}-\x{707A}\x{707C}-\x{7080}\x{7082}-\x{708C}\x{708E}-\x{7096}' + . '\x{7098}-\x{709A}\x{709C}-\x{70A9}\x{70AB}-\x{70B1}\x{70B3}-\x{70B5}' + . '\x{70B7}-\x{70D4}\x{70D6}-\x{70FD}\x{70FF}-\x{7107}\x{7109}-\x{7113}' + . '\x{7115}-\x{7123}\x{7125}-\x{7132}\x{7135}-\x{713B}\x{713D}-\x{7154}\x{7156}' + . '\x{7158}-\x{716A}\x{716C}\x{716E}-\x{718C}\x{718E}-\x{7195}\x{7197}-\x{71A5}' + . '\x{71A7}-\x{71AA}\x{71AC}-\x{71B5}\x{71B7}-\x{71CB}\x{71CD}-\x{71D2}' + . '\x{71D4}-\x{71F2}\x{71F4}-\x{71F9}\x{71FB}-\x{71FF}\x{7201}-\x{720A}' + . '\x{720C}-\x{7210}\x{7212}-\x{7214}\x{7216}\x{7218}-\x{721F}\x{7221}-\x{7223}' + . '\x{7226}-\x{722E}\x{7230}-\x{7233}\x{7235}-\x{7244}\x{7246}-\x{724D}\x{724F}' + . '\x{7251}-\x{7254}\x{7256}-\x{729F}\x{72A1}-\x{72AA}\x{72AC}-\x{72BD}' + . '\x{72BF}-\x{7301}\x{7303}-\x{730F}\x{7311}-\x{731E}\x{7320}-\x{7327}' + . '\x{7329}-\x{732E}\x{7330}-\x{734E}\x{7350}-\x{7352}\x{7354}-\x{7362}' + . '\x{7364}-\x{739B}\x{739D}-\x{73C0}\x{73C2}-\x{73E0}\x{73E2}\x{73E3}' + . '\x{73E5}-\x{73F2}\x{73F4}-\x{73FA}\x{73FC}-\x{7417}\x{7419}-\x{7438}' + . '\x{743A}-\x{743D}\x{743F}-\x{7446}\x{7448}\x{744A}-\x{7457}\x{7459}-\x{745F}' + . '\x{7461}-\x{747A}\x{747C}-\x{7483}\x{7485}-\x{7495}\x{7497}-\x{749C}' + . '\x{749E}-\x{74A1}\x{74A3}-\x{74C6}\x{74CA}\x{74CB}\x{74CD}-\x{74EA}' + . '\x{74EC}-\x{750D}\x{750F}-\x{751F}\x{7521}-\x{7533}\x{7535}-\x{7540}' + . '\x{7542}-\x{7549}\x{754B}-\x{7551}\x{7553}\x{7554}\x{7556}-\x{755D}\x{755F}' + . '\x{7560}\x{7562}-\x{7570}\x{7572}\x{7574}-\x{7579}\x{757C}-\x{7584}' + . '\x{7586}-\x{758D}\x{758F}-\x{75A8}\x{75AA}-\x{75B6}\x{75B8}-\x{75DB}' + . '\x{75DD}-\x{75E8}\x{75EA}-\x{75ED}\x{75EF}-\x{762B}\x{762D}-\x{7643}' + . '\x{7646}-\x{764D}\x{764F}\x{7650}\x{7652}-\x{7654}\x{7656}-\x{7672}' + . '\x{7674}-\x{7679}\x{767B}-\x{768C}\x{768E}-\x{76A0}\x{76A3}\x{76A4}\x{76A6}' + . '\x{76A7}\x{76A9}-\x{76B2}\x{76B4}\x{76B5}\x{76B7}\x{76B8}\x{76BA}-\x{76C0}' + . '\x{76C2}-\x{76CA}\x{76CD}-\x{76D8}\x{76DA}-\x{76EA}\x{76EC}-\x{76FF}\x{7701}' + . '\x{7703}-\x{770D}\x{770F}-\x{7720}\x{7722}\x{7723}\x{7725}-\x{772A}' + . '\x{772C}-\x{773E}\x{7740}\x{7741}\x{7743}-\x{7763}\x{7765}-\x{7795}' + . '\x{7797}-\x{77A3}\x{77A5}-\x{77BD}\x{77BF}\x{77C0}\x{77C2}-\x{77D1}' + . '\x{77D3}-\x{77DC}\x{77DE}-\x{77E3}\x{77E5}\x{77E7}-\x{77F3}\x{77F6}-\x{7806}' + . '\x{7808}-\x{7823}\x{7825}-\x{7835}\x{7837}-\x{783E}\x{7840}\x{7841}' + . '\x{7843}-\x{7845}\x{7847}-\x{784A}\x{784C}-\x{784E}\x{7850}-\x{7875}' + . '\x{7877}-\x{7887}\x{7889}-\x{78C1}\x{78C3}-\x{78C6}\x{78C8}-\x{78D1}' + . '\x{78D3}-\x{78EF}\x{78F1}-\x{78F7}\x{78F9}-\x{78FF}\x{7901}-\x{7907}' + . '\x{7909}-\x{790C}\x{790E}-\x{7914}\x{7916}-\x{791E}\x{7921}-\x{7931}' + . '\x{7933}-\x{7935}\x{7937}-\x{7958}\x{795A}-\x{796B}\x{796D}\x{796F}-\x{7974}' + . '\x{7977}-\x{7985}\x{7988}-\x{799C}\x{799F}-\x{79A8}\x{79AA}-\x{79BB}' + . '\x{79BD}-\x{79C3}\x{79C5}\x{79C6}\x{79C8}-\x{79CB}\x{79CD}-\x{79D3}\x{79D5}' + . '\x{79D6}\x{79D8}-\x{7A00}\x{7A02}-\x{7A06}\x{7A08}\x{7A0A}-\x{7A2B}' + . '\x{7A2D}-\x{7A35}\x{7A37}\x{7A39}\x{7A3B}-\x{7A4E}\x{7A50}-\x{7A62}' + . '\x{7A65}-\x{7A69}\x{7A6B}-\x{7A6E}\x{7A70}-\x{7A81}\x{7A83}-\x{7A99}' + . '\x{7A9C}-\x{7AB8}\x{7ABA}\x{7ABE}-\x{7AC1}\x{7AC4}\x{7AC5}\x{7AC7}-\x{7AD6}' + . '\x{7AD8}\x{7AD9}\x{7ADB}-\x{7AE8}\x{7AEA}-\x{7AF4}\x{7AF6}-\x{7AFB}' + . '\x{7AFD}-\x{7B06}\x{7B08}-\x{7B1E}\x{7B20}-\x{7B26}\x{7B28}\x{7B2A}-\x{7B41}' + . '\x{7B43}-\x{7B52}\x{7B54}-\x{7B6E}\x{7B70}-\x{7B79}\x{7B7B}-\x{7B85}' + . '\x{7B87}-\x{7B91}\x{7B93}-\x{7BA2}\x{7BA4}\x{7BA6}-\x{7BAF}\x{7BB1}' + . '\x{7BB3}-\x{7BCE}\x{7BD0}-\x{7BF9}\x{7BFB}-\x{7C13}\x{7C15}-\x{7C1A}' + . '\x{7C1C}-\x{7C2D}\x{7C30}-\x{7C4E}\x{7C50}\x{7C51}\x{7C53}\x{7C54}' + . '\x{7C56}-\x{7C5C}\x{7C5E}-\x{7C75}\x{7C77}-\x{7C82}\x{7C84}-\x{7C86}' + . '\x{7C88}-\x{7C92}\x{7C94}-\x{7C99}\x{7C9B}-\x{7CAA}\x{7CAD}-\x{7CD2}' + . '\x{7CD4}-\x{7CD9}\x{7CDC}-\x{7CE0}\x{7CE2}\x{7CE4}\x{7CE7}-\x{7CFB}\x{7CFD}' + . '\x{7CFE}\x{7D00}-\x{7D22}\x{7D24}-\x{7D29}\x{7D2B}\x{7D2C}\x{7D2E}-\x{7D47}' + . '\x{7D49}-\x{7D4C}\x{7D4E}-\x{7D59}\x{7D5B}-\x{7D63}\x{7D65}-\x{7D77}' + . '\x{7D79}-\x{7D81}\x{7D83}-\x{7D94}\x{7D96}\x{7D97}\x{7D99}\x{7D9B}-\x{7DA3}' + . '\x{7DA5}-\x{7DA7}\x{7DA9}-\x{7DCC}\x{7DCE}-\x{7DD2}\x{7DD4}-\x{7DDB}' + . '\x{7DDD}-\x{7DE3}\x{7DE6}-\x{7DEA}\x{7DEC}-\x{7DFC}\x{7E00}-\x{7E17}' + . '\x{7E19}-\x{7E49}\x{7E4C}-\x{7E5A}\x{7E5C}-\x{7E63}\x{7E65}-\x{7E9C}' + . '\x{7E9E}-\x{7F3A}\x{7F3D}-\x{7F40}\x{7F42}-\x{7F45}\x{7F47}-\x{7F58}' + . '\x{7F5A}-\x{7F83}\x{7F85}-\x{7F8F}\x{7F91}-\x{7F96}\x{7F98}\x{7F9A}-\x{7FB3}' + . '\x{7FB5}-\x{7FD5}\x{7FD7}-\x{7FDC}\x{7FDE}-\x{7FE3}\x{7FE5}-\x{8009}' + . '\x{800B}-\x{802E}\x{8030}-\x{803B}\x{803D}-\x{803F}\x{8041}-\x{8065}' + . '\x{8067}-\x{8087}\x{8089}-\x{808D}\x{808F}-\x{8093}\x{8095}-\x{80A5}' + . '\x{80A9}-\x{80AB}\x{80AD}-\x{80B2}\x{80B4}-\x{80B8}\x{80BA}-\x{80DE}' + . '\x{80E0}-\x{8102}\x{8105}-\x{8116}\x{8118}-\x{8132}\x{8136}-\x{815E}' + . '\x{8160}-\x{8183}\x{8185}-\x{818F}\x{8191}-\x{8195}\x{8197}-\x{81CA}' + . '\x{81CC}-\x{81D2}\x{81D4}-\x{81E3}\x{81E5}-\x{81EE}\x{81F1}-\x{8212}' + . '\x{8214}-\x{8216}\x{8218}-\x{8223}\x{8225}-\x{822D}\x{822F}-\x{8240}' + . '\x{8242}-\x{8261}\x{8263}\x{8264}\x{8266}-\x{828B}\x{828D}-\x{82B1}' + . '\x{82B3}-\x{82E1}\x{82E3}-\x{82FB}\x{82FD}-\x{8309}\x{830B}-\x{830F}' + . '\x{8311}-\x{832F}\x{8331}-\x{8354}\x{8356}-\x{839E}\x{83A0}-\x{83B4}' + . '\x{83B6}-\x{83BD}\x{83BF}-\x{83E5}\x{83E7}-\x{83EC}\x{83EE}-\x{8413}\x{8415}' + . '\x{8418}-\x{841E}\x{8421}-\x{8457}\x{8459}-\x{8482}\x{8484}-\x{8494}' + . '\x{8496}-\x{84AC}\x{84AE}-\x{84B6}\x{84B8}-\x{84C2}\x{84C4}-\x{84D9}' + . '\x{84DB}-\x{84EC}\x{84EE}-\x{8504}\x{8506}-\x{850F}\x{8511}-\x{8531}' + . '\x{8534}-\x{854B}\x{854D}-\x{854F}\x{8551}-\x{857E}\x{8580}-\x{8592}' + . '\x{8594}-\x{8596}\x{8598}-\x{85B1}\x{85B3}-\x{85BA}\x{85BC}-\x{85CB}' + . '\x{85CD}-\x{85ED}\x{85EF}-\x{85F2}\x{85F4}-\x{85FB}\x{85FD}-\x{8602}' + . '\x{8604}-\x{860C}\x{860F}\x{8611}-\x{8614}\x{8616}-\x{861C}\x{861E}-\x{8636}' + . '\x{8638}-\x{8656}\x{8658}-\x{8674}\x{8676}-\x{8688}\x{868A}-\x{8691}' + . '\x{8693}-\x{869F}\x{86A1}-\x{86A5}\x{86A7}-\x{86CC}\x{86CE}-\x{86D4}' + . '\x{86D6}-\x{86DF}\x{86E1}-\x{86E6}\x{86E8}-\x{86FC}\x{86FE}-\x{871C}' + . '\x{871E}-\x{872E}\x{8730}-\x{873C}\x{873E}-\x{8744}\x{8746}-\x{874A}' + . '\x{874C}-\x{8770}\x{8772}-\x{877E}\x{8780}-\x{878D}\x{878F}-\x{8798}' + . '\x{879A}-\x{87D9}\x{87DB}-\x{87EF}\x{87F1}-\x{8806}\x{8808}-\x{8811}' + . '\x{8813}-\x{882C}\x{882E}-\x{8839}\x{883B}-\x{8846}\x{8848}-\x{8857}' + . '\x{8859}-\x{885B}\x{885D}\x{885E}\x{8860}-\x{8879}\x{887B}-\x{88B4}' + . '\x{88B6}-\x{88E5}\x{88E7}\x{88E8}\x{88EA}-\x{88EC}\x{88EE}-\x{8902}' + . '\x{8904}-\x{890E}\x{8910}-\x{8923}\x{8925}-\x{894C}\x{894E}-\x{8964}' + . '\x{8966}-\x{8974}\x{8976}-\x{897C}\x{897E}-\x{898C}\x{898E}\x{898F}' + . '\x{8991}-\x{8993}\x{8995}-\x{8998}\x{899A}-\x{89A8}\x{89AA}-\x{89AF}' + . '\x{89B1}-\x{89B3}\x{89B5}-\x{89BA}\x{89BD}-\x{89ED}\x{89EF}-\x{89F4}' + . '\x{89F6}-\x{89F8}\x{89FA}-\x{89FC}\x{89FE}-\x{8A04}\x{8A07}-\x{8A13}' + . '\x{8A15}-\x{8A18}\x{8A1A}-\x{8A1F}\x{8A22}-\x{8A2A}\x{8A2C}-\x{8A32}' + . '\x{8A34}-\x{8A3C}\x{8A3E}-\x{8A4A}\x{8A4C}-\x{8A63}\x{8A65}-\x{8A77}' + . '\x{8A79}-\x{8A7C}\x{8A7E}-\x{8A87}\x{8A89}-\x{8A9E}\x{8AA0}-\x{8AAC}\x{8AAE}' + . '\x{8AB0}-\x{8AB6}\x{8AB8}-\x{8ACF}\x{8AD1}-\x{8AEB}\x{8AED}-\x{8B0B}' + . '\x{8B0D}-\x{8B28}\x{8B2A}-\x{8B31}\x{8B33}-\x{8B37}\x{8B39}-\x{8B3E}' + . '\x{8B40}-\x{8B60}\x{8B63}-\x{8B68}\x{8B6A}-\x{8B71}\x{8B73}\x{8B74}' + . '\x{8B76}-\x{8B7B}\x{8B7D}-\x{8B80}\x{8B82}-\x{8B86}\x{8B88}-\x{8B8C}\x{8B8E}' + . '\x{8B90}-\x{8B9A}\x{8B9C}-\x{8C37}\x{8C39}-\x{8C3F}\x{8C41}-\x{8C43}' + . '\x{8C45}-\x{8C50}\x{8C54}-\x{8C57}\x{8C59}-\x{8C73}\x{8C75}-\x{8C7B}\x{8C7D}' + . '\x{8C7E}\x{8C80}-\x{8C82}\x{8C84}-\x{8C86}\x{8C88}-\x{8C8A}\x{8C8C}\x{8C8D}' + . '\x{8C8F}-\x{8C9A}\x{8C9C}-\x{8CA5}\x{8CA7}-\x{8CCA}\x{8CCC}\x{8CCE}-\x{8CD5}' + . '\x{8CD7}\x{8CD9}-\x{8CE8}\x{8CEA}-\x{8CF6}\x{8CF8}-\x{8D00}\x{8D02}-\x{8D10}' + . '\x{8D13}-\x{8D7B}\x{8D7D}-\x{8DA5}\x{8DA7}-\x{8DBF}\x{8DC1}-\x{8DE4}' + . '\x{8DE6}-\x{8E00}\x{8E02}-\x{8E0A}\x{8E0C}-\x{8E31}\x{8E33}-\x{8E45}' + . '\x{8E47}-\x{8E4E}\x{8E50}-\x{8E6D}\x{8E6F}-\x{8E74}\x{8E76}\x{8E78}' + . '\x{8E7A}-\x{8E98}\x{8E9A}\x{8E9C}-\x{8EA1}\x{8EA3}-\x{8EB2}\x{8EB4}\x{8EB5}' + . '\x{8EB8}-\x{8EC0}\x{8EC2}\x{8EC3}\x{8EC5}-\x{8ED8}\x{8EDA}-\x{8EE1}' + . '\x{8EE4}-\x{8EEF}\x{8EF1}-\x{8F0B}\x{8F0D}\x{8F0E}\x{8F10}-\x{8F18}' + . '\x{8F1A}-\x{8F2C}\x{8F2E}-\x{8F39}\x{8F3B}-\x{8F40}\x{8F42}-\x{8F5B}' + . '\x{8F5D}-\x{8F9C}\x{8F9E}-\x{8FA3}\x{8FA5}-\x{8FB2}\x{8FB4}-\x{8FB9}' + . '\x{8FBB}-\x{8FC2}\x{8FC4}-\x{8FC9}\x{8FCB}-\x{8FE6}\x{8FE8}-\x{900D}' + . '\x{900F}-\x{9029}\x{902B}\x{902D}-\x{9036}\x{9038}\x{903A}-\x{903F}' + . '\x{9041}-\x{9045}\x{9047}-\x{90AA}\x{90AC}-\x{90CB}\x{90CE}-\x{90D1}' + . '\x{90D3}-\x{90F5}\x{90F7}-\x{9109}\x{910B}-\x{913B}\x{913E}-\x{9158}' + . '\x{915A}-\x{917A}\x{917C}-\x{9194}\x{9196}\x{9199}-\x{91A3}\x{91A5}-\x{91A8}' + . '\x{91AA}-\x{91B7}\x{91B9}-\x{91BE}\x{91C0}-\x{91C3}\x{91C5}-\x{91C7}' + . '\x{91C9}-\x{91D5}\x{91D7}-\x{91DF}\x{91E2}-\x{91EE}\x{91F0}-\x{91F5}' + . '\x{91F7}-\x{91FB}\x{91FD}-\x{9212}\x{9214}-\x{921E}\x{9220}\x{9221}' + . '\x{9223}-\x{922B}\x{922D}-\x{9242}\x{9245}-\x{9268}\x{926B}-\x{9270}' + . '\x{9272}-\x{9280}\x{9282}\x{9283}\x{9285}-\x{929D}\x{929F}-\x{92BC}' + . '\x{92BE}-\x{92D3}\x{92D5}-\x{92DA}\x{92DC}-\x{92E1}\x{92E3}-\x{931B}' + . '\x{931D}-\x{932B}\x{932D}-\x{932F}\x{9332}-\x{9361}\x{9363}-\x{9367}\x{9369}' + . '\x{936A}\x{936C}-\x{936E}\x{9370}-\x{9372}\x{9374}-\x{9377}\x{9379}-\x{937E}' + . '\x{9380}\x{9382}-\x{938A}\x{938C}-\x{939B}\x{939D}-\x{939F}\x{93A1}-\x{93AA}' + . '\x{93AC}-\x{93BA}\x{93BC}-\x{93DF}\x{93E1}-\x{93E4}\x{93E6}-\x{93F2}' + . '\x{93F4}-\x{9401}\x{9403}-\x{9416}\x{9418}\x{9419}\x{941B}\x{941D}\x{9420}' + . '\x{9422}\x{9423}\x{9425}-\x{9442}\x{9444}-\x{944D}\x{944F}-\x{9459}' + . '\x{945B}-\x{946B}\x{946D}-\x{947A}\x{947C}-\x{9577}\x{957A}-\x{957D}' + . '\x{957F}-\x{9584}\x{9586}-\x{9596}\x{9598}-\x{959F}\x{95A1}-\x{95B2}' + . '\x{95B5}-\x{95B7}\x{95B9}-\x{95C0}\x{95C2}-\x{95D8}\x{95DA}-\x{95DC}' + . '\x{95DE}-\x{9624}\x{9627}\x{9628}\x{962A}-\x{963D}\x{963F}-\x{9655}' + . '\x{9658}-\x{9664}\x{9666}-\x{9678}\x{967C}-\x{967E}\x{9680}\x{9683}-\x{968B}' + . '\x{968D}-\x{9695}\x{9697}-\x{9699}\x{969B}\x{969C}\x{969E}\x{96A0}-\x{96AA}' + . '\x{96AC}-\x{96AE}\x{96B0}\x{96B1}\x{96B3}\x{96B4}\x{96B6}-\x{96E3}\x{96E5}' + . '\x{96E8}-\x{96FB}\x{96FD}-\x{9713}\x{9715}\x{9716}\x{9718}\x{9719}' + . '\x{971C}-\x{9732}\x{9735}\x{9736}\x{9738}-\x{973F}\x{9742}-\x{974C}' + . '\x{974E}-\x{9756}\x{9758}-\x{9762}\x{9765}-\x{9770}\x{9772}-\x{9774}' + . '\x{9776}-\x{9786}\x{9788}\x{978A}-\x{979A}\x{979C}-\x{97A8}\x{97AA}-\x{97AF}' + . '\x{97B2}-\x{97B4}\x{97B6}-\x{97BD}\x{97BF}\x{97C1}-\x{97D1}\x{97D3}-\x{97FB}' + . '\x{97FD}-\x{981E}\x{9820}-\x{9824}\x{9826}-\x{9829}\x{982B}\x{982D}-\x{9832}' + . '\x{9834}-\x{9839}\x{983B}-\x{983D}\x{983F}-\x{9841}\x{9843}-\x{9846}' + . '\x{9848}-\x{984A}\x{984C}-\x{9855}\x{9857}-\x{9865}\x{9867}\x{9869}-\x{98B6}' + . '\x{98B8}-\x{98C6}\x{98C8}\x{98C9}\x{98CB}-\x{98E0}\x{98E2}\x{98E3}' + . '\x{98E5}-\x{98EB}\x{98ED}\x{98EF}\x{98F0}\x{98F2}-\x{98F7}\x{98F9}\x{98FA}' + . '\x{98FC}-\x{9918}\x{991A}-\x{993A}\x{993C}-\x{9943}\x{9945}-\x{994C}' + . '\x{994E}-\x{9959}\x{995B}\x{995C}\x{995E}-\x{99BE}\x{99C0}-\x{99C4}' + . '\x{99C6}-\x{99DF}\x{99E1}-\x{99E5}\x{99E7}-\x{99EA}\x{99EC}-\x{99F4}' + . '\x{99F6}-\x{9A0F}\x{9A11}\x{9A14}-\x{9A16}\x{9A19}-\x{9A27}\x{9A29}-\x{9A3A}' + . '\x{9A3C}-\x{9A50}\x{9A52}-\x{9A57}\x{9A59}-\x{9A5C}\x{9A5E}-\x{9A62}' + . '\x{9A64}-\x{9AA8}\x{9AAA}-\x{9ABC}\x{9ABE}-\x{9AC7}\x{9AC9}-\x{9AD6}' + . '\x{9AD8}-\x{9ADF}\x{9AE1}-\x{9AE3}\x{9AE5}-\x{9AE7}\x{9AEA}-\x{9AEF}' + . '\x{9AF1}-\x{9AFF}\x{9B01}\x{9B03}-\x{9B08}\x{9B0A}-\x{9B13}\x{9B15}-\x{9B1A}' + . '\x{9B1C}-\x{9B33}\x{9B35}-\x{9B3C}\x{9B3E}\x{9B3F}\x{9B41}-\x{9B4F}' + . '\x{9B51}-\x{9B56}\x{9B58}-\x{9B61}\x{9B63}-\x{9B71}\x{9B73}-\x{9B88}\x{9B8A}' + . '\x{9B8B}\x{9B8D}-\x{9B98}\x{9B9A}-\x{9BC1}\x{9BC3}-\x{9BF5}\x{9BF7}-\x{9BFF}' + . '\x{9C02}\x{9C05}-\x{9C2D}\x{9C2F}-\x{9C41}\x{9C43}-\x{9C4E}\x{9C50}' + . '\x{9C52}-\x{9C60}\x{9C62}\x{9C63}\x{9C65}-\x{9C75}\x{9C77}-\x{9C7A}' + . '\x{9C7C}-\x{9D0B}\x{9D0F}\x{9D10}\x{9D12}-\x{9D26}\x{9D28}\x{9D29}\x{9D2B}' + . '\x{9D2D}-\x{9D34}\x{9D36}-\x{9D3B}\x{9D3D}-\x{9D43}\x{9D45}-\x{9D6C}' + . '\x{9D6E}-\x{9D8E}\x{9D90}-\x{9D94}\x{9D96}-\x{9DAD}\x{9DAF}-\x{9DBC}\x{9DBE}' + . '\x{9DBF}\x{9DC1}-\x{9DC5}\x{9DC7}-\x{9DE9}\x{9DEB}-\x{9DFB}\x{9DFD}-\x{9E0D}' + . '\x{9E0F}-\x{9E15}\x{9E17}-\x{9E1B}\x{9E1D}-\x{9E77}\x{9E79}\x{9E7A}' + . '\x{9E7C}-\x{9E8E}\x{9E91}-\x{9E94}\x{9E96}\x{9E97}\x{9E99}-\x{9E9D}' + . '\x{9E9F}-\x{9EA1}\x{9EA3}-\x{9EAA}\x{9EAD}-\x{9EB0}\x{9EB2}-\x{9EB8}' + . '\x{9EBB}-\x{9EEB}\x{9EED}-\x{9EF0}\x{9EF2}-\x{9F02}\x{9F04}-\x{9F10}\x{9F12}' + . '\x{9F13}\x{9F15}-\x{9F20}\x{9F22}-\x{9F25}\x{9F27}-\x{9F44}\x{9F46}-\x{9F52}' + . '\x{9F54}-\x{9F61}\x{9F63}-\x{9F6C}\x{9F6E}-\x{9FA0}\x{9FA2}\x{9FA4}\x{9FA5}]{1,20}$/iu', ]; diff --git a/vendor/laminas/laminas-validator/src/Hostname/Cn.php b/vendor/laminas/laminas-validator/src/Hostname/Cn.php index d280764b0..25e4eaafa 100644 --- a/vendor/laminas/laminas-validator/src/Hostname/Cn.php +++ b/vendor/laminas/laminas-validator/src/Hostname/Cn.php @@ -11,2169 +11,306 @@ . '\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', + . '\x{49B6}\x{49B7}\x{4C77}\x{4C9F}-\x{4CA3}\x{4D13}-\x{4D19}\x{4DAE}' + . '\x{4E00}-\x{4E11}\x{4E13}-\x{4E28}\x{4E2A}-\x{4E54}\x{4E56}-\x{4E67}' + . '\x{4E69}-\x{4E78}\x{4E7A}-\x{4E89}\x{4E8B}-\x{4E95}\x{4E97}-\x{4EA2}' + . '\x{4EA4}-\x{4EBB}\x{4EBD}-\x{4ECB}\x{4ECD}-\x{4EE6}\x{4EE8}-\x{4EEC}' + . '\x{4EEF}-\x{4EF7}\x{4EFB}\x{4EFD}\x{4EFF}-\x{4F06}\x{4F08}-\x{4F15}' + . '\x{4F17}-\x{4F27}\x{4F29}-\x{4F30}\x{4F32}-\x{4F34}\x{4F36}\x{4F38}-\x{4F3F}' + . '\x{4F41}-\x{4F43}\x{4F45}-\x{4F70}\x{4F72}-\x{4F8B}\x{4F8D}\x{4F8F}-\x{4FA1}' + . '\x{4FA3}-\x{4FAC}\x{4FAE}-\x{4FBC}\x{4FBE}-\x{4FC5}\x{4FC7}\x{4FC9}-\x{4FCB}' + . '\x{4FCD}-\x{4FE1}\x{4FE3}-\x{4FFB}\x{4FFE}-\x{500F}\x{5011}-\x{5033}' + . '\x{5035}-\x{5037}\x{5039}-\x{503C}\x{503E}-\x{5041}\x{5043}-\x{504F}\x{5051}' + . '\x{5053}-\x{5057}\x{5059}-\x{507B}\x{507D}-\x{5080}\x{5082}-\x{5092}' + . '\x{5094}-\x{5096}\x{5098}-\x{509E}\x{50A2}-\x{50B8}\x{50BA}-\x{50C2}' + . '\x{50C4}-\x{50D7}\x{50D9}-\x{50DE}\x{50E0}\x{50E3}-\x{50EA}\x{50EC}-\x{50F3}' + . '\x{50F5}\x{50F6}\x{50F8}-\x{511A}\x{511C}-\x{5127}\x{5129}\x{512A}' + . '\x{512C}-\x{5141}\x{5143}-\x{5149}\x{514B}-\x{514E}\x{5150}-\x{5152}' + . '\x{5154}-\x{5157}\x{5159}-\x{515F}\x{5161}-\x{5163}\x{5165}-\x{5171}' + . '\x{5173}-\x{517D}\x{517F}-\x{5182}\x{5185}-\x{518D}\x{518F}-\x{51A0}\x{51A2}' + . '\x{51A4}-\x{51A8}\x{51AA}-\x{51AC}\x{51AE}-\x{51B3}\x{51B5}-\x{51B7}\x{51B9}' + . '\x{51BB}-\x{51C1}\x{51C3}-\x{51D1}\x{51D4}-\x{51DE}\x{51E0}-\x{51E5}' + . '\x{51E7}-\x{51EB}\x{51ED}\x{51EF}-\x{51F1}\x{51F3}-\x{5226}\x{5228}-\x{524E}' + . '\x{5250}-\x{5252}\x{5254}-\x{5265}\x{5267}-\x{5270}\x{5272}-\x{5278}' + . '\x{527A}-\x{5284}\x{5286}-\x{528D}\x{528F}-\x{52A3}\x{52A5}-\x{52C3}\x{52C6}' + . '\x{52C7}\x{52C9}-\x{52CB}\x{52CD}\x{52CF}\x{52D0}\x{52D2}\x{52D3}' + . '\x{52D5}-\x{52E0}\x{52E2}-\x{52E4}\x{52E6}-\x{52ED}\x{52EF}-\x{5302}' + . '\x{5305}-\x{5317}\x{5319}\x{531A}\x{531C}\x{531D}\x{531F}-\x{5326}\x{5328}' + . '\x{532A}-\x{5331}\x{5333}\x{5334}\x{5337}\x{5339}-\x{5341}\x{5343}-\x{535A}' + . '\x{535C}\x{535E}-\x{5367}\x{5369}\x{536B}\x{536C}\x{536E}-\x{537F}' + . '\x{5381}-\x{53A0}\x{53A2}-\x{53A9}\x{53AC}-\x{53AE}\x{53B0}-\x{53B9}' + . '\x{53BB}-\x{53C4}\x{53C6}-\x{53CE}\x{53D0}-\x{53D9}\x{53DB}\x{53DC}' + . '\x{53DF}-\x{53E6}\x{53E8}-\x{53FE}\x{5401}-\x{5419}\x{541B}-\x{5421}' + . '\x{5423}-\x{544B}\x{544D}-\x{545C}\x{545E}-\x{5468}\x{546A}-\x{5489}' + . '\x{548B}-\x{54B4}\x{54B6}-\x{54F5}\x{54F7}-\x{5514}\x{5516}\x{5517}' + . '\x{551A}-\x{5546}\x{5548}-\x{555F}\x{5561}-\x{5579}\x{557B}-\x{55DF}' + . '\x{55E1}-\x{55F7}\x{55F9}-\x{5604}\x{5606}-\x{5609}\x{560C}-\x{561F}' + . '\x{5621}-\x{562A}\x{562C}-\x{5636}\x{5638}-\x{563B}\x{563D}-\x{5643}' + . '\x{5645}-\x{564A}\x{564C}-\x{5650}\x{5652}-\x{5655}\x{5657}-\x{565E}\x{5660}' + . '\x{5662}-\x{5674}\x{5676}-\x{567C}\x{567E}-\x{5687}\x{568A}\x{568C}-\x{5695}' + . '\x{5697}-\x{569D}\x{569F}-\x{56A1}\x{56A3}-\x{56B9}\x{56BB}-\x{56CE}' + . '\x{56D0}-\x{56D8}\x{56DA}-\x{56E5}\x{56E7}-\x{56F5}\x{56F7}\x{56F9}\x{56FA}' + . '\x{56FD}-\x{5704}\x{5706}-\x{5710}\x{5712}-\x{5716}\x{5718}-\x{5720}\x{5722}' + . '\x{5723}\x{5725}-\x{573C}\x{573E}-\x{5742}\x{5744}-\x{5747}\x{5749}-\x{5754}' + . '\x{5757}\x{5759}-\x{5762}\x{5764}-\x{576D}\x{576F}-\x{5777}\x{5779}-\x{5780}' + . '\x{5782}-\x{5786}\x{5788}-\x{5795}\x{5797}-\x{57A7}\x{57A9}-\x{57C9}' + . '\x{57CB}-\x{57D0}\x{57D2}-\x{57D6}\x{57D8}-\x{57DA}\x{57DC}\x{57DD}' + . '\x{57DF}-\x{5816}\x{5819}-\x{5840}\x{5842}-\x{584F}\x{5851}-\x{5855}' + . '\x{5857}-\x{585F}\x{5861}-\x{5865}\x{5868}-\x{5876}\x{5878}-\x{5894}' + . '\x{5896}-\x{58A9}\x{58AB}-\x{58B4}\x{58B7}-\x{58BF}\x{58C1}\x{58C2}' + . '\x{58C5}-\x{58CB}\x{58CE}\x{58CF}\x{58D1}-\x{58DB}\x{58DD}-\x{58E0}' + . '\x{58E2}-\x{58E5}\x{58E7}-\x{58F4}\x{58F6}-\x{5900}\x{5902}-\x{5904}\x{5906}' + . '\x{5907}\x{5909}-\x{5910}\x{5912}\x{5914}-\x{5922}\x{5924}-\x{5932}\x{5934}' + . '\x{5935}\x{5937}-\x{5958}\x{595A}\x{595C}-\x{599A}\x{599C}-\x{59B6}' + . '\x{59B8}-\x{59E6}\x{59E8}-\x{5A23}\x{5A25}\x{5A27}-\x{5A2B}\x{5A2D}-\x{5A2F}' + . '\x{5A31}-\x{5A53}\x{5A55}-\x{5A58}\x{5A5A}-\x{5A6E}\x{5A70}\x{5A72}-\x{5A86}' + . '\x{5A88}-\x{5A8C}\x{5A8E}-\x{5AAA}\x{5AAC}-\x{5ACF}\x{5AD1}\x{5AD2}' + . '\x{5AD4}-\x{5AEE}\x{5AF1}-\x{5B09}\x{5B0B}\x{5B0C}\x{5B0E}-\x{5B38}' + . '\x{5B3A}-\x{5B45}\x{5B47}-\x{5B4E}\x{5B50}\x{5B51}\x{5B53}-\x{5B5F}' + . '\x{5B62}-\x{5B6E}\x{5B70}-\x{5B78}\x{5B7A}-\x{5B7D}\x{5B7F}-\x{5B85}' + . '\x{5B87}-\x{5B8F}\x{5B91}-\x{5BA8}\x{5BAA}-\x{5BB1}\x{5BB3}-\x{5BB6}' + . '\x{5BB8}-\x{5BBB}\x{5BBD}-\x{5BC7}\x{5BCA}-\x{5BD6}\x{5BD8}\x{5BD9}' + . '\x{5BDB}-\x{5BFD}\x{5BFF}\x{5C01}\x{5C03}-\x{5C1A}\x{5C1C}-\x{5C22}\x{5C24}' + . '\x{5C25}\x{5C27}\x{5C28}\x{5C2A}-\x{5C35}\x{5C37}-\x{5C59}\x{5C5B}-\x{5C84}' + . '\x{5C86}-\x{5CB3}\x{5CB5}-\x{5CB8}\x{5CBA}-\x{5CBF}\x{5CC1}-\x{5CD4}' + . '\x{5CD6}-\x{5CDC}\x{5CDE}-\x{5CF4}\x{5CF6}-\x{5D2A}\x{5D2C}-\x{5D2E}' + . '\x{5D30}-\x{5D3A}\x{5D3C}-\x{5D52}\x{5D54}-\x{5D56}\x{5D58}-\x{5D5B}' + . '\x{5D5D}-\x{5D5F}\x{5D61}-\x{5D82}\x{5D84}-\x{5D95}\x{5D97}-\x{5DA2}' + . '\x{5DA5}-\x{5DAA}\x{5DAC}-\x{5DB2}\x{5DB4}-\x{5DB8}\x{5DBA}-\x{5DC3}' + . '\x{5DC5}-\x{5DD6}\x{5DD8}\x{5DD9}\x{5DDB}\x{5DDD}-\x{5DF5}\x{5DF7}-\x{5E11}' + . '\x{5E13}-\x{5E3E}\x{5E40}-\x{5E47}\x{5E49}-\x{5E50}\x{5E52}-\x{5E91}' + . '\x{5E93}-\x{5EB9}\x{5EBB}-\x{5EBF}\x{5EC1}-\x{5EEA}\x{5EEC}-\x{5EF8}' + . '\x{5EFA}-\x{5F08}\x{5F0A}-\x{5F0D}\x{5F0F}\x{5F11}-\x{5F3A}\x{5F3C}' + . '\x{5F3E}-\x{5F8E}\x{5F90}-\x{5F99}\x{5F9B}-\x{5FA2}\x{5FA5}-\x{5FAF}' + . '\x{5FB1}-\x{5FC1}\x{5FC3}-\x{5FCD}\x{5FCF}-\x{5FDA}\x{5FDC}-\x{5FDE}\x{5FE0}' + . '\x{5FE1}\x{5FE3}-\x{5FEB}\x{5FED}-\x{5FFB}\x{5FFD}-\x{6022}\x{6024}-\x{6055}' + . '\x{6057}-\x{605F}\x{6062}-\x{6070}\x{6072}\x{6073}\x{6075}-\x{6090}\x{6092}' + . '\x{6094}-\x{60A4}\x{60A6}-\x{60A8}\x{60AA}-\x{60D1}\x{60D3}-\x{60D5}' + . '\x{60D7}-\x{60DD}\x{60DF}-\x{60E2}\x{60E4}\x{60E6}-\x{60FC}\x{60FE}-\x{6101}' + . '\x{6103}-\x{6106}\x{6108}-\x{6110}\x{6112}-\x{611D}\x{611F}\x{6120}' + . '\x{6122}-\x{6130}\x{6132}\x{6134}\x{6136}\x{6137}\x{613A}-\x{615F}' + . '\x{6161}-\x{616E}\x{6170}-\x{617A}\x{617C}\x{617E}\x{6180}-\x{6185}' + . '\x{6187}-\x{6196}\x{6198}-\x{619B}\x{619D}-\x{61B8}\x{61BA}\x{61BC}-\x{61D2}' + . '\x{61D4}\x{61D6}-\x{61EB}\x{61ED}\x{61EE}\x{61F0}-\x{61F3}\x{61F5}-\x{6204}' + . '\x{6206}-\x{6234}\x{6236}-\x{6238}\x{623A}-\x{6256}\x{6258}-\x{6281}' + . '\x{6283}-\x{628C}\x{628E}-\x{629C}\x{629E}-\x{62A5}\x{62A7}-\x{62DD}' + . '\x{62DF}-\x{62E9}\x{62EB}-\x{6309}\x{630B}-\x{6316}\x{6318}-\x{6330}' + . '\x{6332}-\x{6334}\x{6336}\x{6338}-\x{633E}\x{6340}-\x{635A}\x{635C}-\x{637E}' + . '\x{6380}-\x{638A}\x{638C}-\x{6392}\x{6394}-\x{63BA}\x{63BC}-\x{63D0}' + . '\x{63D2}-\x{6406}\x{6408}-\x{643A}\x{643D}-\x{6441}\x{6443}-\x{6448}' + . '\x{644A}-\x{6459}\x{645B}-\x{647D}\x{647F}-\x{6485}\x{6487}-\x{64A0}' + . '\x{64A2}-\x{64AE}\x{64B0}-\x{64B5}\x{64B7}-\x{64C7}\x{64C9}-\x{64D4}' + . '\x{64D6}-\x{64E0}\x{64E2}-\x{64E4}\x{64E6}-\x{64ED}\x{64EF}-\x{64F4}' + . '\x{64F6}-\x{64F8}\x{64FA}-\x{6501}\x{6503}-\x{6509}\x{650B}-\x{651E}' + . '\x{6520}-\x{6527}\x{6529}-\x{653F}\x{6541}\x{6543}-\x{6559}\x{655B}-\x{655E}' + . '\x{6560}-\x{656C}\x{656E}-\x{657C}\x{657E}-\x{6589}\x{658B}-\x{6599}' + . '\x{659B}-\x{65B4}\x{65B6}-\x{65BD}\x{65BF}-\x{65C7}\x{65CA}-\x{65D0}' + . '\x{65D2}-\x{65D7}\x{65DA}\x{65DB}\x{65DD}-\x{65E3}\x{65E5}-\x{65E9}' + . '\x{65EB}-\x{65F8}\x{65FA}-\x{65FD}\x{6600}-\x{6616}\x{6618}-\x{661D}' + . '\x{661F}-\x{662B}\x{662D}-\x{6636}\x{6639}\x{663A}\x{663C}-\x{663E}' + . '\x{6640}-\x{6647}\x{6649}-\x{664C}\x{664E}-\x{665F}\x{6661}\x{6662}' + . '\x{6664}-\x{6666}\x{6668}-\x{6691}\x{6693}-\x{669B}\x{669D}\x{669F}-\x{66AB}' + . '\x{66AE}-\x{66CF}\x{66D1}\x{66D2}\x{66D4}-\x{66D6}\x{66D8}-\x{66DE}' + . '\x{66E0}-\x{66EE}\x{66F0}-\x{66FC}\x{66FE}-\x{6701}\x{6703}-\x{6706}' + . '\x{6708}-\x{6718}\x{671A}-\x{6723}\x{6725}-\x{6728}\x{672A}-\x{6766}' + . '\x{6768}-\x{6787}\x{6789}-\x{6795}\x{6797}-\x{67A8}\x{67AA}-\x{67BC}\x{67BE}' + . '\x{67C0}-\x{67D4}\x{67D6}\x{67D8}-\x{67F8}\x{67FA}-\x{6800}\x{6802}-\x{6814}' + . '\x{6816}-\x{681D}\x{681F}-\x{6826}\x{6828}-\x{682F}\x{6831}-\x{6857}\x{685B}' + . '\x{685D}\x{6860}-\x{6879}\x{687B}-\x{6894}\x{6896}-\x{6898}\x{689A}-\x{68A4}' + . '\x{68A6}-\x{68B7}\x{68B9}\x{68BB}-\x{68C2}\x{68C4}\x{68C6}-\x{68D8}' + . '\x{68DA}-\x{68E1}\x{68E3}\x{68E4}\x{68E6}-\x{68FF}\x{6901}-\x{6908}' + . '\x{690A}-\x{693D}\x{693F}-\x{694C}\x{694E}-\x{699E}\x{69A0}\x{69A1}' + . '\x{69A3}-\x{69BF}\x{69C1}-\x{69D0}\x{69D3}\x{69D4}\x{69D8}-\x{69F8}' + . '\x{69FA}-\x{6A02}\x{6A04}-\x{6A0B}\x{6A0D}-\x{6A1B}\x{6A1D}-\x{6A23}' + . '\x{6A25}-\x{6A36}\x{6A38}-\x{6A49}\x{6A4B}-\x{6A52}\x{6A54}-\x{6A5B}' + . '\x{6A5D}-\x{6A6D}\x{6A6F}\x{6A71}-\x{6A85}\x{6A87}-\x{6A89}\x{6A8B}-\x{6A8E}' + . '\x{6A90}-\x{6A98}\x{6A9A}-\x{6A9C}\x{6A9E}-\x{6AA9}\x{6AAB}-\x{6AB0}' + . '\x{6AB2}-\x{6ABD}\x{6ABF}\x{6AC1}-\x{6AC3}\x{6AC5}-\x{6AC7}\x{6ACA}-\x{6AD7}' + . '\x{6AD9}-\x{6AE8}\x{6AEA}-\x{6B0D}\x{6B0F}-\x{6B1A}\x{6B1C}-\x{6B2D}' + . '\x{6B2F}-\x{6B34}\x{6B36}-\x{6B3F}\x{6B41}-\x{6B56}\x{6B59}-\x{6B5C}' + . '\x{6B5E}-\x{6B67}\x{6B69}-\x{6B6B}\x{6B6D}\x{6B6F}\x{6B70}\x{6B72}-\x{6B74}' + . '\x{6B76}-\x{6B7C}\x{6B7E}-\x{6BB0}\x{6BB2}-\x{6BB7}\x{6BB9}-\x{6BE8}' + . '\x{6BEA}-\x{6BF0}\x{6BF2}\x{6BF3}\x{6BF5}-\x{6BF9}\x{6BFB}-\x{6C09}' + . '\x{6C0B}-\x{6C16}\x{6C18}-\x{6C1B}\x{6C1D}-\x{6C2C}\x{6C2E}-\x{6C38}\x{6C3A}' + . '\x{6C3B}\x{6C3D}-\x{6C44}\x{6C46}-\x{6C6B}\x{6C6D}\x{6C6F}-\x{6C9F}' + . '\x{6CA1}-\x{6CD7}\x{6CD9}-\x{6CF3}\x{6CF5}-\x{6D01}\x{6D03}-\x{6D1B}' + . '\x{6D1D}-\x{6D23}\x{6D25}-\x{6D70}\x{6D72}-\x{6D80}\x{6D82}-\x{6D95}' + . '\x{6D97}-\x{6D9B}\x{6D9D}-\x{6DAF}\x{6DB2}-\x{6DB5}\x{6DB7}-\x{6DFD}\x{6E00}' + . '\x{6E03}-\x{6E05}\x{6E07}-\x{6E11}\x{6E14}-\x{6E17}\x{6E19}-\x{6E29}' + . '\x{6E2B}-\x{6E4B}\x{6E4D}-\x{6E6B}\x{6E6D}-\x{6E75}\x{6E77}-\x{6E79}' + . '\x{6E7E}-\x{6E8A}\x{6E8D}-\x{6E94}\x{6E96}-\x{6EDA}\x{6EDC}\x{6EDE}-\x{6EE2}' + . '\x{6EE4}-\x{6F03}\x{6F05}-\x{6F0A}\x{6F0C}-\x{6F41}\x{6F43}-\x{6F47}\x{6F49}' + . '\x{6F4B}-\x{6F78}\x{6F7A}-\x{6F97}\x{6F99}\x{6F9B}-\x{6F9E}\x{6FA0}-\x{6FB6}' + . '\x{6FB8}-\x{6FC4}\x{6FC6}-\x{6FCF}\x{6FD1}\x{6FD2}\x{6FD4}-\x{6FF4}' + . '\x{6FF6}-\x{6FFC}\x{6FFE}-\x{700F}\x{7011}\x{7012}\x{7014}-\x{701D}' + . '\x{701F}-\x{7046}\x{7048}-\x{704A}\x{704C}\x{704D}\x{704F}-\x{7071}' + . '\x{7074}-\x{707A}\x{707C}-\x{7080}\x{7082}-\x{708C}\x{708E}-\x{7096}' + . '\x{7098}-\x{709A}\x{709C}-\x{70A9}\x{70AB}-\x{70B1}\x{70B3}-\x{70B5}' + . '\x{70B7}-\x{70D4}\x{70D6}-\x{70FD}\x{70FF}-\x{7107}\x{7109}-\x{7113}' + . '\x{7115}-\x{7123}\x{7125}-\x{7132}\x{7135}-\x{713B}\x{713D}-\x{7154}\x{7156}' + . '\x{7158}-\x{716A}\x{716C}\x{716E}-\x{718C}\x{718E}-\x{7195}\x{7197}-\x{71A5}' + . '\x{71A7}-\x{71AA}\x{71AC}-\x{71B5}\x{71B7}-\x{71CB}\x{71CD}-\x{71D2}' + . '\x{71D4}-\x{71F2}\x{71F4}-\x{71F9}\x{71FB}-\x{71FF}\x{7201}-\x{720A}' + . '\x{720C}-\x{7210}\x{7212}-\x{7214}\x{7216}\x{7218}-\x{721F}\x{7221}-\x{7223}' + . '\x{7226}-\x{722E}\x{7230}-\x{7233}\x{7235}-\x{7244}\x{7246}-\x{724D}\x{724F}' + . '\x{7251}-\x{7254}\x{7256}-\x{729F}\x{72A1}-\x{72AA}\x{72AC}-\x{72BD}' + . '\x{72BF}-\x{7301}\x{7303}-\x{730F}\x{7311}-\x{731E}\x{7320}-\x{7327}' + . '\x{7329}-\x{732E}\x{7330}-\x{734E}\x{7350}-\x{7352}\x{7354}-\x{7362}' + . '\x{7364}-\x{739B}\x{739D}-\x{73C0}\x{73C2}-\x{73E0}\x{73E2}\x{73E3}' + . '\x{73E5}-\x{73F2}\x{73F4}-\x{73FA}\x{73FC}-\x{7417}\x{7419}-\x{7438}' + . '\x{743A}-\x{743D}\x{743F}-\x{7446}\x{7448}\x{744A}-\x{7457}\x{7459}-\x{745F}' + . '\x{7461}-\x{747A}\x{747C}-\x{7483}\x{7485}-\x{7495}\x{7497}-\x{749C}' + . '\x{749E}-\x{74A1}\x{74A3}-\x{74C6}\x{74CA}\x{74CB}\x{74CD}-\x{74EA}' + . '\x{74EC}-\x{750D}\x{750F}-\x{751F}\x{7521}-\x{7533}\x{7535}-\x{7540}' + . '\x{7542}-\x{7549}\x{754B}-\x{7551}\x{7553}\x{7554}\x{7556}-\x{755D}\x{755F}' + . '\x{7560}\x{7562}-\x{7570}\x{7572}\x{7574}-\x{7579}\x{757C}-\x{7584}' + . '\x{7586}-\x{758D}\x{758F}-\x{75A8}\x{75AA}-\x{75B6}\x{75B8}-\x{75DB}' + . '\x{75DD}-\x{75E8}\x{75EA}-\x{75ED}\x{75EF}-\x{762B}\x{762D}-\x{7643}' + . '\x{7646}-\x{764D}\x{764F}\x{7650}\x{7652}-\x{7654}\x{7656}-\x{7672}' + . '\x{7674}-\x{7679}\x{767B}-\x{768C}\x{768E}-\x{76A0}\x{76A3}\x{76A4}\x{76A6}' + . '\x{76A7}\x{76A9}-\x{76B2}\x{76B4}\x{76B5}\x{76B7}\x{76B8}\x{76BA}-\x{76C0}' + . '\x{76C2}-\x{76CA}\x{76CD}-\x{76D8}\x{76DA}-\x{76EA}\x{76EC}-\x{76FF}\x{7701}' + . '\x{7703}-\x{770D}\x{770F}-\x{7720}\x{7722}\x{7723}\x{7725}-\x{772A}' + . '\x{772C}-\x{773E}\x{7740}\x{7741}\x{7743}-\x{7763}\x{7765}-\x{7795}' + . '\x{7797}-\x{77A3}\x{77A5}-\x{77BD}\x{77BF}\x{77C0}\x{77C2}-\x{77D1}' + . '\x{77D3}-\x{77DC}\x{77DE}-\x{77E3}\x{77E5}\x{77E7}-\x{77F3}\x{77F6}-\x{7806}' + . '\x{7808}-\x{7823}\x{7825}-\x{7835}\x{7837}-\x{783E}\x{7840}\x{7841}' + . '\x{7843}-\x{7845}\x{7847}-\x{784A}\x{784C}-\x{784E}\x{7850}-\x{7875}' + . '\x{7877}-\x{7887}\x{7889}-\x{78C1}\x{78C3}-\x{78C6}\x{78C8}-\x{78D1}' + . '\x{78D3}-\x{78EF}\x{78F1}-\x{78F7}\x{78F9}-\x{78FF}\x{7901}-\x{7907}' + . '\x{7909}-\x{790C}\x{790E}-\x{7914}\x{7916}-\x{791E}\x{7921}-\x{7931}' + . '\x{7933}-\x{7935}\x{7937}-\x{7958}\x{795A}-\x{796B}\x{796D}\x{796F}-\x{7974}' + . '\x{7977}-\x{7985}\x{7988}-\x{799C}\x{799F}-\x{79A8}\x{79AA}-\x{79BB}' + . '\x{79BD}-\x{79C3}\x{79C5}\x{79C6}\x{79C8}-\x{79CB}\x{79CD}-\x{79D3}\x{79D5}' + . '\x{79D6}\x{79D8}-\x{7A00}\x{7A02}-\x{7A06}\x{7A08}\x{7A0A}-\x{7A2B}' + . '\x{7A2D}-\x{7A35}\x{7A37}\x{7A39}\x{7A3B}-\x{7A4E}\x{7A50}-\x{7A62}' + . '\x{7A65}-\x{7A69}\x{7A6B}-\x{7A6E}\x{7A70}-\x{7A81}\x{7A83}-\x{7A99}' + . '\x{7A9C}-\x{7AB8}\x{7ABA}\x{7ABE}-\x{7AC1}\x{7AC4}\x{7AC5}\x{7AC7}-\x{7AD6}' + . '\x{7AD8}\x{7AD9}\x{7ADB}-\x{7AE8}\x{7AEA}-\x{7AF4}\x{7AF6}-\x{7AFB}' + . '\x{7AFD}-\x{7B06}\x{7B08}-\x{7B1E}\x{7B20}-\x{7B26}\x{7B28}\x{7B2A}-\x{7B41}' + . '\x{7B43}-\x{7B52}\x{7B54}-\x{7B6E}\x{7B70}-\x{7B79}\x{7B7B}-\x{7B85}' + . '\x{7B87}-\x{7B91}\x{7B93}-\x{7BA2}\x{7BA4}\x{7BA6}-\x{7BAF}\x{7BB1}' + . '\x{7BB3}-\x{7BCE}\x{7BD0}-\x{7BF9}\x{7BFB}-\x{7C13}\x{7C15}-\x{7C1A}' + . '\x{7C1C}-\x{7C2D}\x{7C30}-\x{7C4E}\x{7C50}\x{7C51}\x{7C53}\x{7C54}' + . '\x{7C56}-\x{7C5C}\x{7C5E}-\x{7C75}\x{7C77}-\x{7C82}\x{7C84}-\x{7C86}' + . '\x{7C88}-\x{7C92}\x{7C94}-\x{7C99}\x{7C9B}-\x{7CAA}\x{7CAD}-\x{7CD2}' + . '\x{7CD4}-\x{7CD9}\x{7CDC}-\x{7CE0}\x{7CE2}\x{7CE4}\x{7CE7}-\x{7CFB}\x{7CFD}' + . '\x{7CFE}\x{7D00}-\x{7D22}\x{7D24}-\x{7D29}\x{7D2B}\x{7D2C}\x{7D2E}-\x{7D47}' + . '\x{7D49}-\x{7D4C}\x{7D4E}-\x{7D59}\x{7D5B}-\x{7D63}\x{7D65}-\x{7D77}' + . '\x{7D79}-\x{7D81}\x{7D83}-\x{7D94}\x{7D96}\x{7D97}\x{7D99}\x{7D9B}-\x{7DA3}' + . '\x{7DA5}-\x{7DA7}\x{7DA9}-\x{7DCC}\x{7DCE}-\x{7DD2}\x{7DD4}-\x{7DDB}' + . '\x{7DDD}-\x{7DE3}\x{7DE6}-\x{7DEA}\x{7DEC}-\x{7DFC}\x{7E00}-\x{7E17}' + . '\x{7E19}-\x{7E49}\x{7E4C}-\x{7E5A}\x{7E5C}-\x{7E63}\x{7E65}-\x{7E9C}' + . '\x{7E9E}-\x{7F3A}\x{7F3D}-\x{7F40}\x{7F42}-\x{7F45}\x{7F47}-\x{7F58}' + . '\x{7F5A}-\x{7F83}\x{7F85}-\x{7F8F}\x{7F91}-\x{7F96}\x{7F98}\x{7F9A}-\x{7FB3}' + . '\x{7FB5}-\x{7FD5}\x{7FD7}-\x{7FDC}\x{7FDE}-\x{7FE3}\x{7FE5}-\x{8009}' + . '\x{800B}-\x{802E}\x{8030}-\x{803B}\x{803D}-\x{803F}\x{8041}-\x{8065}' + . '\x{8067}-\x{8087}\x{8089}-\x{808D}\x{808F}-\x{8093}\x{8095}-\x{80A5}' + . '\x{80A9}-\x{80AB}\x{80AD}-\x{80B2}\x{80B4}-\x{80B8}\x{80BA}-\x{80DE}' + . '\x{80E0}-\x{8102}\x{8105}-\x{8116}\x{8118}-\x{8132}\x{8136}-\x{815E}' + . '\x{8160}-\x{8183}\x{8185}-\x{818F}\x{8191}-\x{8195}\x{8197}-\x{81CA}' + . '\x{81CC}-\x{81D2}\x{81D4}-\x{81E3}\x{81E5}-\x{81EE}\x{81F1}-\x{8212}' + . '\x{8214}-\x{8216}\x{8218}-\x{8223}\x{8225}-\x{822D}\x{822F}-\x{8240}' + . '\x{8242}-\x{8261}\x{8263}\x{8264}\x{8266}-\x{828B}\x{828D}-\x{82B1}' + . '\x{82B3}-\x{82E1}\x{82E3}-\x{82FB}\x{82FD}-\x{8309}\x{830B}-\x{830F}' + . '\x{8311}-\x{832F}\x{8331}-\x{8354}\x{8356}-\x{839E}\x{83A0}-\x{83B4}' + . '\x{83B6}-\x{83BD}\x{83BF}-\x{83E5}\x{83E7}-\x{83EC}\x{83EE}-\x{8413}\x{8415}' + . '\x{8418}-\x{841E}\x{8421}-\x{8457}\x{8459}-\x{8482}\x{8484}-\x{8494}' + . '\x{8496}-\x{84AC}\x{84AE}-\x{84B6}\x{84B8}-\x{84C2}\x{84C4}-\x{84D9}' + . '\x{84DB}-\x{84EC}\x{84EE}-\x{8504}\x{8506}-\x{850F}\x{8511}-\x{8531}' + . '\x{8534}-\x{854B}\x{854D}-\x{854F}\x{8551}-\x{857E}\x{8580}-\x{8592}' + . '\x{8594}-\x{8596}\x{8598}-\x{85B1}\x{85B3}-\x{85BA}\x{85BC}-\x{85CB}' + . '\x{85CD}-\x{85ED}\x{85EF}-\x{85F2}\x{85F4}-\x{85FB}\x{85FD}-\x{8602}' + . '\x{8604}-\x{860C}\x{860F}\x{8611}-\x{8614}\x{8616}-\x{861C}\x{861E}-\x{8636}' + . '\x{8638}-\x{8656}\x{8658}-\x{8674}\x{8676}-\x{8688}\x{868A}-\x{8691}' + . '\x{8693}-\x{869F}\x{86A1}-\x{86A5}\x{86A7}-\x{86CC}\x{86CE}-\x{86D4}' + . '\x{86D6}-\x{86DF}\x{86E1}-\x{86E6}\x{86E8}-\x{86FC}\x{86FE}-\x{871C}' + . '\x{871E}-\x{872E}\x{8730}-\x{873C}\x{873E}-\x{8744}\x{8746}-\x{874A}' + . '\x{874C}-\x{8770}\x{8772}-\x{877E}\x{8780}-\x{878D}\x{878F}-\x{8798}' + . '\x{879A}-\x{87D9}\x{87DB}-\x{87EF}\x{87F1}-\x{8806}\x{8808}-\x{8811}' + . '\x{8813}-\x{882C}\x{882E}-\x{8839}\x{883B}-\x{8846}\x{8848}-\x{8857}' + . '\x{8859}-\x{885B}\x{885D}\x{885E}\x{8860}-\x{8879}\x{887B}-\x{88B4}' + . '\x{88B6}-\x{88E5}\x{88E7}\x{88E8}\x{88EA}-\x{88EC}\x{88EE}-\x{8902}' + . '\x{8904}-\x{890E}\x{8910}-\x{8923}\x{8925}-\x{894C}\x{894E}-\x{8964}' + . '\x{8966}-\x{8974}\x{8976}-\x{897C}\x{897E}-\x{898C}\x{898E}\x{898F}' + . '\x{8991}-\x{8993}\x{8995}-\x{8998}\x{899A}-\x{89A8}\x{89AA}-\x{89AF}' + . '\x{89B1}-\x{89B3}\x{89B5}-\x{89BA}\x{89BD}-\x{89ED}\x{89EF}-\x{89F4}' + . '\x{89F6}-\x{89F8}\x{89FA}-\x{89FC}\x{89FE}-\x{8A04}\x{8A07}-\x{8A13}' + . '\x{8A15}-\x{8A18}\x{8A1A}-\x{8A1F}\x{8A22}-\x{8A2A}\x{8A2C}-\x{8A32}' + . '\x{8A34}-\x{8A3C}\x{8A3E}-\x{8A4A}\x{8A4C}-\x{8A63}\x{8A65}-\x{8A77}' + . '\x{8A79}-\x{8A7C}\x{8A7E}-\x{8A87}\x{8A89}-\x{8A9E}\x{8AA0}-\x{8AAC}\x{8AAE}' + . '\x{8AB0}-\x{8AB6}\x{8AB8}-\x{8ACF}\x{8AD1}-\x{8AEB}\x{8AED}-\x{8B0B}' + . '\x{8B0D}-\x{8B28}\x{8B2A}-\x{8B31}\x{8B33}-\x{8B37}\x{8B39}-\x{8B3E}' + . '\x{8B40}-\x{8B60}\x{8B63}-\x{8B68}\x{8B6A}-\x{8B71}\x{8B73}\x{8B74}' + . '\x{8B76}-\x{8B7B}\x{8B7D}-\x{8B80}\x{8B82}-\x{8B86}\x{8B88}-\x{8B8C}\x{8B8E}' + . '\x{8B90}-\x{8B9A}\x{8B9C}-\x{8C37}\x{8C39}-\x{8C3F}\x{8C41}-\x{8C43}' + . '\x{8C45}-\x{8C50}\x{8C54}-\x{8C57}\x{8C59}-\x{8C73}\x{8C75}-\x{8C7B}\x{8C7D}' + . '\x{8C7E}\x{8C80}-\x{8C82}\x{8C84}-\x{8C86}\x{8C88}-\x{8C8A}\x{8C8C}\x{8C8D}' + . '\x{8C8F}-\x{8C9A}\x{8C9C}-\x{8CA5}\x{8CA7}-\x{8CCA}\x{8CCC}\x{8CCE}-\x{8CD5}' + . '\x{8CD7}\x{8CD9}-\x{8CE8}\x{8CEA}-\x{8CF6}\x{8CF8}-\x{8D00}\x{8D02}-\x{8D10}' + . '\x{8D13}-\x{8D7B}\x{8D7D}-\x{8DA5}\x{8DA7}-\x{8DBF}\x{8DC1}-\x{8DE4}' + . '\x{8DE6}-\x{8E00}\x{8E02}-\x{8E0A}\x{8E0C}-\x{8E31}\x{8E33}-\x{8E45}' + . '\x{8E47}-\x{8E4E}\x{8E50}-\x{8E6D}\x{8E6F}-\x{8E74}\x{8E76}\x{8E78}' + . '\x{8E7A}-\x{8E98}\x{8E9A}\x{8E9C}-\x{8EA1}\x{8EA3}-\x{8EB2}\x{8EB4}\x{8EB5}' + . '\x{8EB8}-\x{8EC0}\x{8EC2}\x{8EC3}\x{8EC5}-\x{8ED8}\x{8EDA}-\x{8EE1}' + . '\x{8EE4}-\x{8EEF}\x{8EF1}-\x{8F0B}\x{8F0D}\x{8F0E}\x{8F10}-\x{8F18}' + . '\x{8F1A}-\x{8F2C}\x{8F2E}-\x{8F39}\x{8F3B}-\x{8F40}\x{8F42}-\x{8F5B}' + . '\x{8F5D}-\x{8F9C}\x{8F9E}-\x{8FA3}\x{8FA5}-\x{8FB2}\x{8FB4}-\x{8FB9}' + . '\x{8FBB}-\x{8FC2}\x{8FC4}-\x{8FC9}\x{8FCB}-\x{8FE6}\x{8FE8}-\x{900D}' + . '\x{900F}-\x{9029}\x{902B}\x{902D}-\x{9036}\x{9038}\x{903A}-\x{903F}' + . '\x{9041}-\x{9045}\x{9047}-\x{90AA}\x{90AC}-\x{90CB}\x{90CE}-\x{90D1}' + . '\x{90D3}-\x{90F5}\x{90F7}-\x{9109}\x{910B}-\x{913B}\x{913E}-\x{9158}' + . '\x{915A}-\x{917A}\x{917C}-\x{9194}\x{9196}\x{9199}-\x{91A3}\x{91A5}-\x{91A8}' + . '\x{91AA}-\x{91B7}\x{91B9}-\x{91BE}\x{91C0}-\x{91C3}\x{91C5}-\x{91C7}' + . '\x{91C9}-\x{91D5}\x{91D7}-\x{91DF}\x{91E2}-\x{91EE}\x{91F0}-\x{91F5}' + . '\x{91F7}-\x{91FB}\x{91FD}-\x{9212}\x{9214}-\x{921E}\x{9220}\x{9221}' + . '\x{9223}-\x{922B}\x{922D}-\x{9242}\x{9245}-\x{9268}\x{926B}-\x{9270}' + . '\x{9272}-\x{9280}\x{9282}\x{9283}\x{9285}-\x{929D}\x{929F}-\x{92BC}' + . '\x{92BE}-\x{92D3}\x{92D5}-\x{92DA}\x{92DC}-\x{92E1}\x{92E3}-\x{931B}' + . '\x{931D}-\x{932B}\x{932D}-\x{932F}\x{9332}-\x{9361}\x{9363}-\x{9367}\x{9369}' + . '\x{936A}\x{936C}-\x{936E}\x{9370}-\x{9372}\x{9374}-\x{9377}\x{9379}-\x{937E}' + . '\x{9380}\x{9382}-\x{938A}\x{938C}-\x{939B}\x{939D}-\x{939F}\x{93A1}-\x{93AA}' + . '\x{93AC}-\x{93BA}\x{93BC}-\x{93DF}\x{93E1}-\x{93E4}\x{93E6}-\x{93F2}' + . '\x{93F4}-\x{9401}\x{9403}-\x{9416}\x{9418}\x{9419}\x{941B}\x{941D}\x{9420}' + . '\x{9422}\x{9423}\x{9425}-\x{9442}\x{9444}-\x{944D}\x{944F}-\x{9459}' + . '\x{945B}-\x{946B}\x{946D}-\x{947A}\x{947C}-\x{9577}\x{957A}-\x{957D}' + . '\x{957F}-\x{9584}\x{9586}-\x{9596}\x{9598}-\x{959F}\x{95A1}-\x{95B2}' + . '\x{95B5}-\x{95B7}\x{95B9}-\x{95C0}\x{95C2}-\x{95D8}\x{95DA}-\x{95DC}' + . '\x{95DE}-\x{9624}\x{9627}\x{9628}\x{962A}-\x{963D}\x{963F}-\x{9655}' + . '\x{9658}-\x{9664}\x{9666}-\x{9678}\x{967C}-\x{967E}\x{9680}\x{9683}-\x{968B}' + . '\x{968D}-\x{9695}\x{9697}-\x{9699}\x{969B}\x{969C}\x{969E}\x{96A0}-\x{96AA}' + . '\x{96AC}-\x{96AE}\x{96B0}\x{96B1}\x{96B3}\x{96B4}\x{96B6}-\x{96E3}\x{96E5}' + . '\x{96E8}-\x{96FB}\x{96FD}-\x{9713}\x{9715}\x{9716}\x{9718}\x{9719}' + . '\x{971C}-\x{9732}\x{9735}\x{9736}\x{9738}-\x{973F}\x{9742}-\x{974C}' + . '\x{974E}-\x{9756}\x{9758}-\x{9762}\x{9765}-\x{9770}\x{9772}-\x{9774}' + . '\x{9776}-\x{9786}\x{9788}\x{978A}-\x{979A}\x{979C}-\x{97A8}\x{97AA}-\x{97AF}' + . '\x{97B2}-\x{97B4}\x{97B6}-\x{97BD}\x{97BF}\x{97C1}-\x{97D1}\x{97D3}-\x{97FB}' + . '\x{97FD}-\x{981E}\x{9820}-\x{9824}\x{9826}-\x{9829}\x{982B}\x{982D}-\x{9832}' + . '\x{9834}-\x{9839}\x{983B}-\x{983D}\x{983F}-\x{9841}\x{9843}-\x{9846}' + . '\x{9848}-\x{984A}\x{984C}-\x{9855}\x{9857}-\x{9865}\x{9867}\x{9869}-\x{98B6}' + . '\x{98B8}-\x{98C6}\x{98C8}\x{98C9}\x{98CB}-\x{98E0}\x{98E2}\x{98E3}' + . '\x{98E5}-\x{98EB}\x{98ED}\x{98EF}\x{98F0}\x{98F2}-\x{98F7}\x{98F9}\x{98FA}' + . '\x{98FC}-\x{9918}\x{991A}-\x{993A}\x{993C}-\x{9943}\x{9945}-\x{994C}' + . '\x{994E}-\x{9959}\x{995B}\x{995C}\x{995E}-\x{99BE}\x{99C0}-\x{99C4}' + . '\x{99C6}-\x{99DF}\x{99E1}-\x{99E5}\x{99E7}-\x{99EA}\x{99EC}-\x{99F4}' + . '\x{99F6}-\x{9A0F}\x{9A11}\x{9A14}-\x{9A16}\x{9A19}-\x{9A27}\x{9A29}-\x{9A3A}' + . '\x{9A3C}-\x{9A50}\x{9A52}-\x{9A57}\x{9A59}-\x{9A5C}\x{9A5E}-\x{9A62}' + . '\x{9A64}-\x{9AA8}\x{9AAA}-\x{9ABC}\x{9ABE}-\x{9AC7}\x{9AC9}-\x{9AD6}' + . '\x{9AD8}-\x{9ADF}\x{9AE1}-\x{9AE3}\x{9AE5}-\x{9AE7}\x{9AEA}-\x{9AEF}' + . '\x{9AF1}-\x{9AFF}\x{9B01}\x{9B03}-\x{9B08}\x{9B0A}-\x{9B13}\x{9B15}-\x{9B1A}' + . '\x{9B1C}-\x{9B33}\x{9B35}-\x{9B3C}\x{9B3E}\x{9B3F}\x{9B41}-\x{9B4F}' + . '\x{9B51}-\x{9B56}\x{9B58}-\x{9B61}\x{9B63}-\x{9B71}\x{9B73}-\x{9B88}\x{9B8A}' + . '\x{9B8B}\x{9B8D}-\x{9B98}\x{9B9A}-\x{9BC1}\x{9BC3}-\x{9BF5}\x{9BF7}-\x{9BFF}' + . '\x{9C02}\x{9C05}-\x{9C2D}\x{9C2F}-\x{9C41}\x{9C43}-\x{9C4E}\x{9C50}' + . '\x{9C52}-\x{9C60}\x{9C62}\x{9C63}\x{9C65}-\x{9C75}\x{9C77}-\x{9C7A}' + . '\x{9C7C}-\x{9D0B}\x{9D0F}\x{9D10}\x{9D12}-\x{9D26}\x{9D28}\x{9D29}\x{9D2B}' + . '\x{9D2D}-\x{9D34}\x{9D36}-\x{9D3B}\x{9D3D}-\x{9D43}\x{9D45}-\x{9D6C}' + . '\x{9D6E}-\x{9D8E}\x{9D90}-\x{9D94}\x{9D96}-\x{9DAD}\x{9DAF}-\x{9DBC}\x{9DBE}' + . '\x{9DBF}\x{9DC1}-\x{9DC5}\x{9DC7}-\x{9DE9}\x{9DEB}-\x{9DFB}\x{9DFD}-\x{9E0D}' + . '\x{9E0F}-\x{9E15}\x{9E17}-\x{9E1B}\x{9E1D}-\x{9E77}\x{9E79}\x{9E7A}' + . '\x{9E7C}-\x{9E8E}\x{9E91}-\x{9E94}\x{9E96}\x{9E97}\x{9E99}-\x{9E9D}' + . '\x{9E9F}-\x{9EA1}\x{9EA3}-\x{9EAA}\x{9EAD}-\x{9EB0}\x{9EB2}-\x{9EB8}' + . '\x{9EBB}-\x{9EEB}\x{9EED}-\x{9EF0}\x{9EF2}-\x{9F02}\x{9F04}-\x{9F10}\x{9F12}' + . '\x{9F13}\x{9F15}-\x{9F20}\x{9F22}-\x{9F25}\x{9F27}-\x{9F44}\x{9F46}-\x{9F52}' + . '\x{9F54}-\x{9F61}\x{9F63}-\x{9F6C}\x{9F6E}-\x{9FA0}\x{9FA2}\x{9FA4}\x{9FA5}]{1,20}$/iu', ]; diff --git a/vendor/league/color-extractor/.gitignore b/vendor/league/color-extractor/.gitignore new file mode 100644 index 000000000..74ef5f876 --- /dev/null +++ b/vendor/league/color-extractor/.gitignore @@ -0,0 +1,5 @@ +vendor +composer.lock +.DS_Store +.idea +.php_cs.cache \ No newline at end of file diff --git a/vendor/league/color-extractor/.php_cs b/vendor/league/color-extractor/.php_cs new file mode 100644 index 000000000..c18187489 --- /dev/null +++ b/vendor/league/color-extractor/.php_cs @@ -0,0 +1,13 @@ +files() + ->name('*.php') + ->in(array('src', 'tests')); + +return PhpCsFixer\Config::create() + ->setFinder($finder) + ->setRules([ + '@Symfony' => true, + 'array_syntax' => ['syntax' => 'short'], + ]); \ No newline at end of file diff --git a/vendor/league/color-extractor/.travis.yml b/vendor/league/color-extractor/.travis.yml new file mode 100644 index 000000000..073521ec0 --- /dev/null +++ b/vendor/league/color-extractor/.travis.yml @@ -0,0 +1,16 @@ +language: php + +php: + - 5.4 + - 5.5 + - 5.6 + - 7.0 + - hhvm + +before_script: + - travis_retry composer self-update + - travis_retry composer install --no-interaction --prefer-source --dev + +script: + - phpunit --coverage-text + - ./vendor/bin/phpcs src --standard=psr2 diff --git a/vendor/league/color-extractor/composer.json b/vendor/league/color-extractor/composer.json new file mode 100644 index 000000000..a5fb0099d --- /dev/null +++ b/vendor/league/color-extractor/composer.json @@ -0,0 +1,32 @@ +{ + "name": "league/color-extractor", + "type": "library", + "description": "Extract colors from an image as a human would do.", + "keywords": ["image", "color", "extract", "palette", "human"], + "homepage": "https://github.com/thephpleague/color-extractor", + "license": "MIT", + "replace": { + "matthecat/colorextractor": "*" + }, + "authors": [ + { + "name": "Mathieu Lechat", + "email": "math.lechat@gmail.com", + "homepage": "http://matthecat.com", + "role": "Developer" + } + ], + "require": { + "php": ">=5.4.0", + "ext-gd": "*" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "~2", + "phpunit/phpunit": "~5" + }, + "autoload": { + "psr-4": { + "": "src" + } + } +} diff --git a/vendor/league/color-extractor/tests/League/ColorExtractor/Test/PaletteTest.php b/vendor/league/color-extractor/tests/League/ColorExtractor/Test/PaletteTest.php new file mode 100644 index 000000000..c9a8eeb8c --- /dev/null +++ b/vendor/league/color-extractor/tests/League/ColorExtractor/Test/PaletteTest.php @@ -0,0 +1,67 @@ +jpegPath)); + $colors = $extractor->extract(1); + + $this->assertInternalType('array', $colors); + $this->assertCount(1, $colors); + $this->assertEquals(15985688, $colors[0]); + } + + public function testGifExtractSingleColor() + { + $extractor = new ColorExtractor(Palette::fromFilename($this->gifPath)); + $colors = $extractor->extract(1); + + $this->assertInternalType('array', $colors); + $this->assertCount(1, $colors); + $this->assertEquals(12022491, $colors[0]); + } + + public function testPngExtractSingleColor() + { + $extractor = new ColorExtractor(Palette::fromFilename($this->pngPath)); + $colors = $extractor->extract(1); + + $this->assertInternalType('array', $colors); + $this->assertCount(1, $colors); + $this->assertEquals(14024704, $colors[0]); + } + + public function testJpegExtractMultipleColors() + { + $extractor = new ColorExtractor(Palette::fromFilename($this->pngPath)); + $numColors = 3; + $colors = $extractor->extract($numColors); + + $this->assertInternalType('array', $colors); + $this->assertCount($numColors, $colors); + $this->assertEquals($colors, [14024704, 3407872, 7111569]); + } + + public function testTransparencyHandling() + { + $this->assertCount(0, Palette::fromFilename($this->transparentPngPath)); + + $whiteBackgroundPalette = Palette::fromFilename($this->transparentPngPath, Color::fromHexToInt('#FFFFFF')); + $this->assertEquals(iterator_to_array($whiteBackgroundPalette), [Color::fromHexToInt('#FF8080') => 1]); + + $blackBackgroundPalette = Palette::fromFilename($this->transparentPngPath, Color::fromHexToInt('#000000')); + $this->assertEquals(iterator_to_array($blackBackgroundPalette), [Color::fromHexToInt('#7E0000') => 1]); + } +} diff --git a/vendor/league/color-extractor/tests/assets/google.png b/vendor/league/color-extractor/tests/assets/google.png new file mode 100644 index 000000000..c9a210d93 Binary files /dev/null and b/vendor/league/color-extractor/tests/assets/google.png differ diff --git a/vendor/league/color-extractor/tests/assets/red-transparent-50.png b/vendor/league/color-extractor/tests/assets/red-transparent-50.png new file mode 100644 index 000000000..fbec7f3b4 Binary files /dev/null and b/vendor/league/color-extractor/tests/assets/red-transparent-50.png differ diff --git a/vendor/league/color-extractor/tests/assets/test.gif b/vendor/league/color-extractor/tests/assets/test.gif new file mode 100644 index 000000000..5200badfa Binary files /dev/null and b/vendor/league/color-extractor/tests/assets/test.gif differ diff --git a/vendor/league/color-extractor/tests/assets/test.jpeg b/vendor/league/color-extractor/tests/assets/test.jpeg new file mode 100644 index 000000000..4f68aead6 Binary files /dev/null and b/vendor/league/color-extractor/tests/assets/test.jpeg differ diff --git a/vendor/league/color-extractor/tests/assets/test.png b/vendor/league/color-extractor/tests/assets/test.png new file mode 100644 index 000000000..25c88fd7e Binary files /dev/null and b/vendor/league/color-extractor/tests/assets/test.png differ diff --git a/vendor/league/color-extractor/tests/bootstrap.php b/vendor/league/color-extractor/tests/bootstrap.php new file mode 100644 index 000000000..00f57feb9 --- /dev/null +++ b/vendor/league/color-extractor/tests/bootstrap.php @@ -0,0 +1,4 @@ +addPsr4('', __DIR__); diff --git a/vendor/league/oauth1-client/.gitignore b/vendor/league/oauth1-client/.gitignore deleted file mode 100644 index 783a2df0a..000000000 --- a/vendor/league/oauth1-client/.gitignore +++ /dev/null @@ -1,7 +0,0 @@ -/build -/vendor -/composer.lock -/coverage.xml -/.phpunit.result.cache -/.php_cs.cache -.DS_Store diff --git a/vendor/league/oauth1-client/.php_cs.dist b/vendor/league/oauth1-client/.php_cs.dist deleted file mode 100644 index c7c4df1ba..000000000 --- a/vendor/league/oauth1-client/.php_cs.dist +++ /dev/null @@ -1,29 +0,0 @@ -in([__DIR__ . '/src', __DIR__ . '/tests']); - -return PhpCsFixer\Config::create() - ->setRules([ - '@PSR2' => true, - 'array_syntax' => ['syntax' => 'short'], - 'binary_operator_spaces' => true, - 'blank_line_before_return' => true, - 'cast_spaces' => true, - 'concat_space' => ['spacing' => 'one'], - 'no_singleline_whitespace_before_semicolons' => true, - 'not_operator_with_space' => true, - 'ordered_imports' => true, - 'phpdoc_align' => true, - 'phpdoc_indent' => true, - 'phpdoc_no_access' => true, - 'phpdoc_no_alias_tag' => true, - 'phpdoc_no_package' => true, - 'phpdoc_scalar' => true, - 'phpdoc_separation' => true, - 'phpdoc_summary' => true, - 'phpdoc_to_comment' => true, - 'phpdoc_trim' => true, - 'single_blank_line_at_eof' => true, - 'ternary_operator_spaces' => true, - ]) - ->setFinder($finder); \ No newline at end of file diff --git a/vendor/league/oauth1-client/.scrutinizer.yml b/vendor/league/oauth1-client/.scrutinizer.yml deleted file mode 100644 index 1d352e5bf..000000000 --- a/vendor/league/oauth1-client/.scrutinizer.yml +++ /dev/null @@ -1,35 +0,0 @@ -filter: - excluded_paths: [tests/*] -checks: - php: - code_rating: true - remove_extra_empty_lines: true - remove_php_closing_tag: true - remove_trailing_whitespace: true - fix_use_statements: - remove_unused: true - preserve_multiple: false - preserve_blanklines: true - order_alphabetically: true - fix_php_opening_tag: true - fix_linefeed: true - fix_line_ending: true - fix_identation_4spaces: true - fix_doc_comments: true -tools: - external_code_coverage: - timeout: 600 - runs: 4 - php_analyzer: true - php_code_coverage: false - php_code_sniffer: - config: - standard: PSR2 - filter: - paths: ['src'] - php_loc: - enabled: true - excluded_dirs: [vendor, tests] - php_cpd: - enabled: true - excluded_dirs: [vendor, tests] diff --git a/vendor/league/oauth1-client/.travis.yml b/vendor/league/oauth1-client/.travis.yml deleted file mode 100644 index 3bd1b4e95..000000000 --- a/vendor/league/oauth1-client/.travis.yml +++ /dev/null @@ -1,57 +0,0 @@ -language: php - -matrix: - include: - - php: 7.1 - dist: bionic - env: COMPOSER_OPTS="" - - php: 7.1 - dist: bionic - env: COMPOSER_OPTS="--prefer-lowest" - - php: 7.2 - dist: bionic - env: COMPOSER_OPTS="" - - php: 7.2 - dist: bionic - env: COMPOSER_OPTS="--prefer-lowest" - - php: 7.3 - dist: bionic - env: COMPOSER_OPTS="" - - php: 7.3 - dist: bionic - env: COMPOSER_OPTS="--prefer-lowest" - - php: 7.4 - dist: bionic - env: COMPOSER_OPTS="" - - php: 7.4 - dist: bionic - env: COMPOSER_OPTS="--prefer-lowest" - - php: 8.0 - dist: bionic - env: COMPOSER_OPTS="" - - php: 8.0 - dist: bionic - env: COMPOSER_OPTS="--prefer-lowest" - - php: nightly - dist: bionic - env: COMPOSER_OPTS="--ignore-platform-reqs" - - php: nightly - dist: bionic - env: COMPOSER_OPTS="--ignore-platform-reqs --prefer-lowest" - allow_failures: - - php: nightly - env: COMPOSER_OPTS="--ignore-platform-reqs" - - php: nightly - env: COMPOSER_OPTS="--ignore-platform-reqs --prefer-lowest" - -install: - - travis_retry composer update --prefer-dist $COMPOSER_OPTS - -script: - - composer php-cs-fixer:lint - - composer test:unit - - composer analyze - -after_script: - - wget https://scrutinizer-ci.com/ocular.phar - - php ocular.phar code-coverage:upload --format=php-clover coverage.xml \ No newline at end of file diff --git a/vendor/league/oauth1-client/CHANGELOG.md b/vendor/league/oauth1-client/CHANGELOG.md deleted file mode 100644 index ffb73d7c4..000000000 --- a/vendor/league/oauth1-client/CHANGELOG.md +++ /dev/null @@ -1,20 +0,0 @@ -# Changelog - -## v1.9.0 - -- Adds support for PHP 8.0. -- Allows optional authorization URL parameters to be passed. - -## v1.8.2 - -- Fixes an issue where the base string used to generate signatures did not account for non-standard ports. - -## v1.8.1 - -- Reverts the public API changes introduced in v1.8.0 where language level type declarations and return types that were introduced caused inheritence to break. -- Fixes a Composer warning with relation to autoloading test files. - -## v1.8.0 - -- We allow installation with Guzzle 6 **or** Guzzle 7. -- The minimum PHP version has been bumped from PHP 5.6 to 7.1. diff --git a/vendor/league/oauth1-client/CONDUCT.md b/vendor/league/oauth1-client/CONDUCT.md deleted file mode 100644 index 6ff94ca3a..000000000 --- a/vendor/league/oauth1-client/CONDUCT.md +++ /dev/null @@ -1,22 +0,0 @@ -# Contributor Code of Conduct - -As contributors and maintainers of this project, and in the interest of fostering an open and welcoming community, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting pull requests or patches, and other activities. - -We are committed to making participation in this project a harassment-free experience for everyone, regardless of level of experience, gender, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, ethnicity, age, religion, or nationality. - -Examples of unacceptable behavior by participants include: - -* The use of sexualized language or imagery -* Personal attacks -* Trolling or insulting/derogatory comments -* Public or private harassment -* Publishing other's private information, such as physical or electronic addresses, without explicit permission -* Other unethical or unprofessional conduct. - -Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct. By adopting this Code of Conduct, project maintainers commit themselves to fairly and consistently applying these principles to every aspect of managing this project. Project maintainers who do not follow or enforce the Code of Conduct may be permanently removed from the project team. - -This code of conduct applies both within project spaces and in public spaces when an individual is representing the project or its community in a direct capacity. Personal views, beliefs and values of individuals do not necessarily reflect those of the organisation or affiliated individuals and organisations. - -Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by opening an issue or contacting one or more of the project maintainers. - -This Code of Conduct is adapted from the [Contributor Covenant](http://contributor-covenant.org), version 1.2.0, available at [http://contributor-covenant.org/version/1/2/0/](http://contributor-covenant.org/version/1/2/0/) diff --git a/vendor/league/oauth1-client/CONTRIBUTING.md b/vendor/league/oauth1-client/CONTRIBUTING.md deleted file mode 100644 index 576bb1f35..000000000 --- a/vendor/league/oauth1-client/CONTRIBUTING.md +++ /dev/null @@ -1,32 +0,0 @@ -# Contributing - -Contributions are **welcome** and will be fully **credited**. - -We accept contributions via Pull Requests on [Github](https://github.com/thephpleague/oauth1-client). - - -## Pull Requests - -- **[PSR-2 Coding Standard](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md)** - The easiest way to apply the conventions is to install [PHP Code Sniffer](http://pear.php.net/package/PHP_CodeSniffer). - -- **Add tests!** - Your patch won't be accepted if it doesn't have tests. - -- **Document any change in behaviour** - Make sure the README and any other relevant documentation are kept up-to-date. - -- **Consider our release cycle** - We try to follow semver. Randomly breaking public APIs is not an option. - -- **Create topic branches** - Don't ask us to pull from your master branch. - -- **One pull request per feature** - If you want to do more than one thing, send multiple pull requests. - -- **Send coherent history** - Make sure each individual commit in your pull request is meaningful. If you had to make multiple intermediate commits while developing, please squash them before submitting. - - -## Running Tests - -``` bash -$ phpunit -``` - - -**Happy coding**! diff --git a/vendor/league/oauth1-client/LICENSE b/vendor/league/oauth1-client/LICENSE deleted file mode 100644 index 922a51418..000000000 --- a/vendor/league/oauth1-client/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2013 Ben Corlett - -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. diff --git a/vendor/league/oauth1-client/README.md b/vendor/league/oauth1-client/README.md deleted file mode 100644 index a6c70dcfd..000000000 --- a/vendor/league/oauth1-client/README.md +++ /dev/null @@ -1,264 +0,0 @@ -# OAuth 1.0 Client - -[![Latest Stable Version](https://img.shields.io/github/release/thephpleague/oauth1-client.svg?style=flat-square)](https://github.com/thephpleague/oauth1-client/releases) -[![Software License](https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat-square)](LICENSE.md) -[![Build Status](https://img.shields.io/travis/thephpleague/oauth1-client/master.svg?style=flat-square&1)](https://travis-ci.org/thephpleague/oauth1-client) -[![Coverage Status](https://img.shields.io/scrutinizer/coverage/g/thephpleague/oauth1-client.svg?style=flat-square)](https://scrutinizer-ci.com/g/thephpleague/oauth1-client/code-structure) -[![Quality Score](https://img.shields.io/scrutinizer/g/thephpleague/oauth1-client.svg?style=flat-square)](https://scrutinizer-ci.com/g/thephpleague/oauth1-client) -[![Total Downloads](https://img.shields.io/packagist/dt/league/oauth1-client.svg?style=flat-square)](https://packagist.org/packages/thephpleague/oauth1-client) - -OAuth 1 Client is an OAuth [RFC 5849 standards-compliant](http://tools.ietf.org/html/rfc5849) library for authenticating against OAuth 1 servers. - -It has built in support for: - -- Bitbucket -- Magento -- Trello -- Tumblr -- Twitter -- Uservoice -- Xing - -Adding support for other providers is trivial. The library requires PHP 7.1+ and is PSR-2 compatible. - -### Third-Party Providers - -If you would like to support other providers, please make them available as a Composer package, then link to them -below. - -These providers allow integration with other providers not supported by `oauth1-client`. They may require an older version -so please help them out with a pull request if you notice this. - -- [Intuit](https://packagist.org/packages/wheniwork/oauth1-intuit) -- [500px](https://packagist.org/packages/mechant/oauth1-500px) -- [Etsy](https://packagist.org/packages/y0lk/oauth1-etsy) -- [Xero](https://packagist.org/packages/Invoiced/oauth1-xero) -- [Garmin](https://packagist.org/packages/techgyani/garmin-wellness) -- [Goodreads](https://packagist.org/packages/netgalley/oauth1-goodreads) - -#### Terminology (as per the RFC 5849 specification): - - client - An HTTP client (per [RFC2616]) capable of making OAuth- - authenticated requests (Section 3). - - server - An HTTP server (per [RFC2616]) capable of accepting OAuth- - authenticated requests (Section 3). - - protected resource - An access-restricted resource that can be obtained from the - server using an OAuth-authenticated request (Section 3). - - resource owner - An entity capable of accessing and controlling protected - resources by using credentials to authenticate with the server. - - credentials - Credentials are a pair of a unique identifier and a matching - shared secret. OAuth defines three classes of credentials: - client, temporary, and token, used to identify and authenticate - the client making the request, the authorization request, and - the access grant, respectively. - - token - A unique identifier issued by the server and used by the client - to associate authenticated requests with the resource owner - whose authorization is requested or has been obtained by the - client. Tokens have a matching shared-secret that is used by - the client to establish its ownership of the token, and its - authority to represent the resource owner. - - The original community specification used a somewhat different - terminology that maps to this specifications as follows (original - community terms provided on left): - - Consumer: client - - Service Provider: server - - User: resource owner - - Consumer Key and Secret: client credentials - - Request Token and Secret: temporary credentials - - Access Token and Secret: token credentials - - -## Install - -Via Composer - -```shell -$ composer require league/oauth1-client -``` - - -## Usage - -### Bitbucket - -```php -$server = new League\OAuth1\Client\Server\Bitbucket([ - 'identifier' => 'your-identifier', - 'secret' => 'your-secret', - 'callback_uri' => "http://your-callback-uri/", -]); -``` - -### Trello - -```php -$server = new League\OAuth1\Client\Server\Trello([ - 'identifier' => 'your-identifier', - 'secret' => 'your-secret', - 'callback_uri' => 'http://your-callback-uri/', - 'name' => 'your-application-name', // optional, defaults to null - 'expiration' => 'your-application-expiration', // optional ('never', '1day', '2days'), defaults to '1day' - 'scope' => 'your-application-scope' // optional ('read', 'read,write'), defaults to 'read' -]); -``` - -### Tumblr - -```php -$server = new League\OAuth1\Client\Server\Tumblr([ - 'identifier' => 'your-identifier', - 'secret' => 'your-secret', - 'callback_uri' => "http://your-callback-uri/", -]); -``` - -### Twitter - -```php -$server = new League\OAuth1\Client\Server\Twitter([ - 'identifier' => 'your-identifier', - 'secret' => 'your-secret', - 'callback_uri' => "http://your-callback-uri/", -]); -``` - -### Xing - -```php -$server = new League\OAuth1\Client\Server\Xing([ - 'identifier' => 'your-consumer-key', - 'secret' => 'your-consumer-secret', - 'callback_uri' => "http://your-callback-uri/", -]); -``` - -### Showing a Login Button - -To begin, it's advisable that you include a login button on your website. Most servers (Twitter, Tumblr etc) have resources available for making buttons that are familiar to users. Some servers actually require you use their buttons as part of their terms. - -```html -Login With Twitter -``` - -### Retrieving Temporary Credentials - -The first step to authenticating with OAuth 1 is to retrieve temporary credentials. These have been referred to as **request tokens** in earlier versions of OAuth 1. - -To do this, we'll retrieve and store temporary credentials in the session, and redirect the user to the server: - -```php -// Retrieve temporary credentials -$temporaryCredentials = $server->getTemporaryCredentials(); - -// Store credentials in the session, we'll need them later -$_SESSION['temporary_credentials'] = serialize($temporaryCredentials); -session_write_close(); - -// Second part of OAuth 1.0 authentication is to redirect the -// resource owner to the login screen on the server. -$server->authorize($temporaryCredentials); -``` - -The user will be redirected to the familiar login screen on the server, where they will login to their account and authorise your app to access their data. - -### Retrieving Token Credentials - -Once the user has authenticated (or denied) your application, they will be redirected to the `callback_uri` which you specified when creating the server. - -> Note, some servers (such as Twitter) require that the callback URI you specify when authenticating matches what you registered with their app. This is to stop a potential third party impersonating you. This is actually part of the protocol however some servers choose to ignore this. -> -> Because of this, we actually require you specify a callback URI for all servers, regardless of whether the server requires it or not. This is good practice. - -You'll need to handle when the user is redirected back. This will involve retrieving token credentials, which you may then use to make calls to the server on behalf of the user. These have been referred to as **access tokens** in earlier versions of OAuth 1. - -```php -if (isset($_GET['oauth_token']) && isset($_GET['oauth_verifier'])) { - // Retrieve the temporary credentials we saved before - $temporaryCredentials = unserialize($_SESSION['temporary_credentials']); - - // We will now retrieve token credentials from the server - $tokenCredentials = $server->getTokenCredentials($temporaryCredentials, $_GET['oauth_token'], $_GET['oauth_verifier']); -} -``` - -Now, you may choose to do what you need with the token credentials. You may store them in a database, in the session, or use them as one-off and then forget about them. - -All credentials, (`client credentials`, `temporary credentials` and `token credentials`) all implement `League\OAuth1\Client\Credentials\CredentialsInterface` and have two sets of setters and getters exposed: - -```php -var_dump($tokenCredentials->getIdentifier()); -var_dump($tokenCredentials->getSecret()); -``` - -In earlier versions of OAuth 1, the token credentials identifier and token credentials secret were referred to as **access token** and **access token secret**. Don't be scared by the new terminology here - they are the same. This package is using the exact terminology in the RFC 5849 OAuth 1 standard. - -> Twitter will send back an error message in the `denied` query string parameter, allowing you to provide feedback. Some servers do not send back an error message, but rather do not provide the successful `oauth_token` and `oauth_verifier` parameters. - -### Accessing User Information - -Now you have token credentials stored somewhere, you may use them to make calls against the server, as an authenticated user. - -While this package is not intended to be a wrapper for every server's API, it does include basic methods that you may use to retrieve limited information. An example of where this may be useful is if you are using social logins, you only need limited information to confirm who the user is. - -The four exposed methods are: - -```php -// User is an instance of League\OAuth1\Client\Server\User -$user = $server->getUserDetails($tokenCredentials); - -// UID is a string / integer unique representation of the user -$uid = $server->getUserUid($tokenCredentials); - -// Email is either a string or null (as some providers do not supply this data) -$email = $server->getUserEmail($tokenCredentials); - -// Screen name is also known as a username (Twitter handle etc) -$screenName = $server->getUserScreenName($tokenCredentials); -``` - -> `League\OAuth1\Client\Server\User` exposes a number of default public properties and also stores any additional data in an extra array - `$user->extra`. You may also iterate over a user's properties as if it was an array, `foreach ($user as $key => $value)`. - -## Examples - -Examples may be found under the [resources/examples](https://github.com/thephpleague/oauth1-client/tree/master/resources/examples) directory, which take the usage instructions here and go into a bit more depth. They are working examples that would only you substitute in your client credentials to have working. - -## Testing - -``` bash -$ phpunit -``` - - -## Contributing - -Please see [CONTRIBUTING](https://github.com/thephpleague/oauth1-client/blob/master/CONTRIBUTING.md) for details. - - -## Credits - -- [Ben Corlett](https://github.com/bencorlett) -- [Steven Maguire](https://github.com/stevenmaguire) -- [All Contributors](https://github.com/thephpleague/oauth1-client/contributors) - - -## License - -The MIT License (MIT). Please see [License File](https://github.com/thephpleague/oauth1-client/blob/master/LICENSE) for more information. diff --git a/vendor/league/oauth1-client/composer.json b/vendor/league/oauth1-client/composer.json deleted file mode 100644 index 59e8ffc68..000000000 --- a/vendor/league/oauth1-client/composer.json +++ /dev/null @@ -1,65 +0,0 @@ -{ - "name": "league/oauth1-client", - "description": "OAuth 1.0 Client Library", - "license": "MIT", - "require": { - "php": ">=7.1||>=8.0", - "ext-json": "*", - "ext-openssl": "*", - "guzzlehttp/guzzle": "^6.0|^7.0" - }, - "require-dev": { - "ext-simplexml": "*", - "phpunit/phpunit": "^7.5||9.5", - "mockery/mockery": "^1.3.3", - "phpstan/phpstan": "^0.12.42", - "friendsofphp/php-cs-fixer": "^2.17" - }, - "scripts": { - "analyze": "vendor/bin/phpstan analyse -l 6 src/", - "php-cs-fixer:lint": "PHP_CS_FIXER_IGNORE_ENV=1 vendor/bin/php-cs-fixer fix --verbose --dry-run", - "php-cs-fixer:format": "PHP_CS_FIXER_IGNORE_ENV=1 vendor/bin/php-cs-fixer fix", - "test:unit": "vendor/bin/phpunit --coverage-text --coverage-clover coverage.xml" - }, - "suggest": { - "ext-simplexml": "For decoding XML-based responses." - }, - "keywords": [ - "oauth", - "oauth1", - "authorization", - "authentication", - "idp", - "identity", - "sso", - "single sign on", - "bitbucket", - "trello", - "tumblr", - "twitter" - ], - "authors": [ - { - "name": "Ben Corlett", - "email": "bencorlett@me.com", - "homepage": "http://www.webcomm.com.au", - "role": "Developer" - } - ], - "autoload": { - "psr-4": { - "League\\OAuth1\\Client\\": "src/" - } - }, - "autoload-dev": { - "psr-4": { - "League\\OAuth1\\Client\\Tests\\": "tests/" - } - }, - "extra": { - "branch-alias": { - "dev-master": "1.0-dev", - "dev-develop": "2.0-dev" - } - } -} diff --git a/vendor/league/oauth1-client/phpstan.neon b/vendor/league/oauth1-client/phpstan.neon deleted file mode 100644 index 90f89d365..000000000 --- a/vendor/league/oauth1-client/phpstan.neon +++ /dev/null @@ -1,11 +0,0 @@ -parameters: - checkMissingIterableValueType: false - checkGenericClassInNonGenericObjectType: false - ignoreErrors: - - - message: '#has unknown class OpenSSLAsymmetricKey as its type#' - path: src/Credentials/RsaClientCredentials.php - - - message: '#invalid type OpenSSLAsymmetricKey#' - path: src/Credentials/RsaClientCredentials.php - reportUnmatchedIgnoredErrors: false \ No newline at end of file diff --git a/vendor/league/oauth1-client/phpunit.php b/vendor/league/oauth1-client/phpunit.php deleted file mode 100644 index 46bb1e3d3..000000000 --- a/vendor/league/oauth1-client/phpunit.php +++ /dev/null @@ -1,5 +0,0 @@ - - - - - ./tests - - - - - ./src - - - - - - - diff --git a/vendor/league/oauth1-client/resources/examples/tumblr.php b/vendor/league/oauth1-client/resources/examples/tumblr.php deleted file mode 100644 index 236914a7d..000000000 --- a/vendor/league/oauth1-client/resources/examples/tumblr.php +++ /dev/null @@ -1,87 +0,0 @@ - 'your-identifier', - 'secret' => 'your-secret', - 'callback_uri' => "http://your-callback-uri/", -)); - -// Start session -session_start(); - -// Step 4 -if (isset($_GET['user'])) { - - // Check somebody hasn't manually entered this URL in, - // by checking that we have the token credentials in - // the session. - if ( ! isset($_SESSION['token_credentials'])) { - echo 'No token credentials.'; - exit(1); - } - - // Retrieve our token credentials. From here, it's play time! - $tokenCredentials = unserialize($_SESSION['token_credentials']); - - // // Below is an example of retrieving the identifier & secret - // // (formally known as access token key & secret in earlier - // // OAuth 1.0 specs). - // $identifier = $tokenCredentials->getIdentifier(); - // $secret = $tokenCredentials->getSecret(); - - // Some OAuth clients try to act as an API wrapper for - // the server and it's API. We don't. This is what you - // get - the ability to access basic information. If - // you want to get fancy, you should be grabbing a - // package for interacting with the APIs, by using - // the identifier & secret that this package was - // designed to retrieve for you. But, for fun, - // here's basic user information. - $user = $server->getUserDetails($tokenCredentials); - var_dump($user); - -// Step 3 -} elseif (isset($_GET['oauth_token']) && isset($_GET['oauth_verifier'])) { - - // Retrieve the temporary credentials from step 2 - $temporaryCredentials = unserialize($_SESSION['temporary_credentials']); - - // Third and final part to OAuth 1.0 authentication is to retrieve token - // credentials (formally known as access tokens in earlier OAuth 1.0 - // specs). - $tokenCredentials = $server->getTokenCredentials($temporaryCredentials, $_GET['oauth_token'], $_GET['oauth_verifier']); - - // Now, we'll store the token credentials and discard the temporary - // ones - they're irrelevant at this stage. - unset($_SESSION['temporary_credentials']); - $_SESSION['token_credentials'] = serialize($tokenCredentials); - session_write_close(); - - // Redirect to the user page - header("Location: http://{$_SERVER['HTTP_HOST']}/?user=user"); - exit; - -// Step 2 -} elseif (isset($_GET['go'])) { - - // First part of OAuth 1.0 authentication is retrieving temporary credentials. - // These identify you as a client to the server. - $temporaryCredentials = $server->getTemporaryCredentials(); - - // Store the credentials in the session. - $_SESSION['temporary_credentials'] = serialize($temporaryCredentials); - session_write_close(); - - // Second part of OAuth 1.0 authentication is to redirect the - // resource owner to the login screen on the server. - $server->authorize($temporaryCredentials); - -// Step 1 -} else { - - // Display link to start process - echo 'Login'; -} diff --git a/vendor/league/oauth1-client/resources/examples/twitter.php b/vendor/league/oauth1-client/resources/examples/twitter.php deleted file mode 100644 index 676def2b4..000000000 --- a/vendor/league/oauth1-client/resources/examples/twitter.php +++ /dev/null @@ -1,91 +0,0 @@ - 'your-identifier', - 'secret' => 'your-secret', - 'callback_uri' => "http://your-callback-uri/", -)); - -// Start session -session_start(); - -// Step 4 -if (isset($_GET['user'])) { - - // Check somebody hasn't manually entered this URL in, - // by checking that we have the token credentials in - // the session. - if ( ! isset($_SESSION['token_credentials'])) { - echo 'No token credentials.'; - exit(1); - } - - // Retrieve our token credentials. From here, it's play time! - $tokenCredentials = unserialize($_SESSION['token_credentials']); - - // // Below is an example of retrieving the identifier & secret - // // (formally known as access token key & secret in earlier - // // OAuth 1.0 specs). - // $identifier = $tokenCredentials->getIdentifier(); - // $secret = $tokenCredentials->getSecret(); - - // Some OAuth clients try to act as an API wrapper for - // the server and it's API. We don't. This is what you - // get - the ability to access basic information. If - // you want to get fancy, you should be grabbing a - // package for interacting with the APIs, by using - // the identifier & secret that this package was - // designed to retrieve for you. But, for fun, - // here's basic user information. - $user = $server->getUserDetails($tokenCredentials); - var_dump($user); - -// Step 3 -} elseif (isset($_GET['oauth_token']) && isset($_GET['oauth_verifier'])) { - - // Retrieve the temporary credentials from step 2 - $temporaryCredentials = unserialize($_SESSION['temporary_credentials']); - - // Third and final part to OAuth 1.0 authentication is to retrieve token - // credentials (formally known as access tokens in earlier OAuth 1.0 - // specs). - $tokenCredentials = $server->getTokenCredentials($temporaryCredentials, $_GET['oauth_token'], $_GET['oauth_verifier']); - - // Now, we'll store the token credentials and discard the temporary - // ones - they're irrelevant at this stage. - unset($_SESSION['temporary_credentials']); - $_SESSION['token_credentials'] = serialize($tokenCredentials); - session_write_close(); - - // Redirect to the user page - header("Location: http://{$_SERVER['HTTP_HOST']}/?user=user"); - exit; - -// Step 2.5 - denied request to authorize client -} elseif (isset($_GET['denied'])) { - echo 'Hey! You denied the client access to your Twitter account! If you did this by mistake, you should try again.'; - -// Step 2 -} elseif (isset($_GET['go'])) { - - // First part of OAuth 1.0 authentication is retrieving temporary credentials. - // These identify you as a client to the server. - $temporaryCredentials = $server->getTemporaryCredentials(); - - // Store the credentials in the session. - $_SESSION['temporary_credentials'] = serialize($temporaryCredentials); - session_write_close(); - - // Second part of OAuth 1.0 authentication is to redirect the - // resource owner to the login screen on the server. - $server->authorize($temporaryCredentials); - -// Step 1 -} else { - - // Display link to start process - echo 'Login'; -} diff --git a/vendor/league/oauth1-client/resources/examples/xing.php b/vendor/league/oauth1-client/resources/examples/xing.php deleted file mode 100644 index 2ac0bd435..000000000 --- a/vendor/league/oauth1-client/resources/examples/xing.php +++ /dev/null @@ -1,91 +0,0 @@ - 'your-identifier', - 'secret' => 'your-secret', - 'callback_uri' => "http://your-callback-uri/", -)); - -// Start session -session_start(); - -// Step 4 -if (isset($_GET['user'])) { - - // Check somebody hasn't manually entered this URL in, - // by checking that we have the token credentials in - // the session. - if ( ! isset($_SESSION['token_credentials'])) { - echo 'No token credentials.'; - exit(1); - } - - // Retrieve our token credentials. From here, it's play time! - $tokenCredentials = unserialize($_SESSION['token_credentials']); - - // // Below is an example of retrieving the identifier & secret - // // (formally known as access token key & secret in earlier - // // OAuth 1.0 specs). - // $identifier = $tokenCredentials->getIdentifier(); - // $secret = $tokenCredentials->getSecret(); - - // Some OAuth clients try to act as an API wrapper for - // the server and it's API. We don't. This is what you - // get - the ability to access basic information. If - // you want to get fancy, you should be grabbing a - // package for interacting with the APIs, by using - // the identifier & secret that this package was - // designed to retrieve for you. But, for fun, - // here's basic user information. - $user = $server->getUserDetails($tokenCredentials); - var_dump($user); - -// Step 3 -} elseif (isset($_GET['oauth_token']) && isset($_GET['oauth_verifier'])) { - - // Retrieve the temporary credentials from step 2 - $temporaryCredentials = unserialize($_SESSION['temporary_credentials']); - - // Third and final part to OAuth 1.0 authentication is to retrieve token - // credentials (formally known as access tokens in earlier OAuth 1.0 - // specs). - $tokenCredentials = $server->getTokenCredentials($temporaryCredentials, $_GET['oauth_token'], $_GET['oauth_verifier']); - - // Now, we'll store the token credentials and discard the temporary - // ones - they're irrelevant at this stage. - unset($_SESSION['temporary_credentials']); - $_SESSION['token_credentials'] = serialize($tokenCredentials); - session_write_close(); - - // Redirect to the user page - header("Location: http://{$_SERVER['HTTP_HOST']}/?user=user"); - exit; - -// Step 2.5 - denied request to authorize client -} elseif (isset($_GET['denied'])) { - echo 'Hey! You denied the client access to your Xing account! If you did this by mistake, you should try again.'; - -// Step 2 -} elseif (isset($_GET['go'])) { - - // First part of OAuth 1.0 authentication is retrieving temporary credentials. - // These identify you as a client to the server. - $temporaryCredentials = $server->getTemporaryCredentials(); - - // Store the credentials in the session. - $_SESSION['temporary_credentials'] = serialize($temporaryCredentials); - session_write_close(); - - // Second part of OAuth 1.0 authentication is to redirect the - // resource owner to the login screen on the server. - $server->authorize($temporaryCredentials); - -// Step 1 -} else { - - // Display link to start process - echo 'Login'; -} diff --git a/vendor/league/oauth1-client/rfc5849.txt b/vendor/league/oauth1-client/rfc5849.txt deleted file mode 100644 index 636814d8d..000000000 --- a/vendor/league/oauth1-client/rfc5849.txt +++ /dev/null @@ -1,2131 +0,0 @@ - - - - - - -Internet Engineering Task Force (IETF) E. Hammer-Lahav, Ed. -Request for Comments: 5849 April 2010 -Category: Informational -ISSN: 2070-1721 - - - The OAuth 1.0 Protocol - -Abstract - - OAuth provides a method for clients to access server resources on - behalf of a resource owner (such as a different client or an end- - user). It also provides a process for end-users to authorize third- - party access to their server resources without sharing their - credentials (typically, a username and password pair), using user- - agent redirections. - -Status of This Memo - - This document is not an Internet Standards Track specification; it is - published for informational purposes. - - This document is a product of the Internet Engineering Task Force - (IETF). It represents the consensus of the IETF community. It has - received public review and has been approved for publication by the - Internet Engineering Steering Group (IESG). Not all documents - approved by the IESG are a candidate for any level of Internet - Standard; see Section 2 of RFC 5741. - - Information about the current status of this document, any errata, - and how to provide feedback on it may be obtained at - http://www.rfc-editor.org/info/rfc5849. - -Copyright Notice - - Copyright (c) 2010 IETF Trust and the persons identified as the - document authors. All rights reserved. - - This document is subject to BCP 78 and the IETF Trust's Legal - Provisions Relating to IETF Documents - (http://trustee.ietf.org/license-info) in effect on the date of - publication of this document. Please review these documents - carefully, as they describe your rights and restrictions with respect - to this document. Code Components extracted from this document must - include Simplified BSD License text as described in Section 4.e of - the Trust Legal Provisions and are provided without warranty as - described in the Simplified BSD License. - - - - -Hammer-Lahav Informational [Page 1] - -RFC 5849 OAuth 1.0 April 2010 - - -Table of Contents - - 1. Introduction ....................................................3 - 1.1. Terminology ................................................4 - 1.2. Example ....................................................5 - 1.3. Notational Conventions .....................................7 - 2. Redirection-Based Authorization .................................8 - 2.1. Temporary Credentials ......................................9 - 2.2. Resource Owner Authorization ..............................10 - 2.3. Token Credentials .........................................12 - 3. Authenticated Requests .........................................14 - 3.1. Making Requests ...........................................14 - 3.2. Verifying Requests ........................................16 - 3.3. Nonce and Timestamp .......................................17 - 3.4. Signature .................................................18 - 3.4.1. Signature Base String ..............................18 - 3.4.2. HMAC-SHA1 ..........................................25 - 3.4.3. RSA-SHA1 ...........................................25 - 3.4.4. PLAINTEXT ..........................................26 - 3.5. Parameter Transmission ....................................26 - 3.5.1. Authorization Header ...............................27 - 3.5.2. Form-Encoded Body ..................................28 - 3.5.3. Request URI Query ..................................28 - 3.6. Percent Encoding ..........................................29 - 4. Security Considerations ........................................29 - 4.1. RSA-SHA1 Signature Method .................................29 - 4.2. Confidentiality of Requests ...............................30 - 4.3. Spoofing by Counterfeit Servers ...........................30 - 4.4. Proxying and Caching of Authenticated Content .............30 - 4.5. Plaintext Storage of Credentials ..........................30 - 4.6. Secrecy of the Client Credentials .........................31 - 4.7. Phishing Attacks ..........................................31 - 4.8. Scoping of Access Requests ................................31 - 4.9. Entropy of Secrets ........................................32 - 4.10. Denial-of-Service / Resource-Exhaustion Attacks ..........32 - 4.11. SHA-1 Cryptographic Attacks ..............................33 - 4.12. Signature Base String Limitations ........................33 - 4.13. Cross-Site Request Forgery (CSRF) ........................33 - 4.14. User Interface Redress ...................................34 - 4.15. Automatic Processing of Repeat Authorizations ............34 - 5. Acknowledgments ................................................35 - Appendix A. Differences from the Community Edition ...............36 - 6. References .....................................................37 - 6.1. Normative References ......................................37 - 6.2. Informative References ....................................38 - - - - - - -Hammer-Lahav Informational [Page 2] - -RFC 5849 OAuth 1.0 April 2010 - - -1. Introduction - - The OAuth protocol was originally created by a small community of web - developers from a variety of websites and other Internet services who - wanted to solve the common problem of enabling delegated access to - protected resources. The resulting OAuth protocol was stabilized at - version 1.0 in October 2007, and revised in June 2009 (Revision A) as - published at . - - This specification provides an informational documentation of OAuth - Core 1.0 Revision A, addresses several errata reported since that - time, and makes numerous editorial clarifications. While this - specification is not an item of the IETF's OAuth Working Group, which - at the time of writing is working on an OAuth version that can be - appropriate for publication on the standards track, it has been - transferred to the IETF for change control by authors of the original - work. - - In the traditional client-server authentication model, the client - uses its credentials to access its resources hosted by the server. - With the increasing use of distributed web services and cloud - computing, third-party applications require access to these server- - hosted resources. - - OAuth introduces a third role to the traditional client-server - authentication model: the resource owner. In the OAuth model, the - client (which is not the resource owner, but is acting on its behalf) - requests access to resources controlled by the resource owner, but - hosted by the server. In addition, OAuth allows the server to verify - not only the resource owner authorization, but also the identity of - the client making the request. - - OAuth provides a method for clients to access server resources on - behalf of a resource owner (such as a different client or an end- - user). It also provides a process for end-users to authorize third- - party access to their server resources without sharing their - credentials (typically, a username and password pair), using user- - agent redirections. - - For example, a web user (resource owner) can grant a printing service - (client) access to her private photos stored at a photo sharing - service (server), without sharing her username and password with the - printing service. Instead, she authenticates directly with the photo - sharing service which issues the printing service delegation-specific - credentials. - - - - - - -Hammer-Lahav Informational [Page 3] - -RFC 5849 OAuth 1.0 April 2010 - - - In order for the client to access resources, it first has to obtain - permission from the resource owner. This permission is expressed in - the form of a token and matching shared-secret. The purpose of the - token is to make it unnecessary for the resource owner to share its - credentials with the client. Unlike the resource owner credentials, - tokens can be issued with a restricted scope and limited lifetime, - and revoked independently. - - This specification consists of two parts. The first part defines a - redirection-based user-agent process for end-users to authorize - client access to their resources, by authenticating directly with the - server and provisioning tokens to the client for use with the - authentication method. The second part defines a method for making - authenticated HTTP [RFC2616] requests using two sets of credentials, - one identifying the client making the request, and a second - identifying the resource owner on whose behalf the request is being - made. - - The use of OAuth with any transport protocol other than [RFC2616] is - undefined. - -1.1. Terminology - - client - An HTTP client (per [RFC2616]) capable of making OAuth- - authenticated requests (Section 3). - - server - An HTTP server (per [RFC2616]) capable of accepting OAuth- - authenticated requests (Section 3). - - protected resource - An access-restricted resource that can be obtained from the - server using an OAuth-authenticated request (Section 3). - - resource owner - An entity capable of accessing and controlling protected - resources by using credentials to authenticate with the server. - - credentials - Credentials are a pair of a unique identifier and a matching - shared secret. OAuth defines three classes of credentials: - client, temporary, and token, used to identify and authenticate - the client making the request, the authorization request, and - the access grant, respectively. - - - - - - -Hammer-Lahav Informational [Page 4] - -RFC 5849 OAuth 1.0 April 2010 - - - token - A unique identifier issued by the server and used by the client - to associate authenticated requests with the resource owner - whose authorization is requested or has been obtained by the - client. Tokens have a matching shared-secret that is used by - the client to establish its ownership of the token, and its - authority to represent the resource owner. - - The original community specification used a somewhat different - terminology that maps to this specifications as follows (original - community terms provided on left): - - Consumer: client - - Service Provider: server - - User: resource owner - - Consumer Key and Secret: client credentials - - Request Token and Secret: temporary credentials - - Access Token and Secret: token credentials - -1.2. Example - - Jane (resource owner) has recently uploaded some private vacation - photos (protected resources) to her photo sharing site - 'photos.example.net' (server). She would like to use the - 'printer.example.com' website (client) to print one of these photos. - Typically, Jane signs into 'photos.example.net' using her username - and password. - - However, Jane does not wish to share her username and password with - the 'printer.example.com' website, which needs to access the photo in - order to print it. In order to provide its users with better - service, 'printer.example.com' has signed up for a set of - 'photos.example.net' client credentials ahead of time: - - Client Identifier - dpf43f3p2l4k3l03 - - Client Shared-Secret: - kd94hf93k423kf44 - - The 'printer.example.com' website has also configured its application - to use the protocol endpoints listed in the 'photos.example.net' API - documentation, which use the "HMAC-SHA1" signature method: - - - -Hammer-Lahav Informational [Page 5] - -RFC 5849 OAuth 1.0 April 2010 - - - Temporary Credential Request - https://photos.example.net/initiate - - Resource Owner Authorization URI: - https://photos.example.net/authorize - - Token Request URI: - https://photos.example.net/token - - Before 'printer.example.com' can ask Jane to grant it access to the - photos, it must first establish a set of temporary credentials with - 'photos.example.net' to identify the delegation request. To do so, - the client sends the following HTTPS [RFC2818] request to the server: - - POST /initiate HTTP/1.1 - Host: photos.example.net - Authorization: OAuth realm="Photos", - oauth_consumer_key="dpf43f3p2l4k3l03", - oauth_signature_method="HMAC-SHA1", - oauth_timestamp="137131200", - oauth_nonce="wIjqoS", - oauth_callback="http%3A%2F%2Fprinter.example.com%2Fready", - oauth_signature="74KNZJeDHnMBp0EMJ9ZHt%2FXKycU%3D" - - The server validates the request and replies with a set of temporary - credentials in the body of the HTTP response (line breaks are for - display purposes only): - - HTTP/1.1 200 OK - Content-Type: application/x-www-form-urlencoded - - oauth_token=hh5s93j4hdidpola&oauth_token_secret=hdhd0244k9j7ao03& - oauth_callback_confirmed=true - - The client redirects Jane's user-agent to the server's Resource Owner - Authorization endpoint to obtain Jane's approval for accessing her - private photos: - - https://photos.example.net/authorize?oauth_token=hh5s93j4hdidpola - - The server requests Jane to sign in using her username and password - and if successful, asks her to approve granting 'printer.example.com' - access to her private photos. Jane approves the request and her - user-agent is redirected to the callback URI provided by the client - in the previous request (line breaks are for display purposes only): - - http://printer.example.com/ready? - oauth_token=hh5s93j4hdidpola&oauth_verifier=hfdp7dh39dks9884 - - - -Hammer-Lahav Informational [Page 6] - -RFC 5849 OAuth 1.0 April 2010 - - - The callback request informs the client that Jane completed the - authorization process. The client then requests a set of token - credentials using its temporary credentials (over a secure Transport - Layer Security (TLS) channel): - - POST /token HTTP/1.1 - Host: photos.example.net - Authorization: OAuth realm="Photos", - oauth_consumer_key="dpf43f3p2l4k3l03", - oauth_token="hh5s93j4hdidpola", - oauth_signature_method="HMAC-SHA1", - oauth_timestamp="137131201", - oauth_nonce="walatlh", - oauth_verifier="hfdp7dh39dks9884", - oauth_signature="gKgrFCywp7rO0OXSjdot%2FIHF7IU%3D" - - The server validates the request and replies with a set of token - credentials in the body of the HTTP response: - - HTTP/1.1 200 OK - Content-Type: application/x-www-form-urlencoded - - oauth_token=nnch734d00sl2jdk&oauth_token_secret=pfkkdhi9sl3r4s00 - - With a set of token credentials, the client is now ready to request - the private photo: - - GET /photos?file=vacation.jpg&size=original HTTP/1.1 - Host: photos.example.net - Authorization: OAuth realm="Photos", - oauth_consumer_key="dpf43f3p2l4k3l03", - oauth_token="nnch734d00sl2jdk", - oauth_signature_method="HMAC-SHA1", - oauth_timestamp="137131202", - oauth_nonce="chapoH", - oauth_signature="MdpQcU8iPSUjWoN%2FUDMsK2sui9I%3D" - - The 'photos.example.net' server validates the request and responds - with the requested photo. 'printer.example.com' is able to continue - accessing Jane's private photos using the same set of token - credentials for the duration of Jane's authorization, or until Jane - revokes access. - -1.3. Notational Conventions - - The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", - "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this - document are to be interpreted as described in [RFC2119]. - - - -Hammer-Lahav Informational [Page 7] - -RFC 5849 OAuth 1.0 April 2010 - - -2. Redirection-Based Authorization - - OAuth uses tokens to represent the authorization granted to the - client by the resource owner. Typically, token credentials are - issued by the server at the resource owner's request, after - authenticating the resource owner's identity (usually using a - username and password). - - There are many ways in which a server can facilitate the provisioning - of token credentials. This section defines one such way, using HTTP - redirections and the resource owner's user-agent. This redirection- - based authorization method includes three steps: - - 1. The client obtains a set of temporary credentials from the server - (in the form of an identifier and shared-secret). The temporary - credentials are used to identify the access request throughout - the authorization process. - - 2. The resource owner authorizes the server to grant the client's - access request (identified by the temporary credentials). - - 3. The client uses the temporary credentials to request a set of - token credentials from the server, which will enable it to access - the resource owner's protected resources. - - The server MUST revoke the temporary credentials after being used - once to obtain the token credentials. It is RECOMMENDED that the - temporary credentials have a limited lifetime. Servers SHOULD enable - resource owners to revoke token credentials after they have been - issued to clients. - - In order for the client to perform these steps, the server needs to - advertise the URIs of the following three endpoints: - - Temporary Credential Request - The endpoint used by the client to obtain a set of temporary - credentials as described in Section 2.1. - - Resource Owner Authorization - The endpoint to which the resource owner is redirected to grant - authorization as described in Section 2.2. - - Token Request - The endpoint used by the client to request a set of token - credentials using the set of temporary credentials as described - in Section 2.3. - - - - - -Hammer-Lahav Informational [Page 8] - -RFC 5849 OAuth 1.0 April 2010 - - - The three URIs advertised by the server MAY include a query component - as defined by [RFC3986], Section 3, but if present, the query MUST - NOT contain any parameters beginning with the "oauth_" prefix, to - avoid conflicts with the protocol parameters added to the URIs when - used. - - The methods in which the server advertises and documents its three - endpoints are beyond the scope of this specification. Clients should - avoid making assumptions about the size of tokens and other server- - generated values, which are left undefined by this specification. In - addition, protocol parameters MAY include values that require - encoding when transmitted. Clients and servers should not make - assumptions about the possible range of their values. - -2.1. Temporary Credentials - - The client obtains a set of temporary credentials from the server by - making an authenticated (Section 3) HTTP "POST" request to the - Temporary Credential Request endpoint (unless the server advertises - another HTTP request method for the client to use). The client - constructs a request URI by adding the following REQUIRED parameter - to the request (in addition to the other protocol parameters, using - the same parameter transmission method): - - oauth_callback: An absolute URI back to which the server will - redirect the resource owner when the Resource Owner - Authorization step (Section 2.2) is completed. If - the client is unable to receive callbacks or a - callback URI has been established via other means, - the parameter value MUST be set to "oob" (case - sensitive), to indicate an out-of-band - configuration. - - Servers MAY specify additional parameters. - - When making the request, the client authenticates using only the - client credentials. The client MAY omit the empty "oauth_token" - protocol parameter from the request and MUST use the empty string as - the token secret value. - - Since the request results in the transmission of plain text - credentials in the HTTP response, the server MUST require the use of - a transport-layer mechanisms such as TLS or Secure Socket Layer (SSL) - (or a secure channel with equivalent protections). - - - - - - - -Hammer-Lahav Informational [Page 9] - -RFC 5849 OAuth 1.0 April 2010 - - - For example, the client makes the following HTTPS request: - - POST /request_temp_credentials HTTP/1.1 - Host: server.example.com - Authorization: OAuth realm="Example", - oauth_consumer_key="jd83jd92dhsh93js", - oauth_signature_method="PLAINTEXT", - oauth_callback="http%3A%2F%2Fclient.example.net%2Fcb%3Fx%3D1", - oauth_signature="ja893SD9%26" - - The server MUST verify (Section 3.2) the request and if valid, - respond back to the client with a set of temporary credentials (in - the form of an identifier and shared-secret). The temporary - credentials are included in the HTTP response body using the - "application/x-www-form-urlencoded" content type as defined by - [W3C.REC-html40-19980424] with a 200 status code (OK). - - The response contains the following REQUIRED parameters: - - oauth_token - The temporary credentials identifier. - - oauth_token_secret - The temporary credentials shared-secret. - - oauth_callback_confirmed - MUST be present and set to "true". The parameter is used to - differentiate from previous versions of the protocol. - - Note that even though the parameter names include the term 'token', - these credentials are not token credentials, but are used in the next - two steps in a similar manner to token credentials. - - For example (line breaks are for display purposes only): - - HTTP/1.1 200 OK - Content-Type: application/x-www-form-urlencoded - - oauth_token=hdk48Djdsa&oauth_token_secret=xyz4992k83j47x0b& - oauth_callback_confirmed=true - -2.2. Resource Owner Authorization - - Before the client requests a set of token credentials from the - server, it MUST send the user to the server to authorize the request. - The client constructs a request URI by adding the following REQUIRED - query parameter to the Resource Owner Authorization endpoint URI: - - - - -Hammer-Lahav Informational [Page 10] - -RFC 5849 OAuth 1.0 April 2010 - - - oauth_token - The temporary credentials identifier obtained in Section 2.1 in - the "oauth_token" parameter. Servers MAY declare this - parameter as OPTIONAL, in which case they MUST provide a way - for the resource owner to indicate the identifier through other - means. - - Servers MAY specify additional parameters. - - The client directs the resource owner to the constructed URI using an - HTTP redirection response, or by other means available to it via the - resource owner's user-agent. The request MUST use the HTTP "GET" - method. - - For example, the client redirects the resource owner's user-agent to - make the following HTTPS request: - - GET /authorize_access?oauth_token=hdk48Djdsa HTTP/1.1 - Host: server.example.com - - The way in which the server handles the authorization request, - including whether it uses a secure channel such as TLS/SSL is beyond - the scope of this specification. However, the server MUST first - verify the identity of the resource owner. - - When asking the resource owner to authorize the requested access, the - server SHOULD present to the resource owner information about the - client requesting access based on the association of the temporary - credentials with the client identity. When displaying any such - information, the server SHOULD indicate if the information has been - verified. - - After receiving an authorization decision from the resource owner, - the server redirects the resource owner to the callback URI if one - was provided in the "oauth_callback" parameter or by other means. - - To make sure that the resource owner granting access is the same - resource owner returning back to the client to complete the process, - the server MUST generate a verification code: an unguessable value - passed to the client via the resource owner and REQUIRED to complete - the process. The server constructs the request URI by adding the - following REQUIRED parameters to the callback URI query component: - - oauth_token - The temporary credentials identifier received from the client. - - - - - - -Hammer-Lahav Informational [Page 11] - -RFC 5849 OAuth 1.0 April 2010 - - - oauth_verifier - The verification code. - - If the callback URI already includes a query component, the server - MUST append the OAuth parameters to the end of the existing query. - - For example, the server redirects the resource owner's user-agent to - make the following HTTP request: - - GET /cb?x=1&oauth_token=hdk48Djdsa&oauth_verifier=473f82d3 HTTP/1.1 - Host: client.example.net - - If the client did not provide a callback URI, the server SHOULD - display the value of the verification code, and instruct the resource - owner to manually inform the client that authorization is completed. - If the server knows a client to be running on a limited device, it - SHOULD ensure that the verifier value is suitable for manual entry. - -2.3. Token Credentials - - The client obtains a set of token credentials from the server by - making an authenticated (Section 3) HTTP "POST" request to the Token - Request endpoint (unless the server advertises another HTTP request - method for the client to use). The client constructs a request URI - by adding the following REQUIRED parameter to the request (in - addition to the other protocol parameters, using the same parameter - transmission method): - - oauth_verifier - The verification code received from the server in the previous - step. - - When making the request, the client authenticates using the client - credentials as well as the temporary credentials. The temporary - credentials are used as a substitute for token credentials in the - authenticated request and transmitted using the "oauth_token" - parameter. - - Since the request results in the transmission of plain text - credentials in the HTTP response, the server MUST require the use of - a transport-layer mechanism such as TLS or SSL (or a secure channel - with equivalent protections). - - - - - - - - - -Hammer-Lahav Informational [Page 12] - -RFC 5849 OAuth 1.0 April 2010 - - - For example, the client makes the following HTTPS request: - - POST /request_token HTTP/1.1 - Host: server.example.com - Authorization: OAuth realm="Example", - oauth_consumer_key="jd83jd92dhsh93js", - oauth_token="hdk48Djdsa", - oauth_signature_method="PLAINTEXT", - oauth_verifier="473f82d3", - oauth_signature="ja893SD9%26xyz4992k83j47x0b" - - The server MUST verify (Section 3.2) the validity of the request, - ensure that the resource owner has authorized the provisioning of - token credentials to the client, and ensure that the temporary - credentials have not expired or been used before. The server MUST - also verify the verification code received from the client. If the - request is valid and authorized, the token credentials are included - in the HTTP response body using the - "application/x-www-form-urlencoded" content type as defined by - [W3C.REC-html40-19980424] with a 200 status code (OK). - - The response contains the following REQUIRED parameters: - - oauth_token - The token identifier. - - oauth_token_secret - The token shared-secret. - - For example: - - HTTP/1.1 200 OK - Content-Type: application/x-www-form-urlencoded - - oauth_token=j49ddk933skd9dks&oauth_token_secret=ll399dj47dskfjdk - - The server must retain the scope, duration, and other attributes - approved by the resource owner, and enforce these restrictions when - receiving a client request made with the token credentials issued. - - Once the client receives and stores the token credentials, it can - proceed to access protected resources on behalf of the resource owner - by making authenticated requests (Section 3) using the client - credentials together with the token credentials received. - - - - - - - -Hammer-Lahav Informational [Page 13] - -RFC 5849 OAuth 1.0 April 2010 - - -3. Authenticated Requests - - The HTTP authentication methods defined by [RFC2617] enable clients - to make authenticated HTTP requests. Clients using these methods - gain access to protected resources by using their credentials - (typically, a username and password pair), which allow the server to - verify their authenticity. Using these methods for delegation - requires the client to assume the role of the resource owner. - - OAuth provides a method designed to include two sets of credentials - with each request, one to identify the client, and another to - identify the resource owner. Before a client can make authenticated - requests on behalf of the resource owner, it must obtain a token - authorized by the resource owner. Section 2 provides one such method - through which the client can obtain a token authorized by the - resource owner. - - The client credentials take the form of a unique identifier and an - associated shared-secret or RSA key pair. Prior to making - authenticated requests, the client establishes a set of credentials - with the server. The process and requirements for provisioning these - are outside the scope of this specification. Implementers are urged - to consider the security ramifications of using client credentials, - some of which are described in Section 4.6. - - Making authenticated requests requires prior knowledge of the - server's configuration. OAuth includes multiple methods for - transmitting protocol parameters with requests (Section 3.5), as well - as multiple methods for the client to prove its rightful ownership of - the credentials used (Section 3.4). The way in which clients - discover the required configuration is outside the scope of this - specification. - -3.1. Making Requests - - An authenticated request includes several protocol parameters. Each - parameter name begins with the "oauth_" prefix, and the parameter - names and values are case sensitive. Clients make authenticated - requests by calculating the values of a set of protocol parameters - and adding them to the HTTP request as follows: - - 1. The client assigns value to each of these REQUIRED (unless - specified otherwise) protocol parameters: - - - - - - - - -Hammer-Lahav Informational [Page 14] - -RFC 5849 OAuth 1.0 April 2010 - - - oauth_consumer_key - The identifier portion of the client credentials (equivalent to - a username). The parameter name reflects a deprecated term - (Consumer Key) used in previous revisions of the specification, - and has been retained to maintain backward compatibility. - - oauth_token - The token value used to associate the request with the resource - owner. If the request is not associated with a resource owner - (no token available), clients MAY omit the parameter. - - oauth_signature_method - The name of the signature method used by the client to sign the - request, as defined in Section 3.4. - - oauth_timestamp - The timestamp value as defined in Section 3.3. The parameter - MAY be omitted when using the "PLAINTEXT" signature method. - - oauth_nonce - The nonce value as defined in Section 3.3. The parameter MAY - be omitted when using the "PLAINTEXT" signature method. - - oauth_version - OPTIONAL. If present, MUST be set to "1.0". Provides the - version of the authentication process as defined in this - specification. - - 2. The protocol parameters are added to the request using one of the - transmission methods listed in Section 3.5. Each parameter MUST - NOT appear more than once per request. - - 3. The client calculates and assigns the value of the - "oauth_signature" parameter as described in Section 3.4 and adds - the parameter to the request using the same method as in the - previous step. - - 4. The client sends the authenticated HTTP request to the server. - - For example, to make the following HTTP request authenticated (the - "c2&a3=2+q" string in the following examples is used to illustrate - the impact of a form-encoded entity-body): - - POST /request?b5=%3D%253D&a3=a&c%40=&a2=r%20b HTTP/1.1 - Host: example.com - Content-Type: application/x-www-form-urlencoded - - c2&a3=2+q - - - -Hammer-Lahav Informational [Page 15] - -RFC 5849 OAuth 1.0 April 2010 - - - The client assigns values to the following protocol parameters using - its client credentials, token credentials, the current timestamp, a - uniquely generated nonce, and indicates that it will use the - "HMAC-SHA1" signature method: - - oauth_consumer_key: 9djdj82h48djs9d2 - oauth_token: kkk9d7dh3k39sjv7 - oauth_signature_method: HMAC-SHA1 - oauth_timestamp: 137131201 - oauth_nonce: 7d8f3e4a - - The client adds the protocol parameters to the request using the - OAuth HTTP "Authorization" header field: - - Authorization: OAuth realm="Example", - oauth_consumer_key="9djdj82h48djs9d2", - oauth_token="kkk9d7dh3k39sjv7", - oauth_signature_method="HMAC-SHA1", - oauth_timestamp="137131201", - oauth_nonce="7d8f3e4a" - - Then, it calculates the value of the "oauth_signature" parameter - (using client secret "j49sk3j29djd" and token secret "dh893hdasih9"), - adds it to the request, and sends the HTTP request to the server: - - POST /request?b5=%3D%253D&a3=a&c%40=&a2=r%20b HTTP/1.1 - Host: example.com - Content-Type: application/x-www-form-urlencoded - Authorization: OAuth realm="Example", - oauth_consumer_key="9djdj82h48djs9d2", - oauth_token="kkk9d7dh3k39sjv7", - oauth_signature_method="HMAC-SHA1", - oauth_timestamp="137131201", - oauth_nonce="7d8f3e4a", - oauth_signature="bYT5CMsGcbgUdFHObYMEfcx6bsw%3D" - - c2&a3=2+q - -3.2. Verifying Requests - - Servers receiving an authenticated request MUST validate it by: - - o Recalculating the request signature independently as described in - Section 3.4 and comparing it to the value received from the client - via the "oauth_signature" parameter. - - - - - - -Hammer-Lahav Informational [Page 16] - -RFC 5849 OAuth 1.0 April 2010 - - - o If using the "HMAC-SHA1" or "RSA-SHA1" signature methods, ensuring - that the combination of nonce/timestamp/token (if present) - received from the client has not been used before in a previous - request (the server MAY reject requests with stale timestamps as - described in Section 3.3). - - o If a token is present, verifying the scope and status of the - client authorization as represented by the token (the server MAY - choose to restrict token usage to the client to which it was - issued). - - o If the "oauth_version" parameter is present, ensuring its value is - "1.0". - - If the request fails verification, the server SHOULD respond with the - appropriate HTTP response status code. The server MAY include - further details about why the request was rejected in the response - body. - - The server SHOULD return a 400 (Bad Request) status code when - receiving a request with unsupported parameters, an unsupported - signature method, missing parameters, or duplicated protocol - parameters. The server SHOULD return a 401 (Unauthorized) status - code when receiving a request with invalid client credentials, an - invalid or expired token, an invalid signature, or an invalid or used - nonce. - -3.3. Nonce and Timestamp - - The timestamp value MUST be a positive integer. Unless otherwise - specified by the server's documentation, the timestamp is expressed - in the number of seconds since January 1, 1970 00:00:00 GMT. - - A nonce is a random string, uniquely generated by the client to allow - the server to verify that a request has never been made before and - helps prevent replay attacks when requests are made over a non-secure - channel. The nonce value MUST be unique across all requests with the - same timestamp, client credentials, and token combinations. - - To avoid the need to retain an infinite number of nonce values for - future checks, servers MAY choose to restrict the time period after - which a request with an old timestamp is rejected. Note that this - restriction implies a level of synchronization between the client's - and server's clocks. Servers applying such a restriction MAY provide - a way for the client to sync with the server's clock; alternatively, - both systems could synchronize with a trusted time service. Details - of clock synchronization strategies are beyond the scope of this - specification. - - - -Hammer-Lahav Informational [Page 17] - -RFC 5849 OAuth 1.0 April 2010 - - -3.4. Signature - - OAuth-authenticated requests can have two sets of credentials: those - passed via the "oauth_consumer_key" parameter and those in the - "oauth_token" parameter. In order for the server to verify the - authenticity of the request and prevent unauthorized access, the - client needs to prove that it is the rightful owner of the - credentials. This is accomplished using the shared-secret (or RSA - key) part of each set of credentials. - - OAuth provides three methods for the client to prove its rightful - ownership of the credentials: "HMAC-SHA1", "RSA-SHA1", and - "PLAINTEXT". These methods are generally referred to as signature - methods, even though "PLAINTEXT" does not involve a signature. In - addition, "RSA-SHA1" utilizes an RSA key instead of the shared- - secrets associated with the client credentials. - - OAuth does not mandate a particular signature method, as each - implementation can have its own unique requirements. Servers are - free to implement and document their own custom methods. - Recommending any particular method is beyond the scope of this - specification. Implementers should review the Security - Considerations section (Section 4) before deciding on which method to - support. - - The client declares which signature method is used via the - "oauth_signature_method" parameter. It then generates a signature - (or a string of an equivalent value) and includes it in the - "oauth_signature" parameter. The server verifies the signature as - specified for each method. - - The signature process does not change the request or its parameters, - with the exception of the "oauth_signature" parameter. - -3.4.1. Signature Base String - - The signature base string is a consistent, reproducible concatenation - of several of the HTTP request elements into a single string. The - string is used as an input to the "HMAC-SHA1" and "RSA-SHA1" - signature methods. - - The signature base string includes the following components of the - HTTP request: - - o The HTTP request method (e.g., "GET", "POST", etc.). - - o The authority as declared by the HTTP "Host" request header field. - - - - -Hammer-Lahav Informational [Page 18] - -RFC 5849 OAuth 1.0 April 2010 - - - o The path and query components of the request resource URI. - - o The protocol parameters excluding the "oauth_signature". - - o Parameters included in the request entity-body if they comply with - the strict restrictions defined in Section 3.4.1.3. - - The signature base string does not cover the entire HTTP request. - Most notably, it does not include the entity-body in most requests, - nor does it include most HTTP entity-headers. It is important to - note that the server cannot verify the authenticity of the excluded - request components without using additional protections such as SSL/ - TLS or other methods. - -3.4.1.1. String Construction - - The signature base string is constructed by concatenating together, - in order, the following HTTP request elements: - - 1. The HTTP request method in uppercase. For example: "HEAD", - "GET", "POST", etc. If the request uses a custom HTTP method, it - MUST be encoded (Section 3.6). - - 2. An "&" character (ASCII code 38). - - 3. The base string URI from Section 3.4.1.2, after being encoded - (Section 3.6). - - 4. An "&" character (ASCII code 38). - - 5. The request parameters as normalized in Section 3.4.1.3.2, after - being encoded (Section 3.6). - - For example, the HTTP request: - - POST /request?b5=%3D%253D&a3=a&c%40=&a2=r%20b HTTP/1.1 - Host: example.com - Content-Type: application/x-www-form-urlencoded - Authorization: OAuth realm="Example", - oauth_consumer_key="9djdj82h48djs9d2", - oauth_token="kkk9d7dh3k39sjv7", - oauth_signature_method="HMAC-SHA1", - oauth_timestamp="137131201", - oauth_nonce="7d8f3e4a", - oauth_signature="bYT5CMsGcbgUdFHObYMEfcx6bsw%3D" - - c2&a3=2+q - - - - -Hammer-Lahav Informational [Page 19] - -RFC 5849 OAuth 1.0 April 2010 - - - is represented by the following signature base string (line breaks - are for display purposes only): - - POST&http%3A%2F%2Fexample.com%2Frequest&a2%3Dr%2520b%26a3%3D2%2520q - %26a3%3Da%26b5%3D%253D%25253D%26c%2540%3D%26c2%3D%26oauth_consumer_ - key%3D9djdj82h48djs9d2%26oauth_nonce%3D7d8f3e4a%26oauth_signature_m - ethod%3DHMAC-SHA1%26oauth_timestamp%3D137131201%26oauth_token%3Dkkk - 9d7dh3k39sjv7 - -3.4.1.2. Base String URI - - The scheme, authority, and path of the request resource URI [RFC3986] - are included by constructing an "http" or "https" URI representing - the request resource (without the query or fragment) as follows: - - 1. The scheme and host MUST be in lowercase. - - 2. The host and port values MUST match the content of the HTTP - request "Host" header field. - - 3. The port MUST be included if it is not the default port for the - scheme, and MUST be excluded if it is the default. Specifically, - the port MUST be excluded when making an HTTP request [RFC2616] - to port 80 or when making an HTTPS request [RFC2818] to port 443. - All other non-default port numbers MUST be included. - - For example, the HTTP request: - - GET /r%20v/X?id=123 HTTP/1.1 - Host: EXAMPLE.COM:80 - - is represented by the base string URI: "http://example.com/r%20v/X". - - In another example, the HTTPS request: - - GET /?q=1 HTTP/1.1 - Host: www.example.net:8080 - - is represented by the base string URI: - "https://www.example.net:8080/". - -3.4.1.3. Request Parameters - - In order to guarantee a consistent and reproducible representation of - the request parameters, the parameters are collected and decoded to - their original decoded form. They are then sorted and encoded in a - particular manner that is often different from their original - encoding scheme, and concatenated into a single string. - - - -Hammer-Lahav Informational [Page 20] - -RFC 5849 OAuth 1.0 April 2010 - - -3.4.1.3.1. Parameter Sources - - The parameters from the following sources are collected into a single - list of name/value pairs: - - o The query component of the HTTP request URI as defined by - [RFC3986], Section 3.4. The query component is parsed into a list - of name/value pairs by treating it as an - "application/x-www-form-urlencoded" string, separating the names - and values and decoding them as defined by - [W3C.REC-html40-19980424], Section 17.13.4. - - o The OAuth HTTP "Authorization" header field (Section 3.5.1) if - present. The header's content is parsed into a list of name/value - pairs excluding the "realm" parameter if present. The parameter - values are decoded as defined by Section 3.5.1. - - o The HTTP request entity-body, but only if all of the following - conditions are met: - - * The entity-body is single-part. - - * The entity-body follows the encoding requirements of the - "application/x-www-form-urlencoded" content-type as defined by - [W3C.REC-html40-19980424]. - - * The HTTP request entity-header includes the "Content-Type" - header field set to "application/x-www-form-urlencoded". - - The entity-body is parsed into a list of decoded name/value pairs - as described in [W3C.REC-html40-19980424], Section 17.13.4. - - The "oauth_signature" parameter MUST be excluded from the signature - base string if present. Parameters not explicitly included in the - request MUST be excluded from the signature base string (e.g., the - "oauth_version" parameter when omitted). - - - - - - - - - - - - - - - -Hammer-Lahav Informational [Page 21] - -RFC 5849 OAuth 1.0 April 2010 - - - For example, the HTTP request: - - POST /request?b5=%3D%253D&a3=a&c%40=&a2=r%20b HTTP/1.1 - Host: example.com - Content-Type: application/x-www-form-urlencoded - Authorization: OAuth realm="Example", - oauth_consumer_key="9djdj82h48djs9d2", - oauth_token="kkk9d7dh3k39sjv7", - oauth_signature_method="HMAC-SHA1", - oauth_timestamp="137131201", - oauth_nonce="7d8f3e4a", - oauth_signature="djosJKDKJSD8743243%2Fjdk33klY%3D" - - c2&a3=2+q - - contains the following (fully decoded) parameters used in the - signature base sting: - - +------------------------+------------------+ - | Name | Value | - +------------------------+------------------+ - | b5 | =%3D | - | a3 | a | - | c@ | | - | a2 | r b | - | oauth_consumer_key | 9djdj82h48djs9d2 | - | oauth_token | kkk9d7dh3k39sjv7 | - | oauth_signature_method | HMAC-SHA1 | - | oauth_timestamp | 137131201 | - | oauth_nonce | 7d8f3e4a | - | c2 | | - | a3 | 2 q | - +------------------------+------------------+ - - Note that the value of "b5" is "=%3D" and not "==". Both "c@" and - "c2" have empty values. While the encoding rules specified in this - specification for the purpose of constructing the signature base - string exclude the use of a "+" character (ASCII code 43) to - represent an encoded space character (ASCII code 32), this practice - is widely used in "application/x-www-form-urlencoded" encoded values, - and MUST be properly decoded, as demonstrated by one of the "a3" - parameter instances (the "a3" parameter is used twice in this - request). - - - - - - - - -Hammer-Lahav Informational [Page 22] - -RFC 5849 OAuth 1.0 April 2010 - - -3.4.1.3.2. Parameters Normalization - - The parameters collected in Section 3.4.1.3 are normalized into a - single string as follows: - - 1. First, the name and value of each parameter are encoded - (Section 3.6). - - 2. The parameters are sorted by name, using ascending byte value - ordering. If two or more parameters share the same name, they - are sorted by their value. - - 3. The name of each parameter is concatenated to its corresponding - value using an "=" character (ASCII code 61) as a separator, even - if the value is empty. - - 4. The sorted name/value pairs are concatenated together into a - single string by using an "&" character (ASCII code 38) as - separator. - - For example, the list of parameters from the previous section would - be normalized as follows: - - Encoded: - - +------------------------+------------------+ - | Name | Value | - +------------------------+------------------+ - | b5 | %3D%253D | - | a3 | a | - | c%40 | | - | a2 | r%20b | - | oauth_consumer_key | 9djdj82h48djs9d2 | - | oauth_token | kkk9d7dh3k39sjv7 | - | oauth_signature_method | HMAC-SHA1 | - | oauth_timestamp | 137131201 | - | oauth_nonce | 7d8f3e4a | - | c2 | | - | a3 | 2%20q | - +------------------------+------------------+ - - - - - - - - - - - -Hammer-Lahav Informational [Page 23] - -RFC 5849 OAuth 1.0 April 2010 - - - Sorted: - - +------------------------+------------------+ - | Name | Value | - +------------------------+------------------+ - | a2 | r%20b | - | a3 | 2%20q | - | a3 | a | - | b5 | %3D%253D | - | c%40 | | - | c2 | | - | oauth_consumer_key | 9djdj82h48djs9d2 | - | oauth_nonce | 7d8f3e4a | - | oauth_signature_method | HMAC-SHA1 | - | oauth_timestamp | 137131201 | - | oauth_token | kkk9d7dh3k39sjv7 | - +------------------------+------------------+ - - Concatenated Pairs: - - +-------------------------------------+ - | Name=Value | - +-------------------------------------+ - | a2=r%20b | - | a3=2%20q | - | a3=a | - | b5=%3D%253D | - | c%40= | - | c2= | - | oauth_consumer_key=9djdj82h48djs9d2 | - | oauth_nonce=7d8f3e4a | - | oauth_signature_method=HMAC-SHA1 | - | oauth_timestamp=137131201 | - | oauth_token=kkk9d7dh3k39sjv7 | - +-------------------------------------+ - - and concatenated together into a single string (line breaks are for - display purposes only): - - a2=r%20b&a3=2%20q&a3=a&b5=%3D%253D&c%40=&c2=&oauth_consumer_key=9dj - dj82h48djs9d2&oauth_nonce=7d8f3e4a&oauth_signature_method=HMAC-SHA1 - &oauth_timestamp=137131201&oauth_token=kkk9d7dh3k39sjv7 - - - - - - - - - -Hammer-Lahav Informational [Page 24] - -RFC 5849 OAuth 1.0 April 2010 - - -3.4.2. HMAC-SHA1 - - The "HMAC-SHA1" signature method uses the HMAC-SHA1 signature - algorithm as defined in [RFC2104]: - - digest = HMAC-SHA1 (key, text) - - The HMAC-SHA1 function variables are used in following way: - - text is set to the value of the signature base string from - Section 3.4.1.1. - - key is set to the concatenated values of: - - 1. The client shared-secret, after being encoded - (Section 3.6). - - 2. An "&" character (ASCII code 38), which MUST be included - even when either secret is empty. - - 3. The token shared-secret, after being encoded - (Section 3.6). - - digest is used to set the value of the "oauth_signature" protocol - parameter, after the result octet string is base64-encoded - per [RFC2045], Section 6.8. - -3.4.3. RSA-SHA1 - - The "RSA-SHA1" signature method uses the RSASSA-PKCS1-v1_5 signature - algorithm as defined in [RFC3447], Section 8.2 (also known as - PKCS#1), using SHA-1 as the hash function for EMSA-PKCS1-v1_5. To - use this method, the client MUST have established client credentials - with the server that included its RSA public key (in a manner that is - beyond the scope of this specification). - - The signature base string is signed using the client's RSA private - key per [RFC3447], Section 8.2.1: - - S = RSASSA-PKCS1-V1_5-SIGN (K, M) - - Where: - - K is set to the client's RSA private key, - - M is set to the value of the signature base string from - Section 3.4.1.1, and - - - - -Hammer-Lahav Informational [Page 25] - -RFC 5849 OAuth 1.0 April 2010 - - - S is the result signature used to set the value of the - "oauth_signature" protocol parameter, after the result octet - string is base64-encoded per [RFC2045] section 6.8. - - The server verifies the signature per [RFC3447] section 8.2.2: - - RSASSA-PKCS1-V1_5-VERIFY ((n, e), M, S) - - Where: - - (n, e) is set to the client's RSA public key, - - M is set to the value of the signature base string from - Section 3.4.1.1, and - - S is set to the octet string value of the "oauth_signature" - protocol parameter received from the client. - -3.4.4. PLAINTEXT - - The "PLAINTEXT" method does not employ a signature algorithm. It - MUST be used with a transport-layer mechanism such as TLS or SSL (or - sent over a secure channel with equivalent protections). It does not - utilize the signature base string or the "oauth_timestamp" and - "oauth_nonce" parameters. - - The "oauth_signature" protocol parameter is set to the concatenated - value of: - - 1. The client shared-secret, after being encoded (Section 3.6). - - 2. An "&" character (ASCII code 38), which MUST be included even - when either secret is empty. - - 3. The token shared-secret, after being encoded (Section 3.6). - -3.5. Parameter Transmission - - When making an OAuth-authenticated request, protocol parameters as - well as any other parameter using the "oauth_" prefix SHALL be - included in the request using one and only one of the following - locations, listed in order of decreasing preference: - - 1. The HTTP "Authorization" header field as described in - Section 3.5.1. - - 2. The HTTP request entity-body as described in Section 3.5.2. - - - - -Hammer-Lahav Informational [Page 26] - -RFC 5849 OAuth 1.0 April 2010 - - - 3. The HTTP request URI query as described in Section 3.5.3. - - In addition to these three methods, future extensions MAY define - other methods for including protocol parameters in the request. - -3.5.1. Authorization Header - - Protocol parameters can be transmitted using the HTTP "Authorization" - header field as defined by [RFC2617] with the auth-scheme name set to - "OAuth" (case insensitive). - - For example: - - Authorization: OAuth realm="Example", - oauth_consumer_key="0685bd9184jfhq22", - oauth_token="ad180jjd733klru7", - oauth_signature_method="HMAC-SHA1", - oauth_signature="wOJIO9A2W5mFwDgiDvZbTSMK%2FPY%3D", - oauth_timestamp="137131200", - oauth_nonce="4572616e48616d6d65724c61686176", - oauth_version="1.0" - - Protocol parameters SHALL be included in the "Authorization" header - field as follows: - - 1. Parameter names and values are encoded per Parameter Encoding - (Section 3.6). - - 2. Each parameter's name is immediately followed by an "=" character - (ASCII code 61), a """ character (ASCII code 34), the parameter - value (MAY be empty), and another """ character (ASCII code 34). - - 3. Parameters are separated by a "," character (ASCII code 44) and - OPTIONAL linear whitespace per [RFC2617]. - - 4. The OPTIONAL "realm" parameter MAY be added and interpreted per - [RFC2617] section 1.2. - - Servers MAY indicate their support for the "OAuth" auth-scheme by - returning the HTTP "WWW-Authenticate" response header field upon - client requests for protected resources. As per [RFC2617], such a - response MAY include additional HTTP "WWW-Authenticate" header - fields: - - For example: - - WWW-Authenticate: OAuth realm="http://server.example.com/" - - - - -Hammer-Lahav Informational [Page 27] - -RFC 5849 OAuth 1.0 April 2010 - - - The realm parameter defines a protection realm per [RFC2617], Section - 1.2. - -3.5.2. Form-Encoded Body - - Protocol parameters can be transmitted in the HTTP request entity- - body, but only if the following REQUIRED conditions are met: - - o The entity-body is single-part. - - o The entity-body follows the encoding requirements of the - "application/x-www-form-urlencoded" content-type as defined by - [W3C.REC-html40-19980424]. - - o The HTTP request entity-header includes the "Content-Type" header - field set to "application/x-www-form-urlencoded". - - For example (line breaks are for display purposes only): - - oauth_consumer_key=0685bd9184jfhq22&oauth_token=ad180jjd733klr - u7&oauth_signature_method=HMAC-SHA1&oauth_signature=wOJIO9A2W5 - mFwDgiDvZbTSMK%2FPY%3D&oauth_timestamp=137131200&oauth_nonce=4 - 572616e48616d6d65724c61686176&oauth_version=1.0 - - The entity-body MAY include other request-specific parameters, in - which case, the protocol parameters SHOULD be appended following the - request-specific parameters, properly separated by an "&" character - (ASCII code 38). - -3.5.3. Request URI Query - - Protocol parameters can be transmitted by being added to the HTTP - request URI as a query parameter as defined by [RFC3986], Section 3. - - For example (line breaks are for display purposes only): - - GET /example/path?oauth_consumer_key=0685bd9184jfhq22& - oauth_token=ad180jjd733klru7&oauth_signature_method=HM - AC-SHA1&oauth_signature=wOJIO9A2W5mFwDgiDvZbTSMK%2FPY% - 3D&oauth_timestamp=137131200&oauth_nonce=4572616e48616 - d6d65724c61686176&oauth_version=1.0 HTTP/1.1 - - The request URI MAY include other request-specific query parameters, - in which case, the protocol parameters SHOULD be appended following - the request-specific parameters, properly separated by an "&" - character (ASCII code 38). - - - - - -Hammer-Lahav Informational [Page 28] - -RFC 5849 OAuth 1.0 April 2010 - - -3.6. Percent Encoding - - Existing percent-encoding methods do not guarantee a consistent - construction of the signature base string. The following percent- - encoding method is not defined to replace the existing encoding - methods defined by [RFC3986] and [W3C.REC-html40-19980424]. It is - used only in the construction of the signature base string and the - "Authorization" header field. - - This specification defines the following method for percent-encoding - strings: - - 1. Text values are first encoded as UTF-8 octets per [RFC3629] if - they are not already. This does not include binary values that - are not intended for human consumption. - - 2. The values are then escaped using the [RFC3986] percent-encoding - (%XX) mechanism as follows: - - * Characters in the unreserved character set as defined by - [RFC3986], Section 2.3 (ALPHA, DIGIT, "-", ".", "_", "~") MUST - NOT be encoded. - - * All other characters MUST be encoded. - - * The two hexadecimal characters used to represent encoded - characters MUST be uppercase. - - This method is different from the encoding scheme used by the - "application/x-www-form-urlencoded" content-type (for example, it - encodes space characters as "%20" and not using the "+" character). - It MAY be different from the percent-encoding functions provided by - web-development frameworks (e.g., encode different characters, use - lowercase hexadecimal characters). - -4. Security Considerations - - As stated in [RFC2617], the greatest sources of risks are usually - found not in the core protocol itself but in policies and procedures - surrounding its use. Implementers are strongly encouraged to assess - how this protocol addresses their security requirements. - -4.1. RSA-SHA1 Signature Method - - Authenticated requests made with "RSA-SHA1" signatures do not use the - token shared-secret, or any provisioned client shared-secret. This - means the request relies completely on the secrecy of the private key - used by the client to sign requests. - - - -Hammer-Lahav Informational [Page 29] - -RFC 5849 OAuth 1.0 April 2010 - - -4.2. Confidentiality of Requests - - While this protocol provides a mechanism for verifying the integrity - of requests, it provides no guarantee of request confidentiality. - Unless further precautions are taken, eavesdroppers will have full - access to request content. Servers should carefully consider the - kinds of data likely to be sent as part of such requests, and should - employ transport-layer security mechanisms to protect sensitive - resources. - -4.3. Spoofing by Counterfeit Servers - - This protocol makes no attempt to verify the authenticity of the - server. A hostile party could take advantage of this by intercepting - the client's requests and returning misleading or otherwise incorrect - responses. Service providers should consider such attacks when - developing services using this protocol, and should require - transport-layer security for any requests where the authenticity of - the server or of request responses is an issue. - -4.4. Proxying and Caching of Authenticated Content - - The HTTP Authorization scheme (Section 3.5.1) is optional. However, - [RFC2616] relies on the "Authorization" and "WWW-Authenticate" header - fields to distinguish authenticated content so that it can be - protected. Proxies and caches, in particular, may fail to adequately - protect requests not using these header fields. - - For example, private authenticated content may be stored in (and thus - retrievable from) publicly accessible caches. Servers not using the - HTTP "Authorization" header field should take care to use other - mechanisms, such as the "Cache-Control" header field, to ensure that - authenticated content is protected. - -4.5. Plaintext Storage of Credentials - - The client shared-secret and token shared-secret function the same - way passwords do in traditional authentication systems. In order to - compute the signatures used in methods other than "RSA-SHA1", the - server must have access to these secrets in plaintext form. This is - in contrast, for example, to modern operating systems, which store - only a one-way hash of user credentials. - - If an attacker were to gain access to these secrets -- or worse, to - the server's database of all such secrets -- he or she would be able - to perform any action on behalf of any resource owner. Accordingly, - it is critical that servers protect these secrets from unauthorized - access. - - - -Hammer-Lahav Informational [Page 30] - -RFC 5849 OAuth 1.0 April 2010 - - -4.6. Secrecy of the Client Credentials - - In many cases, the client application will be under the control of - potentially untrusted parties. For example, if the client is a - desktop application with freely available source code or an - executable binary, an attacker may be able to download a copy for - analysis. In such cases, attackers will be able to recover the - client credentials. - - Accordingly, servers should not use the client credentials alone to - verify the identity of the client. Where possible, other factors - such as IP address should be used as well. - -4.7. Phishing Attacks - - Wide deployment of this and similar protocols may cause resource - owners to become inured to the practice of being redirected to - websites where they are asked to enter their passwords. If resource - owners are not careful to verify the authenticity of these websites - before entering their credentials, it will be possible for attackers - to exploit this practice to steal resource owners' passwords. - - Servers should attempt to educate resource owners about the risks - phishing attacks pose, and should provide mechanisms that make it - easy for resource owners to confirm the authenticity of their sites. - Client developers should consider the security implications of how - they interact with a user-agent (e.g., separate window, embedded), - and the ability of the end-user to verify the authenticity of the - server website. - -4.8. Scoping of Access Requests - - By itself, this protocol does not provide any method for scoping the - access rights granted to a client. However, most applications do - require greater granularity of access rights. For example, servers - may wish to make it possible to grant access to some protected - resources but not others, or to grant only limited access (such as - read-only access) to those protected resources. - - When implementing this protocol, servers should consider the types of - access resource owners may wish to grant clients, and should provide - mechanisms to do so. Servers should also take care to ensure that - resource owners understand the access they are granting, as well as - any risks that may be involved. - - - - - - - -Hammer-Lahav Informational [Page 31] - -RFC 5849 OAuth 1.0 April 2010 - - -4.9. Entropy of Secrets - - Unless a transport-layer security protocol is used, eavesdroppers - will have full access to authenticated requests and signatures, and - will thus be able to mount offline brute-force attacks to recover the - credentials used. Servers should be careful to assign shared-secrets - that are long enough, and random enough, to resist such attacks for - at least the length of time that the shared-secrets are valid. - - For example, if shared-secrets are valid for two weeks, servers - should ensure that it is not possible to mount a brute force attack - that recovers the shared-secret in less than two weeks. Of course, - servers are urged to err on the side of caution, and use the longest - secrets reasonable. - - It is equally important that the pseudo-random number generator - (PRNG) used to generate these secrets be of sufficiently high - quality. Many PRNG implementations generate number sequences that - may appear to be random, but that nevertheless exhibit patterns or - other weaknesses that make cryptanalysis or brute force attacks - easier. Implementers should be careful to use cryptographically - secure PRNGs to avoid these problems. - -4.10. Denial-of-Service / Resource-Exhaustion Attacks - - This specification includes a number of features that may make - resource exhaustion attacks against servers possible. For example, - this protocol requires servers to track used nonces. If an attacker - is able to use many nonces quickly, the resources required to track - them may exhaust available capacity. And again, this protocol can - require servers to perform potentially expensive computations in - order to verify the signature on incoming requests. An attacker may - exploit this to perform a denial-of-service attack by sending a large - number of invalid requests to the server. - - Resource Exhaustion attacks are by no means specific to this - specification. However, implementers should be careful to consider - the additional avenues of attack that this protocol exposes, and - design their implementations accordingly. For example, entropy - starvation typically results in either a complete denial of service - while the system waits for new entropy or else in weak (easily - guessable) secrets. When implementing this protocol, servers should - consider which of these presents a more serious risk for their - application and design accordingly. - - - - - - - -Hammer-Lahav Informational [Page 32] - -RFC 5849 OAuth 1.0 April 2010 - - -4.11. SHA-1 Cryptographic Attacks - - SHA-1, the hash algorithm used in "HMAC-SHA1" and "RSA-SHA1" - signature methods, has been shown to have a number of cryptographic - weaknesses that significantly reduce its resistance to collision - attacks. While these weaknesses do not seem to affect the use of - SHA-1 with the Hash-based Message Authentication Code (HMAC) and - should not affect the "HMAC-SHA1" signature method, it may affect the - use of the "RSA-SHA1" signature method. NIST has announced that it - will phase out use of SHA-1 in digital signatures by 2010 - [NIST_SHA-1Comments]. - - Practically speaking, these weaknesses are difficult to exploit, and - by themselves do not pose a significant risk to users of this - protocol. They may, however, make more efficient attacks possible, - and servers should take this into account when considering whether - SHA-1 provides an adequate level of security for their applications. - -4.12. Signature Base String Limitations - - The signature base string has been designed to support the signature - methods defined in this specification. Those designing additional - signature methods, should evaluated the compatibility of the - signature base string with their security requirements. - - Since the signature base string does not cover the entire HTTP - request, such as most request entity-body, most entity-headers, and - the order in which parameters are sent, servers should employ - additional mechanisms to protect such elements. - -4.13. Cross-Site Request Forgery (CSRF) - - Cross-Site Request Forgery (CSRF) is a web-based attack whereby HTTP - requests are transmitted from a user that the website trusts or has - authenticated. CSRF attacks on authorization approvals can allow an - attacker to obtain authorization to protected resources without the - consent of the User. Servers SHOULD strongly consider best practices - in CSRF prevention at all the protocol authorization endpoints. - - CSRF attacks on OAuth callback URIs hosted by clients are also - possible. Clients should prevent CSRF attacks on OAuth callback URIs - by verifying that the resource owner at the client site intended to - complete the OAuth negotiation with the server. The methods for - preventing such CSRF attacks are beyond the scope of this - specification. - - - - - - -Hammer-Lahav Informational [Page 33] - -RFC 5849 OAuth 1.0 April 2010 - - -4.14. User Interface Redress - - Servers should protect the authorization process against user - interface (UI) redress attacks (also known as "clickjacking"). As of - the time of this writing, no complete defenses against UI redress are - available. Servers can mitigate the risk of UI redress attacks using - the following techniques: - - o JavaScript frame busting. - - o JavaScript frame busting, and requiring that browsers have - JavaScript enabled on the authorization page. - - o Browser-specific anti-framing techniques. - - o Requiring password reentry before issuing OAuth tokens. - -4.15. Automatic Processing of Repeat Authorizations - - Servers may wish to automatically process authorization requests - (Section 2.2) from clients that have been previously authorized by - the resource owner. When the resource owner is redirected to the - server to grant access, the server detects that the resource owner - has already granted access to that particular client. Instead of - prompting the resource owner for approval, the server automatically - redirects the resource owner back to the client. - - If the client credentials are compromised, automatic processing - creates additional security risks. An attacker can use the stolen - client credentials to redirect the resource owner to the server with - an authorization request. The server will then grant access to the - resource owner's data without the resource owner's explicit approval, - or even awareness of an attack. If no automatic approval is - implemented, an attacker must use social engineering to convince the - resource owner to approve access. - - Servers can mitigate the risks associated with automatic processing - by limiting the scope of token credentials obtained through automated - approvals. Tokens credentials obtained through explicit resource - owner consent can remain unaffected. Clients can mitigate the risks - associated with automatic processing by protecting their client - credentials. - - - - - - - - - -Hammer-Lahav Informational [Page 34] - -RFC 5849 OAuth 1.0 April 2010 - - -5. Acknowledgments - - This specification is directly based on the OAuth Core 1.0 Revision A - community specification, which in turn was modeled after existing - proprietary protocols and best practices that have been independently - implemented by various companies. - - The community specification was edited by Eran Hammer-Lahav and - authored by: Mark Atwood, Dirk Balfanz, Darren Bounds, Richard M. - Conlan, Blaine Cook, Leah Culver, Breno de Medeiros, Brian Eaton, - Kellan Elliott-McCrea, Larry Halff, Eran Hammer-Lahav, Ben Laurie, - Chris Messina, John Panzer, Sam Quigley, David Recordon, Eran - Sandler, Jonathan Sergent, Todd Sieling, Brian Slesinsky, and Andy - Smith. - - The editor would like to thank the following individuals for their - invaluable contribution to the publication of this edition of the - protocol: Lisa Dusseault, Justin Hart, Avshalom Houri, Chris Messina, - Mark Nottingham, Tim Polk, Peter Saint-Andre, Joseph Smarr, and Paul - Walker. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Hammer-Lahav Informational [Page 35] - -RFC 5849 OAuth 1.0 April 2010 - - -Appendix A. Differences from the Community Edition - - This specification includes the following changes made to the - original community document [OAuthCore1.0_RevisionA] in order to - correct mistakes and omissions identified since the document was - originally published at . - - o Changed using TLS/SSL when sending or requesting plain text - credentials from SHOULD to MUST. This change affects any use of - the "PLAINTEXT" signature method, as well as requesting temporary - credentials (Section 2.1) and obtaining token credentials - (Section 2.3). - - o Adjusted nonce language to indicate it is unique per token/ - timestamp/client combination. - - o Removed the requirement for timestamps to be equal to or greater - than the timestamp used in the previous request. - - o Changed the nonce and timestamp parameters to OPTIONAL when using - the "PLAINTEXT" signature method. - - o Extended signature base string coverage that includes - "application/x-www-form-urlencoded" entity-body parameters when - the HTTP method used is other than "POST" and URI query parameters - when the HTTP method used is other than "GET". - - o Incorporated corrections to the instructions in each signature - method to encode the signature value before inserting it into the - "oauth_signature" parameter, removing errors that would have - caused double-encoded values. - - o Allowed omitting the "oauth_token" parameter when empty. - - o Permitted sending requests for temporary credentials with an empty - "oauth_token" parameter. - - o Removed the restrictions from defining additional "oauth_" - parameters. - - - - - - - - - - - - -Hammer-Lahav Informational [Page 36] - -RFC 5849 OAuth 1.0 April 2010 - - -6. References - -6.1. Normative References - - [RFC2045] Freed, N. and N. Borenstein, "Multipurpose Internet Mail - Extensions (MIME) Part One: Format of Internet Message - Bodies", RFC 2045, November 1996. - - [RFC2104] Krawczyk, H., Bellare, M., and R. Canetti, "HMAC: Keyed- - Hashing for Message Authentication", RFC 2104, - February 1997. - - [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate - Requirement Levels", BCP 14, RFC 2119, March 1997. - - [RFC2616] Fielding, R., Gettys, J., Mogul, J., Frystyk, H., - Masinter, L., Leach, P., and T. Berners-Lee, "Hypertext - Transfer Protocol -- HTTP/1.1", RFC 2616, June 1999. - - [RFC2617] Franks, J., Hallam-Baker, P., Hostetler, J., Lawrence, S., - Leach, P., Luotonen, A., and L. Stewart, "HTTP - Authentication: Basic and Digest Access Authentication", - RFC 2617, June 1999. - - [RFC2818] Rescorla, E., "HTTP Over TLS", RFC 2818, May 2000. - - [RFC3447] Jonsson, J. and B. Kaliski, "Public-Key Cryptography - Standards (PKCS) #1: RSA Cryptography Specifications - Version 2.1", RFC 3447, February 2003. - - [RFC3629] Yergeau, F., "UTF-8, a transformation format of ISO - 10646", STD 63, RFC 3629, November 2003. - - [RFC3986] Berners-Lee, T., Fielding, R., and L. Masinter, "Uniform - Resource Identifier (URI): Generic Syntax", STD 66, - RFC 3986, January 2005. - - [W3C.REC-html40-19980424] - Hors, A., Raggett, D., and I. Jacobs, "HTML 4.0 - Specification", World Wide Web Consortium - Recommendation REC-html40-19980424, April 1998, - . - - - - - - - - - -Hammer-Lahav Informational [Page 37] - -RFC 5849 OAuth 1.0 April 2010 - - -6.2. Informative References - - [NIST_SHA-1Comments] - Burr, W., "NIST Comments on Cryptanalytic Attacks on - SHA-1", - . - - [OAuthCore1.0_RevisionA] - OAuth Community, "OAuth Core 1.0 Revision A", - . - -Author's Address - - Eran Hammer-Lahav (editor) - - EMail: eran@hueniverse.com - URI: http://hueniverse.com - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Hammer-Lahav Informational [Page 38] - diff --git a/vendor/league/oauth1-client/src/Credentials/ClientCredentials.php b/vendor/league/oauth1-client/src/Credentials/ClientCredentials.php deleted file mode 100644 index a0a03bcaf..000000000 --- a/vendor/league/oauth1-client/src/Credentials/ClientCredentials.php +++ /dev/null @@ -1,29 +0,0 @@ -callbackUri; - } - - /** - * @inheritDoc - */ - public function setCallbackUri($callbackUri) - { - $this->callbackUri = $callbackUri; - } -} diff --git a/vendor/league/oauth1-client/src/Credentials/ClientCredentialsInterface.php b/vendor/league/oauth1-client/src/Credentials/ClientCredentialsInterface.php deleted file mode 100644 index c126156d6..000000000 --- a/vendor/league/oauth1-client/src/Credentials/ClientCredentialsInterface.php +++ /dev/null @@ -1,22 +0,0 @@ -identifier; - } - - /** - * @inheritDoc - */ - public function setIdentifier($identifier) - { - $this->identifier = $identifier; - } - - /** - * @inheritDoc - */ - public function getSecret() - { - return $this->secret; - } - - /** - * @inheritDoc - */ - public function setSecret($secret) - { - $this->secret = $secret; - } -} diff --git a/vendor/league/oauth1-client/src/Credentials/CredentialsException.php b/vendor/league/oauth1-client/src/Credentials/CredentialsException.php deleted file mode 100644 index b512eaa44..000000000 --- a/vendor/league/oauth1-client/src/Credentials/CredentialsException.php +++ /dev/null @@ -1,9 +0,0 @@ -rsaPublicKeyFile = $filename; - $this->rsaPublicKey = null; - - return $this; - } - - /** - * Sets the path to the RSA private key. - * - * @param string $filename - * - * @return self - */ - public function setRsaPrivateKey($filename) - { - $this->rsaPrivateKeyFile = $filename; - $this->rsaPrivateKey = null; - - return $this; - } - - /** - * Gets the RSA public key. - * - * @throws CredentialsException when the key could not be loaded. - * - * @return resource|OpenSSLAsymmetricKey - */ - public function getRsaPublicKey() - { - if ($this->rsaPublicKey) { - return $this->rsaPublicKey; - } - - if ( ! file_exists($this->rsaPublicKeyFile)) { - throw new CredentialsException('Could not read the public key file.'); - } - - $this->rsaPublicKey = openssl_get_publickey(file_get_contents($this->rsaPublicKeyFile)); - - if ( ! $this->rsaPublicKey) { - throw new CredentialsException('Cannot access public key for signing'); - } - - return $this->rsaPublicKey; - } - - /** - * Gets the RSA private key. - * - * @throws CredentialsException when the key could not be loaded. - * - * @return resource|OpenSSLAsymmetricKey - */ - public function getRsaPrivateKey() - { - if ($this->rsaPrivateKey) { - return $this->rsaPrivateKey; - } - - if ( ! file_exists($this->rsaPrivateKeyFile)) { - throw new CredentialsException('Could not read the private key file.'); - } - - $this->rsaPrivateKey = openssl_pkey_get_private(file_get_contents($this->rsaPrivateKeyFile)); - - if ( ! $this->rsaPrivateKey) { - throw new CredentialsException('Cannot access private key for signing'); - } - - return $this->rsaPrivateKey; - } -} diff --git a/vendor/league/oauth1-client/src/Credentials/TemporaryCredentials.php b/vendor/league/oauth1-client/src/Credentials/TemporaryCredentials.php deleted file mode 100644 index 91796e0ce..000000000 --- a/vendor/league/oauth1-client/src/Credentials/TemporaryCredentials.php +++ /dev/null @@ -1,7 +0,0 @@ -uid = $data['user']['username']; - $user->nickname = $data['user']['username']; - $user->name = $data['user']['display_name']; - $user->firstName = $data['user']['first_name']; - $user->lastName = $data['user']['last_name']; - $user->imageUrl = $data['user']['avatar']; - - $used = ['username', 'display_name', 'avatar']; - - foreach ($data as $key => $value) { - if (strpos($key, 'url') !== false) { - if ( ! in_array($key, $used)) { - $used[] = $key; - } - - $user->urls[$key] = $value; - } - } - - // Save all extra data - $user->extra = array_diff_key($data, array_flip($used)); - - return $user; - } - - /** - * @inheritDoc - */ - public function userUid($data, TokenCredentials $tokenCredentials) - { - return $data['user']['username']; - } - - /** - * @inheritDoc - */ - public function userEmail($data, TokenCredentials $tokenCredentials) - { - return null; - } - - /** - * @inheritDoc - */ - public function userScreenName($data, TokenCredentials $tokenCredentials) - { - return $data['user']['display_name']; - } -} diff --git a/vendor/league/oauth1-client/src/Server/Magento.php b/vendor/league/oauth1-client/src/Server/Magento.php deleted file mode 100644 index 6267cfa4a..000000000 --- a/vendor/league/oauth1-client/src/Server/Magento.php +++ /dev/null @@ -1,218 +0,0 @@ -parseConfigurationArray($clientCredentials); - } - } - - /** - * @inheritDoc - */ - public function urlTemporaryCredentials() - { - return $this->baseUri . '/oauth/initiate'; - } - - /** - * @inheritDoc - */ - public function urlAuthorization() - { - return $this->isAdmin - ? $this->adminUrl - : $this->baseUri . '/oauth/authorize'; - } - - /** - * @inheritDoc - */ - public function urlTokenCredentials() - { - return $this->baseUri . '/oauth/token'; - } - - /** - * @inheritDoc - */ - public function urlUserDetails() - { - return $this->baseUri . '/api/rest/customers'; - } - - /** - * @inheritDoc - */ - public function userDetails($data, TokenCredentials $tokenCredentials) - { - if ( ! is_array($data) || ! count($data)) { - throw new \Exception('Not possible to get user info'); - } - - $id = key($data); - $data = current($data); - - $user = new User(); - $user->uid = $id; - - $mapping = [ - 'email' => 'email', - 'firstName' => 'firstname', - 'lastName' => 'lastname', - ]; - foreach ($mapping as $userKey => $dataKey) { - if ( ! isset($data[$dataKey])) { - continue; - } - $user->{$userKey} = $data[$dataKey]; - } - - $user->extra = array_diff_key($data, array_flip($mapping)); - - return $user; - } - - /** - * @inheritDoc - */ - public function userUid($data, TokenCredentials $tokenCredentials) - { - return key($data); - } - - /** - * @inheritDoc - */ - public function userEmail($data, TokenCredentials $tokenCredentials) - { - $data = current($data); - - if ( ! isset($data['email'])) { - return null; - } - - return $data['email']; - } - - /** - * @inheritDoc - */ - public function userScreenName($data, TokenCredentials $tokenCredentials) - { - return null; - } - - /** - * @inheritDoc - */ - public function getTokenCredentials(TemporaryCredentials $temporaryCredentials, $temporaryIdentifier, $verifier) - { - $this->verifier = $verifier; - - return parent::getTokenCredentials($temporaryCredentials, $temporaryIdentifier, $verifier); - } - - /** - * @inheritDoc - */ - protected function additionalProtocolParameters() - { - return [ - 'oauth_verifier' => $this->verifier, - ]; - } - - protected function getHttpClientDefaultHeaders() - { - $defaultHeaders = parent::getHttpClientDefaultHeaders(); - // Accept header is required, @see Mage_Api2_Model_Renderer::factory - $defaultHeaders['Accept'] = 'application/json'; - - return $defaultHeaders; - } - - /** - * Parse configuration array to set attributes. - * - * @param array $configuration - * - * @return void - * - * @throws \Exception - */ - private function parseConfigurationArray(array $configuration = []) - { - if ( ! isset($configuration['host'])) { - throw new \Exception('Missing Magento Host'); - } - $url = parse_url($configuration['host']); - $this->baseUri = sprintf('%s://%s', $url['scheme'], $url['host']); - - if (isset($url['port'])) { - $this->baseUri .= ':' . $url['port']; - } - - if (isset($url['path'])) { - $this->baseUri .= '/' . trim($url['path'], '/'); - } - $this->isAdmin = ! empty($configuration['admin']); - if ( ! empty($configuration['adminUrl'])) { - $this->adminUrl = $configuration['adminUrl'] . '/oauth_authorize'; - } else { - $this->adminUrl = $this->baseUri . '/admin/oauth_authorize'; - } - } -} diff --git a/vendor/league/oauth1-client/src/Server/Server.php b/vendor/league/oauth1-client/src/Server/Server.php deleted file mode 100644 index 9341beb19..000000000 --- a/vendor/league/oauth1-client/src/Server/Server.php +++ /dev/null @@ -1,725 +0,0 @@ -createClientCredentials($clientCredentials); - } elseif ( ! $clientCredentials instanceof ClientCredentialsInterface) { - throw new \InvalidArgumentException('Client credentials must be an array or valid object.'); - } - - $this->clientCredentials = $clientCredentials; - - if ( ! $signature && $clientCredentials instanceof RsaClientCredentials) { - $signature = new RsaSha1Signature($clientCredentials); - } - $this->signature = $signature ?: new HmacSha1Signature($clientCredentials); - } - - /** - * Gets temporary credentials by performing a request to - * the server. - * - * @return TemporaryCredentials - * - * @throws CredentialsException - */ - public function getTemporaryCredentials() - { - $uri = $this->urlTemporaryCredentials(); - - $client = $this->createHttpClient(); - - $header = $this->temporaryCredentialsProtocolHeader($uri); - $authorizationHeader = ['Authorization' => $header]; - $headers = $this->buildHttpClientHeaders($authorizationHeader); - - try { - $response = $client->post($uri, [ - 'headers' => $headers, - ]); - - return $this->createTemporaryCredentials((string) $response->getBody()); - } catch (BadResponseException $e) { - $this->handleTemporaryCredentialsBadResponse($e); - } - - throw new CredentialsException('Failed to get temporary credentials'); - } - - /** - * Get the authorization URL by passing in the temporary credentials - * identifier or an object instance. - * - * @param TemporaryCredentials|string $temporaryIdentifier - * @param array $options - * - * @return string - */ - public function getAuthorizationUrl($temporaryIdentifier, array $options = []) - { - // Somebody can pass through an instance of temporary - // credentials and we'll extract the identifier from there. - if ($temporaryIdentifier instanceof TemporaryCredentials) { - $temporaryIdentifier = $temporaryIdentifier->getIdentifier(); - } - - $parameters = array_merge($options, ['oauth_token' => $temporaryIdentifier]); - - $url = $this->urlAuthorization(); - $queryString = http_build_query($parameters); - - return $this->buildUrl($url, $queryString); - } - - /** - * Redirect the client to the authorization URL. - * - * @param TemporaryCredentials|string $temporaryIdentifier - * - * @return void - */ - public function authorize($temporaryIdentifier) - { - $url = $this->getAuthorizationUrl($temporaryIdentifier); - - header('Location: ' . $url); - } - - /** - * Retrieves token credentials by passing in the temporary credentials, - * the temporary credentials identifier as passed back by the server - * and finally the verifier code. - * - * @param TemporaryCredentials $temporaryCredentials - * @param string $temporaryIdentifier - * @param string $verifier - * - * @return TokenCredentials - * - * @throws CredentialsException - */ - public function getTokenCredentials(TemporaryCredentials $temporaryCredentials, $temporaryIdentifier, $verifier) - { - if ($temporaryIdentifier !== $temporaryCredentials->getIdentifier()) { - throw new \InvalidArgumentException( - 'Temporary identifier passed back by server does not match that of stored temporary credentials. - Potential man-in-the-middle.' - ); - } - - $uri = $this->urlTokenCredentials(); - $bodyParameters = ['oauth_verifier' => $verifier]; - - $client = $this->createHttpClient(); - - $headers = $this->getHeaders($temporaryCredentials, 'POST', $uri, $bodyParameters); - - try { - $response = $client->post($uri, [ - 'headers' => $headers, - 'form_params' => $bodyParameters, - ]); - - return $this->createTokenCredentials((string) $response->getBody()); - } catch (BadResponseException $e) { - $this->handleTokenCredentialsBadResponse($e); - } - - throw new CredentialsException('Failed to get token credentials.'); - } - - /** - * Get user details by providing valid token credentials. - * - * @param TokenCredentials $tokenCredentials - * @param bool $force - * - * @return \League\OAuth1\Client\Server\User - */ - public function getUserDetails(TokenCredentials $tokenCredentials, $force = false) - { - $data = $this->fetchUserDetails($tokenCredentials, $force); - - return $this->userDetails($data, $tokenCredentials); - } - - /** - * Get the user's unique identifier (primary key). - * - * @param TokenCredentials $tokenCredentials - * @param bool $force - * - * @return string|int - */ - public function getUserUid(TokenCredentials $tokenCredentials, $force = false) - { - $data = $this->fetchUserDetails($tokenCredentials, $force); - - return $this->userUid($data, $tokenCredentials); - } - - /** - * Get the user's email, if available. - * - * @param TokenCredentials $tokenCredentials - * @param bool $force - * - * @return string|null - */ - public function getUserEmail(TokenCredentials $tokenCredentials, $force = false) - { - $data = $this->fetchUserDetails($tokenCredentials, $force); - - return $this->userEmail($data, $tokenCredentials); - } - - /** - * Get the user's screen name (username), if available. - * - * @param TokenCredentials $tokenCredentials - * @param bool $force - * - * @return string - */ - public function getUserScreenName(TokenCredentials $tokenCredentials, $force = false) - { - $data = $this->fetchUserDetails($tokenCredentials, $force); - - return $this->userScreenName($data, $tokenCredentials); - } - - /** - * Fetch user details from the remote service. - * - * @param TokenCredentials $tokenCredentials - * @param bool $force - * - * @return array HTTP client response - */ - protected function fetchUserDetails(TokenCredentials $tokenCredentials, $force = true) - { - if ( ! $this->cachedUserDetailsResponse || $force) { - $url = $this->urlUserDetails(); - - $client = $this->createHttpClient(); - - $headers = $this->getHeaders($tokenCredentials, 'GET', $url); - - try { - $response = $client->get($url, [ - 'headers' => $headers, - ]); - } catch (BadResponseException $e) { - $response = $e->getResponse(); - $body = $response->getBody(); - $statusCode = $response->getStatusCode(); - - throw new \Exception( - "Received error [$body] with status code [$statusCode] when retrieving token credentials." - ); - } - switch ($this->responseType) { - case 'json': - $this->cachedUserDetailsResponse = json_decode((string) $response->getBody(), true); - break; - - case 'xml': - $this->cachedUserDetailsResponse = simplexml_load_string((string) $response->getBody()); - break; - - case 'string': - parse_str((string) $response->getBody(), $this->cachedUserDetailsResponse); - break; - - default: - throw new \InvalidArgumentException("Invalid response type [{$this->responseType}]."); - } - } - - return $this->cachedUserDetailsResponse; - } - - /** - * Get the client credentials associated with the server. - * - * @return ClientCredentialsInterface - */ - public function getClientCredentials() - { - return $this->clientCredentials; - } - - /** - * Get the signature associated with the server. - * - * @return SignatureInterface - */ - public function getSignature() - { - return $this->signature; - } - - /** - * Creates a Guzzle HTTP client for the given URL. - * - * @return GuzzleHttpClient - */ - public function createHttpClient() - { - return new GuzzleHttpClient(); - } - - /** - * Set the user agent value. - * - * @param string $userAgent - * - * @return Server - */ - public function setUserAgent($userAgent = null) - { - $this->userAgent = $userAgent; - - return $this; - } - - /** - * Get all headers required to created an authenticated request. - * - * @param CredentialsInterface $credentials - * @param string $method - * @param string $url - * @param array $bodyParameters - * - * @return array - */ - public function getHeaders(CredentialsInterface $credentials, $method, $url, array $bodyParameters = []) - { - $header = $this->protocolHeader(strtoupper($method), $url, $credentials, $bodyParameters); - $authorizationHeader = ['Authorization' => $header]; - $headers = $this->buildHttpClientHeaders($authorizationHeader); - - return $headers; - } - - /** - * Get Guzzle HTTP client default headers. - * - * @return array - */ - protected function getHttpClientDefaultHeaders() - { - $defaultHeaders = []; - if ( ! empty($this->userAgent)) { - $defaultHeaders['User-Agent'] = $this->userAgent; - } - - return $defaultHeaders; - } - - /** - * Build Guzzle HTTP client headers. - * - * @param array $headers - * - * @return array - */ - protected function buildHttpClientHeaders($headers = []) - { - $defaultHeaders = $this->getHttpClientDefaultHeaders(); - - return array_merge($headers, $defaultHeaders); - } - - /** - * Creates a client credentials instance from an array of credentials. - * - * @param array $clientCredentials - * - * @return ClientCredentials - */ - protected function createClientCredentials(array $clientCredentials) - { - $keys = ['identifier', 'secret']; - - foreach ($keys as $key) { - if ( ! isset($clientCredentials[$key])) { - throw new \InvalidArgumentException("Missing client credentials key [$key] from options."); - } - } - - if (isset($clientCredentials['rsa_private_key']) && isset($clientCredentials['rsa_public_key'])) { - $_clientCredentials = new RsaClientCredentials(); - $_clientCredentials->setRsaPrivateKey($clientCredentials['rsa_private_key']); - $_clientCredentials->setRsaPublicKey($clientCredentials['rsa_public_key']); - } else { - $_clientCredentials = new ClientCredentials(); - } - - $_clientCredentials->setIdentifier($clientCredentials['identifier']); - $_clientCredentials->setSecret($clientCredentials['secret']); - - if (isset($clientCredentials['callback_uri'])) { - $_clientCredentials->setCallbackUri($clientCredentials['callback_uri']); - } - - return $_clientCredentials; - } - - /** - * Handle a bad response coming back when getting temporary credentials. - * - * @param BadResponseException $e - * - * @return void - * - * @throws CredentialsException - */ - protected function handleTemporaryCredentialsBadResponse(BadResponseException $e) - { - $response = $e->getResponse(); - $body = $response->getBody(); - $statusCode = $response->getStatusCode(); - - throw new CredentialsException( - "Received HTTP status code [$statusCode] with message \"$body\" when getting temporary credentials." - ); - } - - /** - * Creates temporary credentials from the body response. - * - * @param string $body - * - * @return TemporaryCredentials - */ - protected function createTemporaryCredentials($body) - { - parse_str($body, $data); - - if ( ! $data || ! is_array($data)) { - throw new CredentialsException('Unable to parse temporary credentials response.'); - } - - if ( ! isset($data['oauth_callback_confirmed']) || $data['oauth_callback_confirmed'] != 'true') { - throw new CredentialsException('Error in retrieving temporary credentials.'); - } - - $temporaryCredentials = new TemporaryCredentials(); - $temporaryCredentials->setIdentifier($data['oauth_token']); - $temporaryCredentials->setSecret($data['oauth_token_secret']); - - return $temporaryCredentials; - } - - /** - * Handle a bad response coming back when getting token credentials. - * - * @param BadResponseException $e - * - * @return void - * - * @throws CredentialsException - */ - protected function handleTokenCredentialsBadResponse(BadResponseException $e) - { - $response = $e->getResponse(); - $body = $response->getBody(); - $statusCode = $response->getStatusCode(); - - throw new CredentialsException( - "Received HTTP status code [$statusCode] with message \"$body\" when getting token credentials." - ); - } - - /** - * Creates token credentials from the body response. - * - * @param string $body - * - * @return TokenCredentials - */ - protected function createTokenCredentials($body) - { - parse_str($body, $data); - - if ( ! $data || ! is_array($data)) { - throw new CredentialsException('Unable to parse token credentials response.'); - } - - if (isset($data['error'])) { - throw new CredentialsException("Error [{$data['error']}] in retrieving token credentials."); - } - - $tokenCredentials = new TokenCredentials(); - $tokenCredentials->setIdentifier($data['oauth_token']); - $tokenCredentials->setSecret($data['oauth_token_secret']); - - return $tokenCredentials; - } - - /** - * Get the base protocol parameters for an OAuth request. - * Each request builds on these parameters. - * - * @return array - * - * @see OAuth 1.0 RFC 5849 Section 3.1 - */ - protected function baseProtocolParameters() - { - $dateTime = new \DateTime(); - - return [ - 'oauth_consumer_key' => $this->clientCredentials->getIdentifier(), - 'oauth_nonce' => $this->nonce(), - 'oauth_signature_method' => $this->signature->method(), - 'oauth_timestamp' => $dateTime->format('U'), - 'oauth_version' => '1.0', - ]; - } - - /** - * Any additional required protocol parameters for an - * OAuth request. - * - * @return array - */ - protected function additionalProtocolParameters() - { - return []; - } - - /** - * Generate the OAuth protocol header for a temporary credentials - * request, based on the URI. - * - * @param string $uri - * - * @return string - */ - protected function temporaryCredentialsProtocolHeader($uri) - { - $parameters = array_merge($this->baseProtocolParameters(), [ - 'oauth_callback' => $this->clientCredentials->getCallbackUri(), - ]); - - $parameters['oauth_signature'] = $this->signature->sign($uri, $parameters, 'POST'); - - return $this->normalizeProtocolParameters($parameters); - } - - /** - * Generate the OAuth protocol header for requests other than temporary - * credentials, based on the URI, method, given credentials & body query - * string. - * - * @param string $method - * @param string $uri - * @param CredentialsInterface $credentials - * @param array $bodyParameters - * - * @return string - */ - protected function protocolHeader($method, $uri, CredentialsInterface $credentials, array $bodyParameters = []) - { - $parameters = array_merge( - $this->baseProtocolParameters(), - $this->additionalProtocolParameters(), - [ - 'oauth_token' => $credentials->getIdentifier(), - ] - ); - - $this->signature->setCredentials($credentials); - - $parameters['oauth_signature'] = $this->signature->sign( - $uri, - array_merge($parameters, $bodyParameters), - $method - ); - - return $this->normalizeProtocolParameters($parameters); - } - - /** - * Takes an array of protocol parameters and normalizes them - * to be used as a HTTP header. - * - * @param array $parameters - * - * @return string - */ - protected function normalizeProtocolParameters(array $parameters) - { - array_walk($parameters, function (&$value, $key) { - $value = rawurlencode($key) . '="' . rawurlencode($value) . '"'; - }); - - return 'OAuth ' . implode(', ', $parameters); - } - - /** - * Generate a random string. - * - * @param int $length - * - * @return string - * - * @see OAuth 1.0 RFC 5849 Section 3.3 - */ - protected function nonce($length = 32) - { - $pool = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; - - return substr(str_shuffle(str_repeat($pool, 5)), 0, $length); - } - - /** - * Build a url by combining hostname and query string after checking for - * exisiting '?' character in host. - * - * @param string $host - * @param string $queryString - * - * @return string - */ - protected function buildUrl($host, $queryString) - { - return $host . (strpos($host, '?') !== false ? '&' : '?') . $queryString; - } - - /** - * Get the URL for retrieving temporary credentials. - * - * @return string - */ - abstract public function urlTemporaryCredentials(); - - /** - * Get the URL for redirecting the resource owner to authorize the client. - * - * @return string - */ - abstract public function urlAuthorization(); - - /** - * Get the URL retrieving token credentials. - * - * @return string - */ - abstract public function urlTokenCredentials(); - - /** - * Get the URL for retrieving user details. - * - * @return string - */ - abstract public function urlUserDetails(); - - /** - * Take the decoded data from the user details URL and convert - * it to a User object. - * - * @param mixed $data - * @param TokenCredentials $tokenCredentials - * - * @return User - */ - abstract public function userDetails($data, TokenCredentials $tokenCredentials); - - /** - * Take the decoded data from the user details URL and extract - * the user's UID. - * - * @param mixed $data - * @param TokenCredentials $tokenCredentials - * - * @return string|int - */ - abstract public function userUid($data, TokenCredentials $tokenCredentials); - - /** - * Take the decoded data from the user details URL and extract - * the user's email. - * - * @param mixed $data - * @param TokenCredentials $tokenCredentials - * - * @return string|null - */ - abstract public function userEmail($data, TokenCredentials $tokenCredentials); - - /** - * Take the decoded data from the user details URL and extract - * the user's screen name. - * - * @param mixed $data - * @param TokenCredentials $tokenCredentials - * - * @return string|null - */ - abstract public function userScreenName($data, TokenCredentials $tokenCredentials); -} diff --git a/vendor/league/oauth1-client/src/Server/Trello.php b/vendor/league/oauth1-client/src/Server/Trello.php deleted file mode 100644 index 8bb4afbbb..000000000 --- a/vendor/league/oauth1-client/src/Server/Trello.php +++ /dev/null @@ -1,254 +0,0 @@ -parseConfiguration($clientCredentials); - } - } - - /** - * Set the access token. - * - * @param string $accessToken - * - * @return Trello - */ - public function setAccessToken($accessToken) - { - $this->accessToken = $accessToken; - - return $this; - } - - /** - * Set the application expiration. - * - * @param string $applicationExpiration - * - * @return Trello - */ - public function setApplicationExpiration($applicationExpiration) - { - $this->applicationExpiration = $applicationExpiration; - - return $this; - } - - /** - * Get application expiration. - * - * @return string - */ - public function getApplicationExpiration() - { - return $this->applicationExpiration ?: '1day'; - } - - /** - * Set the application name. - * - * @param string $applicationName - * - * @return Trello - */ - public function setApplicationName($applicationName) - { - $this->applicationName = $applicationName; - - return $this; - } - - /** - * Get application name. - * - * @return string|null - */ - public function getApplicationName() - { - return $this->applicationName ?: null; - } - - /** - * Set the application scope. - * - * @param string $applicationScope - * - * @return Trello - */ - public function setApplicationScope($applicationScope) - { - $this->applicationScope = $applicationScope; - - return $this; - } - - /** - * Get application scope. - * - * @return string - */ - public function getApplicationScope() - { - return $this->applicationScope ?: 'read'; - } - - /** - * @inheritDoc - */ - public function urlTemporaryCredentials() - { - return 'https://trello.com/1/OAuthGetRequestToken'; - } - - /** - * @inheritDoc - */ - public function urlAuthorization() - { - return 'https://trello.com/1/OAuthAuthorizeToken?' . - $this->buildAuthorizationQueryParameters(); - } - - /** - * @inheritDoc - */ - public function urlTokenCredentials() - { - return 'https://trello.com/1/OAuthGetAccessToken'; - } - - /** - * @inheritDoc - */ - public function urlUserDetails() - { - return 'https://trello.com/1/members/me?key=' . $this->applicationKey . '&token=' . $this->accessToken; - } - - /** - * @inheritDoc - */ - public function userDetails($data, TokenCredentials $tokenCredentials) - { - $user = new User(); - - $user->nickname = $data['username']; - $user->name = $data['fullName']; - - $user->extra = (array) $data; - - return $user; - } - - /** - * @inheritDoc - */ - public function userUid($data, TokenCredentials $tokenCredentials) - { - return $data['id']; - } - - /** - * @inheritDoc - */ - public function userEmail($data, TokenCredentials $tokenCredentials) - { - return null; - } - - /** - * @inheritDoc - */ - public function userScreenName($data, TokenCredentials $tokenCredentials) - { - return $data['username']; - } - - /** - * Build authorization query parameters. - * - * @return string - */ - private function buildAuthorizationQueryParameters() - { - $params = [ - 'response_type' => 'fragment', - 'scope' => $this->getApplicationScope(), - 'expiration' => $this->getApplicationExpiration(), - 'name' => $this->getApplicationName(), - ]; - - return http_build_query($params); - } - - /** - * Parse configuration array to set attributes. - * - * @param array $configuration - * - * @return void - */ - private function parseConfiguration(array $configuration = []) - { - $configToPropertyMap = [ - 'identifier' => 'applicationKey', - 'expiration' => 'applicationExpiration', - 'name' => 'applicationName', - 'scope' => 'applicationScope', - ]; - - foreach ($configToPropertyMap as $config => $property) { - if (isset($configuration[$config])) { - $this->$property = $configuration[$config]; - } - } - } -} diff --git a/vendor/league/oauth1-client/src/Server/Tumblr.php b/vendor/league/oauth1-client/src/Server/Tumblr.php deleted file mode 100644 index c97095348..000000000 --- a/vendor/league/oauth1-client/src/Server/Tumblr.php +++ /dev/null @@ -1,101 +0,0 @@ -nickname = $data['name']; - - // Save all extra data - $used = ['name']; - $user->extra = array_diff_key($data, array_flip($used)); - - return $user; - } - - /** - * @inheritDoc - */ - public function userUid($data, TokenCredentials $tokenCredentials) - { - if ( ! isset($data['response']['user']) || ! is_array($data['response']['user'])) { - throw new LogicException('Not possible to get user UUID'); - } - - $data = $data['response']['user']; - - return $data['name']; - } - - /** - * @inheritDoc - */ - public function userEmail($data, TokenCredentials $tokenCredentials) - { - return null; - } - - /** - * @inheritDoc - */ - public function userScreenName($data, TokenCredentials $tokenCredentials) - { - if ( ! isset($data['response']['user']) || ! is_array($data['response']['user'])) { - throw new LogicException('Not possible to get user screen name'); - } - - $data = $data['response']['user']; - - return $data['name']; - } -} diff --git a/vendor/league/oauth1-client/src/Server/Twitter.php b/vendor/league/oauth1-client/src/Server/Twitter.php deleted file mode 100644 index b67b606ca..000000000 --- a/vendor/league/oauth1-client/src/Server/Twitter.php +++ /dev/null @@ -1,100 +0,0 @@ -uid = $data['id_str']; - $user->nickname = $data['screen_name']; - $user->name = $data['name']; - $user->location = $data['location']; - $user->description = $data['description']; - $user->imageUrl = $data['profile_image_url']; - - if (isset($data['email'])) { - $user->email = $data['email']; - } - - $used = ['id', 'screen_name', 'name', 'location', 'description', 'profile_image_url', 'email']; - - foreach ($data as $key => $value) { - if (strpos($key, 'url') !== false) { - if ( ! in_array($key, $used)) { - $used[] = $key; - } - - $user->urls[$key] = $value; - } - } - - // Save all extra data - $user->extra = array_diff_key($data, array_flip($used)); - - return $user; - } - - /** - * @inheritDoc - */ - public function userUid($data, TokenCredentials $tokenCredentials) - { - return $data['id']; - } - - /** - * @inheritDoc - */ - public function userEmail($data, TokenCredentials $tokenCredentials) - { - return null; - } - - /** - * @inheritDoc - */ - public function userScreenName($data, TokenCredentials $tokenCredentials) - { - return $data['name']; - } -} diff --git a/vendor/league/oauth1-client/src/Server/User.php b/vendor/league/oauth1-client/src/Server/User.php deleted file mode 100644 index 20bcc7c60..000000000 --- a/vendor/league/oauth1-client/src/Server/User.php +++ /dev/null @@ -1,134 +0,0 @@ -{$key})) { - $this->{$key} = $value; - } - } - - /** - * Tells if a property is set. - * - * @param string $key - * - * @return bool - */ - public function __isset($key) - { - return isset($this->{$key}); - } - - /** - * Get a property from the user. - * - * @param string $key - * - * @return mixed - */ - public function __get($key) - { - if (isset($this->{$key})) { - return $this->{$key}; - } - } - - /** - * @inheritDoc - */ - public function getIterator() - { - return new ArrayIterator(get_object_vars($this)); - } -} diff --git a/vendor/league/oauth1-client/src/Server/Uservoice.php b/vendor/league/oauth1-client/src/Server/Uservoice.php deleted file mode 100644 index f9bbc77e7..000000000 --- a/vendor/league/oauth1-client/src/Server/Uservoice.php +++ /dev/null @@ -1,130 +0,0 @@ -parseConfigurationArray($clientCredentials); - } - } - - /** - * @inheritDoc - */ - public function urlTemporaryCredentials() - { - return $this->base . '/oauth/request_token'; - } - - /** - * @inheritDoc - */ - public function urlAuthorization() - { - return $this->base . '/oauth/authorize'; - } - - /** - * @inheritDoc - */ - public function urlTokenCredentials() - { - return $this->base . '/oauth/access_token'; - } - - /** - * @inheritDoc - */ - public function urlUserDetails() - { - return $this->base . '/api/v1/users/current.json'; - } - - /** - * @inheritDoc - */ - public function userDetails($data, TokenCredentials $tokenCredentials) - { - $user = new User(); - - $user->uid = $data['user']['id']; - $user->name = $data['user']['name']; - $user->imageUrl = $data['user']['avatar_url']; - $user->email = $data['user']['email']; - - if ($data['user']['name']) { - $parts = explode(' ', $data['user']['name'], 2); - - $user->firstName = $parts[0]; - - if (2 === count($parts)) { - $user->lastName = $parts[1]; - } - } - - $user->urls[] = $data['user']['url']; - - return $user; - } - - /** - * @inheritDoc - */ - public function userUid($data, TokenCredentials $tokenCredentials) - { - return $data['user']['id']; - } - - /** - * @inheritDoc - */ - public function userEmail($data, TokenCredentials $tokenCredentials) - { - return $data['user']['email']; - } - - /** - * @inheritDoc - */ - public function userScreenName($data, TokenCredentials $tokenCredentials) - { - return $data['user']['name']; - } - - /** - * Parse configuration array to set attributes. - * - * @param array $configuration - * - * @return void - * - * @throws InvalidArgumentException - */ - private function parseConfigurationArray(array $configuration = []) - { - if (isset($configuration['host'])) { - throw new InvalidArgumentException('Missing host'); - } - - $this->base = trim($configuration['host'], '/'); - } -} diff --git a/vendor/league/oauth1-client/src/Server/Xing.php b/vendor/league/oauth1-client/src/Server/Xing.php deleted file mode 100644 index 17516c0eb..000000000 --- a/vendor/league/oauth1-client/src/Server/Xing.php +++ /dev/null @@ -1,95 +0,0 @@ -uid = $data['id']; - $user->nickname = $data['display_name']; - $user->name = $data['display_name']; - $user->firstName = $data['first_name']; - $user->lastName = $data['last_name']; - $user->location = $data['private_address']['country']; - - if ($user->location == '') { - $user->location = $data['business_address']['country']; - } - $user->description = $data['employment_status']; - $user->imageUrl = $data['photo_urls']['maxi_thumb']; - $user->email = $data['active_email']; - - $user->urls['permalink'] = $data['permalink']; - - return $user; - } - /** - * @inheritDoc - */ - public function userUid($data, TokenCredentials $tokenCredentials) - { - $data = $data['users'][0]; - - return $data['id']; - } - /** - * @inheritDoc - */ - public function userEmail($data, TokenCredentials $tokenCredentials) - { - $data = $data['users'][0]; - - return $data['active_email']; - } - /** - * @inheritDoc - */ - public function userScreenName($data, TokenCredentials $tokenCredentials) - { - $data = $data['users'][0]; - - return $data['display_name']; - } -} diff --git a/vendor/league/oauth1-client/src/Signature/EncodesUrl.php b/vendor/league/oauth1-client/src/Signature/EncodesUrl.php deleted file mode 100644 index 5aab03ebc..000000000 --- a/vendor/league/oauth1-client/src/Signature/EncodesUrl.php +++ /dev/null @@ -1,115 +0,0 @@ - $url->getScheme(), - 'host' => $url->getHost(), - 'port' => $url->getPort(), - 'path' => $url->getPath(), - ]); - - $baseString .= rawurlencode($schemeHostPath) . '&'; - - parse_str($url->getQuery(), $query); - $data = array_merge($query, $parameters); - - // normalize data key/values - $data = $this->normalizeArray($data); - ksort($data); - - $baseString .= $this->queryStringFromData($data); - - return $baseString; - } - - /** - * Return a copy of the given array with all keys and values rawurlencoded. - * - * @param array $array Array to normalize - * - * @return array Normalized array - */ - protected function normalizeArray(array $array = []) - { - $normalizedArray = []; - - foreach ($array as $key => $value) { - $key = rawurlencode(rawurldecode($key)); - - if (is_array($value)) { - $normalizedArray[$key] = $this->normalizeArray($value); - } else { - $normalizedArray[$key] = rawurlencode(rawurldecode($value)); - } - } - - return $normalizedArray; - } - - /** - * Creates an array of rawurlencoded strings out of each array key/value pair - * Handles multi-dimensional arrays recursively. - * - * @param array $data Array of parameters to convert. - * @param array|null $queryParams Array to extend. False by default. - * @param string $prevKey Optional Array key to append - * - * @return string rawurlencoded string version of data - */ - protected function queryStringFromData($data, $queryParams = null, $prevKey = '') - { - if ($initial = (null === $queryParams)) { - $queryParams = []; - } - - foreach ($data as $key => $value) { - if ($prevKey) { - $key = $prevKey . '[' . $key . ']'; // Handle multi-dimensional array - } - if (is_array($value)) { - $queryParams = $this->queryStringFromData($value, $queryParams, $key); - } else { - $queryParams[] = rawurlencode($key . '=' . $value); // join with equals sign - } - } - - if ($initial) { - return implode('%26', $queryParams); // join with ampersand - } - - return $queryParams; - } -} diff --git a/vendor/league/oauth1-client/src/Signature/HmacSha1Signature.php b/vendor/league/oauth1-client/src/Signature/HmacSha1Signature.php deleted file mode 100644 index 6e7b3f1db..000000000 --- a/vendor/league/oauth1-client/src/Signature/HmacSha1Signature.php +++ /dev/null @@ -1,40 +0,0 @@ -createUrl($uri); - - $baseString = $this->baseString($url, $method, $parameters); - - return base64_encode($this->hash($baseString)); - } - - /** - * Hashes a string with the signature's key. - * - * @param string $string - * - * @return string - */ - protected function hash($string) - { - return hash_hmac('sha1', $string, $this->key(), true); - } -} diff --git a/vendor/league/oauth1-client/src/Signature/PlainTextSignature.php b/vendor/league/oauth1-client/src/Signature/PlainTextSignature.php deleted file mode 100644 index c7a04cced..000000000 --- a/vendor/league/oauth1-client/src/Signature/PlainTextSignature.php +++ /dev/null @@ -1,22 +0,0 @@ -key(); - } -} diff --git a/vendor/league/oauth1-client/src/Signature/RsaSha1Signature.php b/vendor/league/oauth1-client/src/Signature/RsaSha1Signature.php deleted file mode 100644 index b694c8ce0..000000000 --- a/vendor/league/oauth1-client/src/Signature/RsaSha1Signature.php +++ /dev/null @@ -1,35 +0,0 @@ -createUrl($uri); - $baseString = $this->baseString($url, $method, $parameters); - - /** @var RsaClientCredentials $clientCredentials */ - $clientCredentials = $this->clientCredentials; - $privateKey = $clientCredentials->getRsaPrivateKey(); - - openssl_sign($baseString, $signature, $privateKey); - - return base64_encode($signature); - } -} diff --git a/vendor/league/oauth1-client/src/Signature/Signature.php b/vendor/league/oauth1-client/src/Signature/Signature.php deleted file mode 100644 index d4c9eeb4e..000000000 --- a/vendor/league/oauth1-client/src/Signature/Signature.php +++ /dev/null @@ -1,55 +0,0 @@ -clientCredentials = $clientCredentials; - } - - /** - * @inheritDoc - */ - public function setCredentials(CredentialsInterface $credentials) - { - $this->credentials = $credentials; - } - - /** - * Generate a signing key. - * - * @return string - */ - protected function key() - { - $key = rawurlencode($this->clientCredentials->getSecret()) . '&'; - - if ($this->credentials !== null) { - $key .= rawurlencode($this->credentials->getSecret()); - } - - return $key; - } -} diff --git a/vendor/league/oauth1-client/src/Signature/SignatureInterface.php b/vendor/league/oauth1-client/src/Signature/SignatureInterface.php deleted file mode 100644 index 8aeb87c63..000000000 --- a/vendor/league/oauth1-client/src/Signature/SignatureInterface.php +++ /dev/null @@ -1,46 +0,0 @@ -assertNull($credentials->getIdentifier()); - $credentials->setIdentifier('foo'); - $this->assertEquals('foo', $credentials->getIdentifier()); - $this->assertNull($credentials->getSecret()); - $credentials->setSecret('foo'); - $this->assertEquals('foo', $credentials->getSecret()); - } -} diff --git a/vendor/league/oauth1-client/tests/HmacSha1SignatureTest.php b/vendor/league/oauth1-client/tests/HmacSha1SignatureTest.php deleted file mode 100644 index 3275b2419..000000000 --- a/vendor/league/oauth1-client/tests/HmacSha1SignatureTest.php +++ /dev/null @@ -1,156 +0,0 @@ -getMockClientCredentials()); - - $uri = 'http://www.example.com/?qux=corge'; - $parameters = ['foo' => 'bar', 'baz' => null]; - - $this->assertEquals('A3Y7C1SUHXR1EBYIUlT3d6QT1cQ=', $signature->sign($uri, $parameters)); - } - - public function testSigningRequestWhereThePortIsNotStandard() - { - $signature = new HmacSha1Signature($this->getMockClientCredentials()); - - $uri = 'http://www.example.com:8080/?qux=corge'; - $parameters = ['foo' => 'bar', 'baz' => null]; - - $this->assertEquals('ECcWxyi5UOC1G0MxH0ygm6Pd6JE=', $signature->sign($uri, $parameters)); - } - - public function testQueryStringFromArray() - { - $array = ['a' => 'b']; - $res = $this->invokeQueryStringFromData($array); - - $this->assertSame( - 'a%3Db', - $res - ); - } - - public function testQueryStringFromIndexedArray() - { - $array = ['a', 'b']; - $res = $this->invokeQueryStringFromData($array); - - $this->assertSame( - '0%3Da%261%3Db', - $res - ); - } - - public function testQueryStringFromMultiDimensionalArray() - { - $array = [ - 'a' => [ - 'b' => [ - 'c' => 'd', - ], - 'e' => [ - 'f' => 'g', - ], - ], - 'h' => 'i', - 'empty' => '', - 'null' => null, - 'false' => false, - ]; - - // Convert to query string. - $res = $this->invokeQueryStringFromData($array); - - $this->assertSame( - 'a%5Bb%5D%5Bc%5D%3Dd%26a%5Be%5D%5Bf%5D%3Dg%26h%3Di%26empty%3D%26null%3D%26false%3D', - $res - ); - - // Reverse engineer the string. - $res = urldecode($res); - - $this->assertSame( - 'a[b][c]=d&a[e][f]=g&h=i&empty=&null=&false=', - $res - ); - - // Finally, parse the string back to an array. - parse_str($res, $original_array); - - // And ensure it matches the orignal array (approximately). - $this->assertSame( - [ - 'a' => [ - 'b' => [ - 'c' => 'd', - ], - 'e' => [ - 'f' => 'g', - ], - ], - 'h' => 'i', - 'empty' => '', - 'null' => '', // null value gets lost in string translation - 'false' => '', // false value gets lost in string translation - ], - $original_array - ); - } - - public function testSigningRequestWithMultiDimensionalParams() - { - $signature = new HmacSha1Signature($this->getMockClientCredentials()); - - $uri = 'http://www.example.com/'; - $parameters = [ - 'a' => [ - 'b' => [ - 'c' => 'd', - ], - 'e' => [ - 'f' => 'g', - ], - ], - 'h' => 'i', - 'empty' => '', - 'null' => null, - 'false' => false, - ]; - - $this->assertEquals('ZUxiJKugeEplaZm9e4hshN0I70U=', $signature->sign($uri, $parameters)); - } - - protected function invokeQueryStringFromData(array $args) - { - $signature = new HmacSha1Signature(m::mock('League\OAuth1\Client\Credentials\ClientCredentialsInterface')); - $refl = new \ReflectionObject($signature); - $method = $refl->getMethod('queryStringFromData'); - $method->setAccessible(true); - - return $method->invokeArgs($signature, [$args]); - } - - protected function getMockClientCredentials() - { - $clientCredentials = m::mock('League\OAuth1\Client\Credentials\ClientCredentialsInterface'); - $clientCredentials->shouldReceive('getSecret')->andReturn('clientsecret'); - - return $clientCredentials; - } -} diff --git a/vendor/league/oauth1-client/tests/PlainTextSignatureTest.php b/vendor/league/oauth1-client/tests/PlainTextSignatureTest.php deleted file mode 100644 index 7d48b69f4..000000000 --- a/vendor/league/oauth1-client/tests/PlainTextSignatureTest.php +++ /dev/null @@ -1,43 +0,0 @@ -getMockClientCredentials()); - $this->assertEquals('clientsecret&', $signature->sign($uri = 'http://www.example.com/')); - - $signature->setCredentials($this->getMockCredentials()); - $this->assertEquals('clientsecret&tokensecret', $signature->sign($uri)); - $this->assertEquals('PLAINTEXT', $signature->method()); - } - - protected function getMockClientCredentials() - { - $clientCredentials = m::mock('League\OAuth1\Client\Credentials\ClientCredentialsInterface'); - $clientCredentials->shouldReceive('getSecret')->andReturn('clientsecret'); - - return $clientCredentials; - } - - protected function getMockCredentials() - { - $credentials = m::mock('League\OAuth1\Client\Credentials\CredentialsInterface'); - $credentials->shouldReceive('getSecret')->andReturn('tokensecret'); - - return $credentials; - } -} diff --git a/vendor/league/oauth1-client/tests/RsaClientCredentialsTest.php b/vendor/league/oauth1-client/tests/RsaClientCredentialsTest.php deleted file mode 100644 index 1609093c4..000000000 --- a/vendor/league/oauth1-client/tests/RsaClientCredentialsTest.php +++ /dev/null @@ -1,75 +0,0 @@ -setRsaPublicKey(__DIR__ . '/test_rsa_publickey.pem'); - - /** @var resource|OpenSSLAsymmetricKey $key */ - $key = $credentials->getRsaPublicKey(); - $this->assertFalse(is_null($key)); - - $this->assertEquals($key, $credentials->getRsaPublicKey()); - } - - public function testGetRsaPublicKeyNotExists() - { - $this->expectException(CredentialsException::class); - - $credentials = new RsaClientCredentials(); - $credentials->setRsaPublicKey('fail'); - - $credentials->getRsaPublicKey(); - } - - public function testGetRsaPublicKeyInvalid() - { - $this->expectException(CredentialsException::class); - - $credentials = new RsaClientCredentials(); - $credentials->setRsaPublicKey(__DIR__ . '/test_rsa_invalidkey.pem'); - - $credentials->getRsaPublicKey(); - } - - public function testGetRsaPrivateKey() - { - $credentials = new RsaClientCredentials(); - $credentials->setRsaPrivateKey(__DIR__ . '/test_rsa_privatekey.pem'); - - /** @var resource|OpenSSLAsymmetricKey $key */ - $key = $credentials->getRsaPrivateKey(); - $this->assertFalse(is_null($key)); - - $this->assertEquals($key, $credentials->getRsaPrivateKey()); - } - - public function testGetRsaPrivateKeyNotExists() - { - $this->expectException(CredentialsException::class); - - $credentials = new RsaClientCredentials(); - $credentials->setRsaPrivateKey('fail'); - - $credentials->getRsaPrivateKey(); - } - - public function testGetRsaPrivateKeyInvalid() - { - $this->expectException(CredentialsException::class); - - $credentials = new RsaClientCredentials(); - $credentials->setRsaPrivateKey(__DIR__ . '/test_rsa_invalidkey.pem'); - - $credentials->getRsaPrivateKey(); - } -} diff --git a/vendor/league/oauth1-client/tests/RsaSha1SignatureTest.php b/vendor/league/oauth1-client/tests/RsaSha1SignatureTest.php deleted file mode 100644 index 068944ae1..000000000 --- a/vendor/league/oauth1-client/tests/RsaSha1SignatureTest.php +++ /dev/null @@ -1,148 +0,0 @@ -getClientCredentials()); - $this->assertEquals('RSA-SHA1', $signature->method()); - } - - public function testSigningRequest() - { - $signature = new RsaSha1Signature($this->getClientCredentials()); - - $uri = 'http://www.example.com/?qux=corge'; - $parameters = ['foo' => 'bar', 'baz' => null]; - - $this->assertEquals('h8vpV4CYnLwss+rWicKE4sY6AiW2+DT6Fe7qB8jA7LSLhX5jvLEeX1D8E2ynSePSksAY48j+OSLu9vo5juS2duwNK8UA2Rtnnvuj6UFxpx70dpjHAsQg6EbycGptL/SChDkxfpG8LhuwX1FlFa+H0jLYXI5Dy8j90g51GRJbj48=', $signature->sign($uri, $parameters)); - } - - public function testQueryStringFromArray() - { - $array = ['a' => 'b']; - $res = $this->invokeQueryStringFromData($array); - - $this->assertSame( - 'a%3Db', - $res - ); - } - - public function testQueryStringFromIndexedArray() - { - $array = ['a', 'b']; - $res = $this->invokeQueryStringFromData($array); - - $this->assertSame( - '0%3Da%261%3Db', - $res - ); - } - - public function testQueryStringFromMultiDimensionalArray() - { - $array = [ - 'a' => [ - 'b' => [ - 'c' => 'd', - ], - 'e' => [ - 'f' => 'g', - ], - ], - 'h' => 'i', - 'empty' => '', - 'null' => null, - 'false' => false, - ]; - - // Convert to query string. - $res = $this->invokeQueryStringFromData($array); - - $this->assertSame( - 'a%5Bb%5D%5Bc%5D%3Dd%26a%5Be%5D%5Bf%5D%3Dg%26h%3Di%26empty%3D%26null%3D%26false%3D', - $res - ); - - // Reverse engineer the string. - $res = urldecode($res); - - $this->assertSame( - 'a[b][c]=d&a[e][f]=g&h=i&empty=&null=&false=', - $res - ); - - // Finally, parse the string back to an array. - parse_str($res, $original_array); - - // And ensure it matches the orignal array (approximately). - $this->assertSame( - [ - 'a' => [ - 'b' => [ - 'c' => 'd', - ], - 'e' => [ - 'f' => 'g', - ], - ], - 'h' => 'i', - 'empty' => '', - 'null' => '', // null value gets lost in string translation - 'false' => '', // false value gets lost in string translation - ], - $original_array - ); - } - - public function testSigningRequestWithMultiDimensionalParams() - { - $signature = new RsaSha1Signature($this->getClientCredentials()); - - $uri = 'http://www.example.com/'; - $parameters = [ - 'a' => [ - 'b' => [ - 'c' => 'd', - ], - 'e' => [ - 'f' => 'g', - ], - ], - 'h' => 'i', - 'empty' => '', - 'null' => null, - 'false' => false, - ]; - - $this->assertEquals('X9EkmOEbA5CoF2Hicf3ciAumpp1zkKxnVZkh/mEwWyF2DDcrfou9XF11WvbBu3G4loJGeX4GY1FsIrQpsjEILbn0e7Alyii/x8VA9mBwdqMhQVl49jF0pdowocc03M04cAbAOMNObT7tMmDs+YTFgRxEGCiUkq9AizP1cW3+eBo=', $signature->sign($uri, $parameters)); - } - - protected function invokeQueryStringFromData(array $args) - { - $signature = new RsaSha1Signature(Mockery::mock(ClientCredentialsInterface::class)); - $refl = new \ReflectionObject($signature); - $method = $refl->getMethod('queryStringFromData'); - $method->setAccessible(true); - - return $method->invokeArgs($signature, [$args]); - } - - protected function getClientCredentials() - { - $credentials = new RsaClientCredentials(); - $credentials->setRsaPublicKey(__DIR__ . '/test_rsa_publickey.pem'); - $credentials->setRsaPrivateKey(__DIR__ . '/test_rsa_privatekey.pem'); - - return $credentials; - } -} diff --git a/vendor/league/oauth1-client/tests/ServerTest.php b/vendor/league/oauth1-client/tests/ServerTest.php deleted file mode 100644 index e355dd560..000000000 --- a/vendor/league/oauth1-client/tests/ServerTest.php +++ /dev/null @@ -1,313 +0,0 @@ -getMockClientCredentials()); - - $credentials = $server->getClientCredentials(); - $this->assertInstanceOf('League\OAuth1\Client\Credentials\ClientCredentialsInterface', $credentials); - $this->assertEquals('myidentifier', $credentials->getIdentifier()); - $this->assertEquals('mysecret', $credentials->getSecret()); - $this->assertEquals('http://app.dev/', $credentials->getCallbackUri()); - } - - public function testCreatingWithArrayRsa() - { - $config = [ - 'identifier' => 'app_key', - 'secret' => 'secret', - 'callback_uri' => 'https://example.com/callback', - 'rsa_public_key' => __DIR__ . '/test_rsa_publickey.pem', - 'rsa_private_key' => __DIR__ . '/test_rsa_privatekey.pem', - ]; - $server = new ServerStub($config); - - $credentials = $server->getClientCredentials(); - $this->assertInstanceOf(RsaClientCredentials::class, $credentials); - - $signature = $server->getSignature(); - $this->assertInstanceOf(RsaSha1Signature::class, $signature); - } - - public function testCreatingWithObject() - { - $credentials = new ClientCredentials; - $credentials->setIdentifier('myidentifier'); - $credentials->setSecret('mysecret'); - $credentials->setCallbackUri('http://app.dev/'); - - $server = new ServerStub($credentials); - - $this->assertEquals($credentials, $server->getClientCredentials()); - } - - public function testCreatingWithInvalidInput() - { - $this->expectException(InvalidArgumentException::class); - - new ServerStub(uniqid()); - } - - public function testGettingTemporaryCredentials() - { - $server = m::mock('League\OAuth1\Client\Tests\ServerStub[createHttpClient]', [$this->getMockClientCredentials()]); - - $server->shouldReceive('createHttpClient')->andReturn($client = m::mock('stdClass')); - - $me = $this; - $client->shouldReceive('post')->with('http://www.example.com/temporary', m::on(function ($options) use ($me) { - $headers = $options['headers']; - - $me->assertTrue(isset($headers['Authorization'])); - - // OAuth protocol specifies a strict number of - // headers should be sent, in the correct order. - // We'll validate that here. - $pattern - = '/OAuth oauth_consumer_key=".*?", oauth_nonce="[a-zA-Z0-9]+", oauth_signature_method="HMAC-SHA1", oauth_timestamp="\d{10}", oauth_version="1.0", oauth_callback="' - . preg_quote('http%3A%2F%2Fapp.dev%2F', '/') . '", oauth_signature=".*?"/'; - - $matches = preg_match($pattern, $headers['Authorization']); - $me->assertEquals(1, $matches, 'Asserting that the authorization header contains the correct expression.'); - - return true; - }))->once()->andReturn($response = m::mock('stdClass')); - $response->shouldReceive('getBody') - ->andReturn('oauth_token=temporarycredentialsidentifier&oauth_token_secret=temporarycredentialssecret&oauth_callback_confirmed=true'); - - $credentials = $server->getTemporaryCredentials(); - $this->assertInstanceOf('League\OAuth1\Client\Credentials\TemporaryCredentials', $credentials); - $this->assertEquals('temporarycredentialsidentifier', $credentials->getIdentifier()); - $this->assertEquals('temporarycredentialssecret', $credentials->getSecret()); - } - - public function testGettingAuthorizationUrl() - { - $server = new ServerStub($this->getMockClientCredentials()); - - $expected = 'http://www.example.com/authorize?oauth_token=foo'; - - $this->assertEquals($expected, $server->getAuthorizationUrl('foo')); - - $credentials = m::mock('League\OAuth1\Client\Credentials\TemporaryCredentials'); - $credentials->shouldReceive('getIdentifier')->andReturn('foo'); - $this->assertEquals($expected, $server->getAuthorizationUrl($credentials)); - } - - public function testGettingAuthorizationUrlWithOptions() - { - $server = new ServerStub($this->getMockClientCredentials()); - $expected = 'http://www.example.com/authorize?oauth_token=foo'; - $this->assertEquals($expected, $server->getAuthorizationUrl('foo', ['oauth_token' => 'bar'])); - - $expected = 'http://www.example.com/authorize?test=bar&oauth_token=foo'; - $this->assertEquals($expected, $server->getAuthorizationUrl('foo', ['test' => 'bar'])); - } - - public function testGettingTokenCredentialsFailsWithManInTheMiddle() - { - $server = new ServerStub($this->getMockClientCredentials()); - - $credentials = m::mock('League\OAuth1\Client\Credentials\TemporaryCredentials'); - $credentials->shouldReceive('getIdentifier')->andReturn('foo'); - - $this->expectException(InvalidArgumentException::class); - - $server->getTokenCredentials($credentials, 'bar', 'verifier'); - } - - public function testGettingTokenCredentials() - { - $server = m::mock('League\OAuth1\Client\Tests\ServerStub[createHttpClient]', [$this->getMockClientCredentials()]); - - $temporaryCredentials = m::mock('League\OAuth1\Client\Credentials\TemporaryCredentials'); - $temporaryCredentials->shouldReceive('getIdentifier')->andReturn('temporarycredentialsidentifier'); - $temporaryCredentials->shouldReceive('getSecret')->andReturn('temporarycredentialssecret'); - - $server->shouldReceive('createHttpClient')->andReturn($client = m::mock('stdClass')); - - $me = $this; - $client->shouldReceive('post')->with('http://www.example.com/token', m::on(function ($options) use ($me) { - $headers = $options['headers']; - $body = $options['form_params']; - - $me->assertTrue(isset($headers['Authorization'])); - $me->assertFalse(isset($headers['User-Agent'])); - - // OAuth protocol specifies a strict number of - // headers should be sent, in the correct order. - // We'll validate that here. - $pattern - = '/OAuth oauth_consumer_key=".*?", oauth_nonce="[a-zA-Z0-9]+", oauth_signature_method="HMAC-SHA1", oauth_timestamp="\d{10}", oauth_version="1.0", oauth_token="temporarycredentialsidentifier", oauth_signature=".*?"/'; - - $matches = preg_match($pattern, $headers['Authorization']); - $me->assertEquals(1, $matches, 'Asserting that the authorization header contains the correct expression.'); - - $me->assertSame($body, ['oauth_verifier' => 'myverifiercode']); - - return true; - }))->once()->andReturn($response = m::mock('stdClass')); - $response->shouldReceive('getBody') - ->andReturn('oauth_token=tokencredentialsidentifier&oauth_token_secret=tokencredentialssecret'); - - $credentials = $server->getTokenCredentials($temporaryCredentials, 'temporarycredentialsidentifier', 'myverifiercode'); - $this->assertInstanceOf('League\OAuth1\Client\Credentials\TokenCredentials', $credentials); - $this->assertEquals('tokencredentialsidentifier', $credentials->getIdentifier()); - $this->assertEquals('tokencredentialssecret', $credentials->getSecret()); - } - - public function testGettingTokenCredentialsWithUserAgent() - { - $userAgent = 'FooBar'; - $server = m::mock('League\OAuth1\Client\Tests\ServerStub[createHttpClient]', [$this->getMockClientCredentials()]); - - $temporaryCredentials = m::mock('League\OAuth1\Client\Credentials\TemporaryCredentials'); - $temporaryCredentials->shouldReceive('getIdentifier')->andReturn('temporarycredentialsidentifier'); - $temporaryCredentials->shouldReceive('getSecret')->andReturn('temporarycredentialssecret'); - - $server->shouldReceive('createHttpClient')->andReturn($client = m::mock('stdClass')); - - $me = $this; - $client->shouldReceive('post')->with('http://www.example.com/token', m::on(function ($options) use ($me, $userAgent) { - $headers = $options['headers']; - $body = $options['form_params']; - - $me->assertTrue(isset($headers['Authorization'])); - $me->assertTrue(isset($headers['User-Agent'])); - $me->assertEquals($userAgent, $headers['User-Agent']); - - // OAuth protocol specifies a strict number of - // headers should be sent, in the correct order. - // We'll validate that here. - $pattern - = '/OAuth oauth_consumer_key=".*?", oauth_nonce="[a-zA-Z0-9]+", oauth_signature_method="HMAC-SHA1", oauth_timestamp="\d{10}", oauth_version="1.0", oauth_token="temporarycredentialsidentifier", oauth_signature=".*?"/'; - - $matches = preg_match($pattern, $headers['Authorization']); - $me->assertEquals(1, $matches, 'Asserting that the authorization header contains the correct expression.'); - - $me->assertSame($body, ['oauth_verifier' => 'myverifiercode']); - - return true; - }))->once()->andReturn($response = m::mock('stdClass')); - $response->shouldReceive('getBody') - ->andReturn('oauth_token=tokencredentialsidentifier&oauth_token_secret=tokencredentialssecret'); - - $credentials = $server->setUserAgent($userAgent) - ->getTokenCredentials($temporaryCredentials, 'temporarycredentialsidentifier', 'myverifiercode'); - $this->assertInstanceOf('League\OAuth1\Client\Credentials\TokenCredentials', $credentials); - $this->assertEquals('tokencredentialsidentifier', $credentials->getIdentifier()); - $this->assertEquals('tokencredentialssecret', $credentials->getSecret()); - } - - public function testGettingUserDetails() - { - $server = m::mock( - 'League\OAuth1\Client\Tests\ServerStub[createHttpClient,protocolHeader]', - [$this->getMockClientCredentials()] - ); - - $temporaryCredentials = m::mock('League\OAuth1\Client\Credentials\TokenCredentials'); - $temporaryCredentials->shouldReceive('getIdentifier')->andReturn('tokencredentialsidentifier'); - $temporaryCredentials->shouldReceive('getSecret')->andReturn('tokencredentialssecret'); - - $server->shouldReceive('createHttpClient')->andReturn($client = m::mock('stdClass')); - - $me = $this; - $client->shouldReceive('get')->with('http://www.example.com/user', m::on(function ($options) use ($me) { - $headers = $options['headers']; - - $me->assertTrue(isset($headers['Authorization'])); - - // OAuth protocol specifies a strict number of - // headers should be sent, in the correct order. - // We'll validate that here. - $pattern - = '/OAuth oauth_consumer_key=".*?", oauth_nonce="[a-zA-Z0-9]+", oauth_signature_method="HMAC-SHA1", oauth_timestamp="\d{10}", oauth_version="1.0", oauth_token="tokencredentialsidentifier", oauth_signature=".*?"/'; - - $matches = preg_match($pattern, $headers['Authorization']); - $me->assertEquals(1, $matches, 'Asserting that the authorization header contains the correct expression.'); - - return true; - }))->once()->andReturn($response = m::mock(ResponseInterface::class)); - $response->shouldReceive('getBody')->once()->andReturn(json_encode([ - 'foo' => 'bar', - 'id' => 123, - 'contact_email' => 'baz@qux.com', - 'username' => 'fred', - ])); - - $user = $server->getUserDetails($temporaryCredentials); - $this->assertInstanceOf('League\OAuth1\Client\Server\User', $user); - $this->assertEquals('bar', $user->firstName); - $this->assertEquals(123, $server->getUserUid($temporaryCredentials)); - $this->assertEquals('baz@qux.com', $server->getUserEmail($temporaryCredentials)); - $this->assertEquals('fred', $server->getUserScreenName($temporaryCredentials)); - } - - public function testGettingHeaders() - { - $server = new ServerStub($this->getMockClientCredentials()); - - $tokenCredentials = m::mock('League\OAuth1\Client\Credentials\TokenCredentials'); - $tokenCredentials->shouldReceive('getIdentifier')->andReturn('mock_identifier'); - $tokenCredentials->shouldReceive('getSecret')->andReturn('mock_secret'); - - // OAuth protocol specifies a strict number of - // headers should be sent, in the correct order. - // We'll validate that here. - $pattern - = '/OAuth oauth_consumer_key=".*?", oauth_nonce="[a-zA-Z0-9]+", oauth_signature_method="HMAC-SHA1", oauth_timestamp="\d{10}", oauth_version="1.0", oauth_token="mock_identifier", oauth_signature=".*?"/'; - - // With a GET request - $headers = $server->getHeaders($tokenCredentials, 'GET', 'http://example.com/'); - $this->assertTrue(isset($headers['Authorization'])); - - $matches = preg_match($pattern, $headers['Authorization']); - $this->assertEquals(1, $matches, 'Asserting that the authorization header contains the correct expression.'); - - // With a POST request - $headers = $server->getHeaders($tokenCredentials, 'POST', 'http://example.com/', ['body' => 'params']); - $this->assertTrue(isset($headers['Authorization'])); - - $matches = preg_match($pattern, $headers['Authorization']); - $this->assertEquals(1, $matches, 'Asserting that the authorization header contains the correct expression.'); - } - - protected function getMockClientCredentials() - { - return [ - 'identifier' => 'myidentifier', - 'secret' => 'mysecret', - 'callback_uri' => 'http://app.dev/', - ]; - } -} diff --git a/vendor/league/oauth1-client/tests/TrelloServerTest.php b/vendor/league/oauth1-client/tests/TrelloServerTest.php deleted file mode 100644 index eaf6c44b1..000000000 --- a/vendor/league/oauth1-client/tests/TrelloServerTest.php +++ /dev/null @@ -1,349 +0,0 @@ -getMockClientCredentials()); - - $credentials = $server->getClientCredentials(); - $this->assertInstanceOf('League\OAuth1\Client\Credentials\ClientCredentialsInterface', $credentials); - $this->assertEquals($this->getApplicationKey(), $credentials->getIdentifier()); - $this->assertEquals('mysecret', $credentials->getSecret()); - $this->assertEquals('http://app.dev/', $credentials->getCallbackUri()); - } - - public function testCreatingWithObject() - { - $credentials = new ClientCredentials; - $credentials->setIdentifier('myidentifier'); - $credentials->setSecret('mysecret'); - $credentials->setCallbackUri('http://app.dev/'); - - $server = new Trello($credentials); - - $this->assertEquals($credentials, $server->getClientCredentials()); - } - - public function testGettingTemporaryCredentials() - { - $server = m::mock('League\OAuth1\Client\Server\Trello[createHttpClient]', [$this->getMockClientCredentials()]); - - $server->shouldReceive('createHttpClient')->andReturn($client = m::mock('stdClass')); - - $me = $this; - $client->shouldReceive('post')->with('https://trello.com/1/OAuthGetRequestToken', m::on(function ($options) use ($me) { - $headers = $options['headers']; - - $me->assertTrue(isset($headers['Authorization'])); - - // OAuth protocol specifies a strict number of - // headers should be sent, in the correct order. - // We'll validate that here. - $pattern = '/OAuth oauth_consumer_key=".*?", oauth_nonce="[a-zA-Z0-9]+", oauth_signature_method="HMAC-SHA1", oauth_timestamp="\d{10}", oauth_version="1.0", oauth_callback="' . preg_quote('http%3A%2F%2Fapp.dev%2F', '/') . '", oauth_signature=".*?"/'; - - $matches = preg_match($pattern, $headers['Authorization']); - $me->assertEquals(1, $matches, 'Asserting that the authorization header contains the correct expression.'); - - return true; - }))->once()->andReturn($response = m::mock(ResponseInterface::class)); - $response->shouldReceive('getBody')->andReturn('oauth_token=temporarycredentialsidentifier&oauth_token_secret=temporarycredentialssecret&oauth_callback_confirmed=true'); - - $credentials = $server->getTemporaryCredentials(); - $this->assertInstanceOf('League\OAuth1\Client\Credentials\TemporaryCredentials', $credentials); - $this->assertEquals('temporarycredentialsidentifier', $credentials->getIdentifier()); - $this->assertEquals('temporarycredentialssecret', $credentials->getSecret()); - } - - public function testGettingDefaultAuthorizationUrl() - { - $server = new Trello($this->getMockClientCredentials()); - - $expected = 'https://trello.com/1/OAuthAuthorizeToken?response_type=fragment&scope=read&expiration=1day&oauth_token=foo'; - - $this->assertEquals($expected, $server->getAuthorizationUrl('foo')); - - $credentials = m::mock('League\OAuth1\Client\Credentials\TemporaryCredentials'); - $credentials->shouldReceive('getIdentifier')->andReturn('foo'); - $this->assertEquals($expected, $server->getAuthorizationUrl($credentials)); - } - - public function testGettingAuthorizationUrlWithExpirationAfterConstructingWithExpiration() - { - $credentials = $this->getMockClientCredentials(); - $expiration = $this->getApplicationExpiration(2); - $credentials['expiration'] = $expiration; - $server = new Trello($credentials); - - $expected = 'https://trello.com/1/OAuthAuthorizeToken?response_type=fragment&scope=read&expiration=' . urlencode($expiration) . '&oauth_token=foo'; - - $this->assertEquals($expected, $server->getAuthorizationUrl('foo')); - - $credentials = m::mock('League\OAuth1\Client\Credentials\TemporaryCredentials'); - $credentials->shouldReceive('getIdentifier')->andReturn('foo'); - $this->assertEquals($expected, $server->getAuthorizationUrl($credentials)); - } - - public function testGettingAuthorizationUrlWithExpirationAfterSettingExpiration() - { - $expiration = $this->getApplicationExpiration(2); - $server = new Trello($this->getMockClientCredentials()); - $server->setApplicationExpiration($expiration); - - $expected = 'https://trello.com/1/OAuthAuthorizeToken?response_type=fragment&scope=read&expiration=' . urlencode($expiration) . '&oauth_token=foo'; - - $this->assertEquals($expected, $server->getAuthorizationUrl('foo')); - - $credentials = m::mock('League\OAuth1\Client\Credentials\TemporaryCredentials'); - $credentials->shouldReceive('getIdentifier')->andReturn('foo'); - $this->assertEquals($expected, $server->getAuthorizationUrl($credentials)); - } - - public function testGettingAuthorizationUrlWithNameAfterConstructingWithName() - { - $credentials = $this->getMockClientCredentials(); - $name = $this->getApplicationName(); - $credentials['name'] = $name; - $server = new Trello($credentials); - - $expected = 'https://trello.com/1/OAuthAuthorizeToken?response_type=fragment&scope=read&expiration=1day&name=' . urlencode($name) . '&oauth_token=foo'; - - $this->assertEquals($expected, $server->getAuthorizationUrl('foo')); - - $credentials = m::mock('League\OAuth1\Client\Credentials\TemporaryCredentials'); - $credentials->shouldReceive('getIdentifier')->andReturn('foo'); - $this->assertEquals($expected, $server->getAuthorizationUrl($credentials)); - } - - public function testGettingAuthorizationUrlWithNameAfterSettingName() - { - $name = $this->getApplicationName(); - $server = new Trello($this->getMockClientCredentials()); - $server->setApplicationName($name); - - $expected = 'https://trello.com/1/OAuthAuthorizeToken?response_type=fragment&scope=read&expiration=1day&name=' . urlencode($name) . '&oauth_token=foo'; - - $this->assertEquals($expected, $server->getAuthorizationUrl('foo')); - - $credentials = m::mock('League\OAuth1\Client\Credentials\TemporaryCredentials'); - $credentials->shouldReceive('getIdentifier')->andReturn('foo'); - $this->assertEquals($expected, $server->getAuthorizationUrl($credentials)); - } - - public function testGettingAuthorizationUrlWithScopeAfterConstructingWithScope() - { - $credentials = $this->getMockClientCredentials(); - $scope = $this->getApplicationScope(false); - $credentials['scope'] = $scope; - $server = new Trello($credentials); - - $expected = 'https://trello.com/1/OAuthAuthorizeToken?response_type=fragment&scope=' . urlencode($scope) . '&expiration=1day&oauth_token=foo'; - - $this->assertEquals($expected, $server->getAuthorizationUrl('foo')); - - $credentials = m::mock('League\OAuth1\Client\Credentials\TemporaryCredentials'); - $credentials->shouldReceive('getIdentifier')->andReturn('foo'); - $this->assertEquals($expected, $server->getAuthorizationUrl($credentials)); - } - - public function testGettingAuthorizationUrlWithScopeAfterSettingScope() - { - $scope = $this->getApplicationScope(false); - $server = new Trello($this->getMockClientCredentials()); - $server->setApplicationScope($scope); - - $expected = 'https://trello.com/1/OAuthAuthorizeToken?response_type=fragment&scope=' . urlencode($scope) . '&expiration=1day&oauth_token=foo'; - - $this->assertEquals($expected, $server->getAuthorizationUrl('foo')); - - $credentials = m::mock('League\OAuth1\Client\Credentials\TemporaryCredentials'); - $credentials->shouldReceive('getIdentifier')->andReturn('foo'); - $this->assertEquals($expected, $server->getAuthorizationUrl($credentials)); - } - - public function testGettingTokenCredentialsFailsWithManInTheMiddle() - { - $server = new Trello($this->getMockClientCredentials()); - - $credentials = m::mock('League\OAuth1\Client\Credentials\TemporaryCredentials'); - $credentials->shouldReceive('getIdentifier')->andReturn('foo'); - - $this->expectException(InvalidArgumentException::class); - - $server->getTokenCredentials($credentials, 'bar', 'verifier'); - } - - public function testGettingTokenCredentials() - { - $server = m::mock('League\OAuth1\Client\Server\Trello[createHttpClient]', [$this->getMockClientCredentials()]); - - $temporaryCredentials = m::mock('League\OAuth1\Client\Credentials\TemporaryCredentials'); - $temporaryCredentials->shouldReceive('getIdentifier')->andReturn('temporarycredentialsidentifier'); - $temporaryCredentials->shouldReceive('getSecret')->andReturn('temporarycredentialssecret'); - - $server->shouldReceive('createHttpClient')->andReturn($client = m::mock('stdClass')); - - $me = $this; - $client->shouldReceive('post')->with('https://trello.com/1/OAuthGetAccessToken', m::on(function ($options) use ($me) { - $headers = $options['headers']; - $body = $options['form_params']; - - $me->assertTrue(isset($headers['Authorization'])); - - // OAuth protocol specifies a strict number of - // headers should be sent, in the correct order. - // We'll validate that here. - $pattern = '/OAuth oauth_consumer_key=".*?", oauth_nonce="[a-zA-Z0-9]+", oauth_signature_method="HMAC-SHA1", oauth_timestamp="\d{10}", oauth_version="1.0", oauth_token="temporarycredentialsidentifier", oauth_signature=".*?"/'; - - $matches = preg_match($pattern, $headers['Authorization']); - $me->assertEquals(1, $matches, 'Asserting that the authorization header contains the correct expression.'); - - $me->assertSame($body, ['oauth_verifier' => 'myverifiercode']); - - return true; - }))->once()->andReturn($response = m::mock(ResponseInterface::class)); - $response->shouldReceive('getBody')->andReturn('oauth_token=tokencredentialsidentifier&oauth_token_secret=tokencredentialssecret'); - - $credentials = $server->getTokenCredentials($temporaryCredentials, 'temporarycredentialsidentifier', 'myverifiercode'); - $this->assertInstanceOf('League\OAuth1\Client\Credentials\TokenCredentials', $credentials); - $this->assertEquals('tokencredentialsidentifier', $credentials->getIdentifier()); - $this->assertEquals('tokencredentialssecret', $credentials->getSecret()); - } - - public function testGettingUserDetails() - { - $server = m::mock('League\OAuth1\Client\Server\Trello[createHttpClient,protocolHeader]', [$this->getMockClientCredentials()]); - - $temporaryCredentials = m::mock('League\OAuth1\Client\Credentials\TokenCredentials'); - $temporaryCredentials->shouldReceive('getIdentifier')->andReturn('tokencredentialsidentifier'); - $temporaryCredentials->shouldReceive('getSecret')->andReturn('tokencredentialssecret'); - - $server->shouldReceive('createHttpClient')->andReturn($client = m::mock('stdClass')); - - $me = $this; - $client->shouldReceive('get')->with('https://trello.com/1/members/me?key=' . $this->getApplicationKey() . '&token=' . $this->getAccessToken(), m::on(function ($options) use ($me) { - $headers = $options['headers']; - - $me->assertTrue(isset($headers['Authorization'])); - - // OAuth protocol specifies a strict number of - // headers should be sent, in the correct order. - // We'll validate that here. - $pattern = '/OAuth oauth_consumer_key=".*?", oauth_nonce="[a-zA-Z0-9]+", oauth_signature_method="HMAC-SHA1", oauth_timestamp="\d{10}", oauth_version="1.0", oauth_token="tokencredentialsidentifier", oauth_signature=".*?"/'; - - $matches = preg_match($pattern, $headers['Authorization']); - $me->assertEquals(1, $matches, 'Asserting that the authorization header contains the correct expression.'); - - return true; - }))->once()->andReturn($response = m::mock(ResponseInterface::class)); - $response->shouldReceive('getBody')->once()->andReturn($this->getUserPayload()); - - $user = $server - ->setAccessToken($this->getAccessToken()) - ->getUserDetails($temporaryCredentials); - $this->assertInstanceOf('League\OAuth1\Client\Server\User', $user); - $this->assertEquals('Matilda Wormwood', $user->name); - $this->assertEquals('545df696e29c0dddaed31967', $server->getUserUid($temporaryCredentials)); - $this->assertEquals(null, $server->getUserEmail($temporaryCredentials)); - $this->assertEquals('matildawormwood12', $server->getUserScreenName($temporaryCredentials)); - } - - protected function getMockClientCredentials() - { - return [ - 'identifier' => $this->getApplicationKey(), - 'secret' => 'mysecret', - 'callback_uri' => 'http://app.dev/', - ]; - } - - protected function getAccessToken() - { - return 'lmnopqrstuvwxyz'; - } - - protected function getApplicationKey() - { - return 'abcdefghijk'; - } - - protected function getApplicationExpiration($days = 0) - { - return is_numeric($days) && $days > 0 ? $days . 'day' . ($days == 1 ? '' : 's') : 'never'; - } - - protected function getApplicationName() - { - return 'fizz buzz'; - } - - protected function getApplicationScope($readonly = true) - { - return $readonly ? 'read' : 'read,write'; - } - - private function getUserPayload() - { - return '{ - "id": "545df696e29c0dddaed31967", - "avatarHash": null, - "bio": "I have magical powers", - "bioData": null, - "confirmed": true, - "fullName": "Matilda Wormwood", - "idPremOrgsAdmin": [], - "initials": "MW", - "memberType": "normal", - "products": [], - "status": "idle", - "url": "https://trello.com/matildawormwood12", - "username": "matildawormwood12", - "avatarSource": "none", - "email": null, - "gravatarHash": "39aaaada0224f26f0bb8f1965326dcb7", - "idBoards": [ - "545df696e29c0dddaed31968", - "545e01d6c7b2dd962b5b46cb" - ], - "idOrganizations": [ - "54adfd79f9aea14f84009a85", - "54adfde13b0e706947bc4789" - ], - "loginTypes": null, - "oneTimeMessagesDismissed": [], - "prefs": { - "sendSummaries": true, - "minutesBetweenSummaries": 1, - "minutesBeforeDeadlineToNotify": 1440, - "colorBlind": false, - "timezoneInfo": { - "timezoneNext": "CDT", - "dateNext": "2015-03-08T08:00:00.000Z", - "offsetNext": 300, - "timezoneCurrent": "CST", - "offsetCurrent": 360 - } - }, - "trophies": [], - "uploadedAvatarHash": null, - "premiumFeatures": [], - "idBoardsPinned": null - }'; - } -} diff --git a/vendor/league/oauth1-client/tests/XingServerTest.php b/vendor/league/oauth1-client/tests/XingServerTest.php deleted file mode 100644 index 1f576e32e..000000000 --- a/vendor/league/oauth1-client/tests/XingServerTest.php +++ /dev/null @@ -1,255 +0,0 @@ -getMockClientCredentials()); - - $credentials = $server->getClientCredentials(); - $this->assertInstanceOf('League\OAuth1\Client\Credentials\ClientCredentialsInterface', $credentials); - $this->assertEquals($this->getApplicationKey(), $credentials->getIdentifier()); - $this->assertEquals('mysecret', $credentials->getSecret()); - $this->assertEquals('http://app.dev/', $credentials->getCallbackUri()); - } - - public function testCreatingWithObject() - { - $credentials = new ClientCredentials; - $credentials->setIdentifier('myidentifier'); - $credentials->setSecret('mysecret'); - $credentials->setCallbackUri('http://app.dev/'); - - $server = new Xing($credentials); - - $this->assertEquals($credentials, $server->getClientCredentials()); - } - - public function testGettingTemporaryCredentials() - { - $server = m::mock('League\OAuth1\Client\Server\Xing[createHttpClient]', [$this->getMockClientCredentials()]); - - $server->shouldReceive('createHttpClient')->andReturn($client = m::mock('stdClass')); - - $me = $this; - $client->shouldReceive('post')->with('https://api.xing.com/v1/request_token', m::on(function ($options) use ($me) { - $headers = $options['headers']; - $me->assertTrue(isset($headers['Authorization'])); - - // OAuth protocol specifies a strict number of - // headers should be sent, in the correct order. - // We'll validate that here. - $pattern = '/OAuth oauth_consumer_key=".*?", oauth_nonce="[a-zA-Z0-9]+", oauth_signature_method="HMAC-SHA1", oauth_timestamp="\d{10}", oauth_version="1.0", oauth_callback="' . preg_quote('http%3A%2F%2Fapp.dev%2F', '/') . '", oauth_signature=".*?"/'; - - $matches = preg_match($pattern, $headers['Authorization']); - $me->assertEquals(1, $matches, 'Asserting that the authorization header contains the correct expression.'); - - return true; - }))->once()->andReturn($response = m::mock(ResponseInterface::class)); - $response->shouldReceive('getBody')->andReturn('oauth_token=temporarycredentialsidentifier&oauth_token_secret=temporarycredentialssecret&oauth_callback_confirmed=true'); - - $credentials = $server->getTemporaryCredentials(); - $this->assertInstanceOf('League\OAuth1\Client\Credentials\TemporaryCredentials', $credentials); - $this->assertEquals('temporarycredentialsidentifier', $credentials->getIdentifier()); - $this->assertEquals('temporarycredentialssecret', $credentials->getSecret()); - } - - public function testGettingDefaultAuthorizationUrl() - { - $server = new Xing($this->getMockClientCredentials()); - - $expected = 'https://api.xing.com/v1/authorize?oauth_token=foo'; - - $this->assertEquals($expected, $server->getAuthorizationUrl('foo')); - - $credentials = m::mock('League\OAuth1\Client\Credentials\TemporaryCredentials'); - $credentials->shouldReceive('getIdentifier')->andReturn('foo'); - $this->assertEquals($expected, $server->getAuthorizationUrl($credentials)); - } - - public function testGettingTokenCredentialsFailsWithManInTheMiddle() - { - $server = new Xing($this->getMockClientCredentials()); - - $credentials = m::mock('League\OAuth1\Client\Credentials\TemporaryCredentials'); - $credentials->shouldReceive('getIdentifier')->andReturn('foo'); - - $this->expectException(InvalidArgumentException::class); - - $server->getTokenCredentials($credentials, 'bar', 'verifier'); - } - - public function testGettingTokenCredentials() - { - $server = m::mock('League\OAuth1\Client\Server\Xing[createHttpClient]', [$this->getMockClientCredentials()]); - - $temporaryCredentials = m::mock('League\OAuth1\Client\Credentials\TemporaryCredentials'); - $temporaryCredentials->shouldReceive('getIdentifier')->andReturn('temporarycredentialsidentifier'); - $temporaryCredentials->shouldReceive('getSecret')->andReturn('temporarycredentialssecret'); - - $server->shouldReceive('createHttpClient')->andReturn($client = m::mock('stdClass')); - - $me = $this; - $client->shouldReceive('post')->with('https://api.xing.com/v1/access_token', m::on(function ($options) use ($me) { - $headers = $options['headers']; - $body = $options['form_params']; - - $me->assertTrue(isset($headers['Authorization'])); - - // OAuth protocol specifies a strict number of - // headers should be sent, in the correct order. - // We'll validate that here. - $pattern = '/OAuth oauth_consumer_key=".*?", oauth_nonce="[a-zA-Z0-9]+", oauth_signature_method="HMAC-SHA1", oauth_timestamp="\d{10}", oauth_version="1.0", oauth_token="temporarycredentialsidentifier", oauth_signature=".*?"/'; - - $matches = preg_match($pattern, $headers['Authorization']); - $me->assertEquals(1, $matches, 'Asserting that the authorization header contains the correct expression.'); - - $me->assertSame($body, ['oauth_verifier' => 'myverifiercode']); - - return true; - }))->once()->andReturn($response = m::mock(ResponseInterface::class)); - $response->shouldReceive('getBody')->andReturn('oauth_token=tokencredentialsidentifier&oauth_token_secret=tokencredentialssecret'); - - $credentials = $server->getTokenCredentials($temporaryCredentials, 'temporarycredentialsidentifier', 'myverifiercode'); - $this->assertInstanceOf('League\OAuth1\Client\Credentials\TokenCredentials', $credentials); - $this->assertEquals('tokencredentialsidentifier', $credentials->getIdentifier()); - $this->assertEquals('tokencredentialssecret', $credentials->getSecret()); - } - - public function testGettingUserDetails() - { - $server = m::mock('League\OAuth1\Client\Server\Xing[createHttpClient,protocolHeader]', [$this->getMockClientCredentials()]); - - $temporaryCredentials = m::mock('League\OAuth1\Client\Credentials\TokenCredentials'); - $temporaryCredentials->shouldReceive('getIdentifier')->andReturn('tokencredentialsidentifier'); - $temporaryCredentials->shouldReceive('getSecret')->andReturn('tokencredentialssecret'); - - $server->shouldReceive('createHttpClient')->andReturn($client = m::mock('stdClass')); - - $me = $this; - $client->shouldReceive('get')->with('https://api.xing.com/v1/users/me', m::on(function ($options) use ($me) { - $headers = $options['headers']; - - $me->assertTrue(isset($headers['Authorization'])); - - // OAuth protocol specifies a strict number of - // headers should be sent, in the correct order. - // We'll validate that here. - $pattern = '/OAuth oauth_consumer_key=".*?", oauth_nonce="[a-zA-Z0-9]+", oauth_signature_method="HMAC-SHA1", oauth_timestamp="\d{10}", oauth_version="1.0", oauth_token="tokencredentialsidentifier", oauth_signature=".*?"/'; - - $matches = preg_match($pattern, $headers['Authorization']); - $me->assertEquals(1, $matches, 'Asserting that the authorization header contains the correct expression.'); - - return true; - }))->once()->andReturn($response = m::mock(ResponseInterface::class)); - $response->shouldReceive('getBody')->once()->andReturn($this->getUserPayload()); - - $user = $server->getUserDetails($temporaryCredentials); - $this->assertInstanceOf('League\OAuth1\Client\Server\User', $user); - $this->assertEquals('Roman Gelembjuk', $user->name); - $this->assertEquals('17144430_0f9409', $server->getUserUid($temporaryCredentials)); - $this->assertEquals('XXXXXXXXXX@gmail.com', $server->getUserEmail($temporaryCredentials)); - $this->assertEquals('Roman Gelembjuk', $server->getUserScreenName($temporaryCredentials)); - } - - protected function getMockClientCredentials() - { - return [ - 'identifier' => $this->getApplicationKey(), - 'secret' => 'mysecret', - 'callback_uri' => 'http://app.dev/', - ]; - } - - protected function getApplicationKey() - { - return 'abcdefghijk'; - } - - protected function getApplicationExpiration($days = 0) - { - return is_numeric($days) && $days > 0 ? $days . 'day' . ($days == 1 ? '' : 's') : 'never'; - } - - protected function getApplicationName() - { - return 'fizz buzz'; - } - - private function getUserPayload() - { - return '{ - "users":[ - { - "id":"17144430_0f9409", - "active_email":"XXXXXXXXXX@gmail.com", - "time_zone": - { - "utc_offset":3.0, - "name":"Europe/Kiev" - }, - "display_name":"Roman Gelembjuk", - "first_name":"Roman", - "last_name":"Gelembjuk", - "gender":"m", - "page_name":"Roman_Gelembjuk", - "birth_date": - {"year":null,"month":null,"day":null}, - "wants":null, - "haves":null, - "interests":null, - "web_profiles":{}, - "badges":[], - "photo_urls": - { - "large":"https://x1.xingassets.com/assets/frontend_minified/img/users/nobody_m.140x185.jpg", - "maxi_thumb":"https://x1.xingassets.com/assets/frontend_minified/img/users/nobody_m.70x93.jpg", - "medium_thumb":"https://x1.xingassets.com/assets/frontend_minified/img/users/nobody_m.57x75.jpg" - }, - "permalink":"https://www.xing.com/profile/Roman_Gelembjuk", - "languages":{"en":null}, - "employment_status":"EMPLOYEE", - "organisation_member":null, - "instant_messaging_accounts":{}, - "educational_background": - {"degree":null,"primary_school":null,"schools":[],"qualifications":[]}, - "private_address":{ - "street":null, - "zip_code":null, - "city":null, - "province":null, - "country":null, - "email":"XXXXXXXX@gmail.com", - "fax":null, - "phone":null, - "mobile_phone":null} - ,"business_address": - { - "street":null, - "zip_code":null, - "city":"Ivano-Frankivsk", - "province":null, - "country":"UA", - "email":null, - "fax":null,"phone":null,"mobile_phone":null - }, - "premium_services":[] - }]}'; - } -} diff --git a/vendor/league/oauth1-client/tests/stubs/ServerStub.php b/vendor/league/oauth1-client/tests/stubs/ServerStub.php deleted file mode 100644 index 7df5c31d1..000000000 --- a/vendor/league/oauth1-client/tests/stubs/ServerStub.php +++ /dev/null @@ -1,77 +0,0 @@ -firstName = $data['foo']; - - return $user; - } - - /** - * @inheritDoc - */ - public function userUid($data, TokenCredentials $tokenCredentials) - { - return isset($data['id']) ? $data['id'] : null; - } - - /** - * @inheritDoc - */ - public function userEmail($data, TokenCredentials $tokenCredentials) - { - return isset($data['contact_email']) ? $data['contact_email'] : null; - } - - /** - * @inheritDoc - */ - public function userScreenName($data, TokenCredentials $tokenCredentials) - { - return isset($data['username']) ? $data['username'] : null; - } -} diff --git a/vendor/league/oauth1-client/tests/test_rsa_invalidkey.pem b/vendor/league/oauth1-client/tests/test_rsa_invalidkey.pem deleted file mode 100644 index 40a712d89..000000000 --- a/vendor/league/oauth1-client/tests/test_rsa_invalidkey.pem +++ /dev/null @@ -1 +0,0 @@ -not a valid RSA key \ No newline at end of file diff --git a/vendor/league/oauth1-client/tests/test_rsa_privatekey.pem b/vendor/league/oauth1-client/tests/test_rsa_privatekey.pem deleted file mode 100644 index 25804aa04..000000000 --- a/vendor/league/oauth1-client/tests/test_rsa_privatekey.pem +++ /dev/null @@ -1,15 +0,0 @@ ------BEGIN RSA PRIVATE KEY----- -MIICXAIBAAKBgQDJScPCpHHPakw9v4nhxi+cBumCml3WpMNDaE3Cxnkf6HALzoi8 -fQPx3XRfKSoLG6b7uTG+vDoLCL49ZCyYwrnggsFF08bJMqIhUHlZrkiyT5UhdTIh -XEEFfb6XmieHNtra+ur8E3PVal4PEdOCEmJehBMJkiCsxNOJ/kCeYSMdbQIDAQAB -AoGAMo7JkcEWKP/NCJFsg33xBWKjEj/NpBUcSnkPVwXc9IvAYObOZ3GLJRv3l9NS -ERov9fgNK5hBh/X5OphHr1LxtqU5gAFYx5Qgt/WG3ZH9KScXkaPS3Oq2qK9krbA2 -BXYKP4NEqhjJTecy7M8bju5+lsjteyqVSsVLHdLhUfPRbE0CQQDyYP6iChqZm1AK -A8x8PKvJsd4zSdxWXUYSmD7mAtek5VeWblbcXYYdeYPN6hNmqzaLelmrZI51x1Uf -hf1ryIfrAkEA1JmdSsNuxi9MOY3HqErWYsqZ//mVOxVyCAwf7OWQ0rTHEQBhQwpS -9nk0YFHI9t6nVUwXrZ7/7UJPTu8OjPKyBwJAYw2OomwcqM/XKvCYfeFRl1DwbOdv -e4AM5gaAFgHtXP85B0o6hz5VU/BYFCvoF9o6pU+wG6IxsiJvQD3C7mx6VwJAbXYW -PVs4WsQZe/ya0vSNQ1pLRjdr9XrKNoh/m4prMYGwiPloGotjQdIP/JO/ZBQplcpS -2qrl3HPqv5poJHwE2wJBAM37BVINHR0zcSHfFLmSYrqmLx2oC3UAB3exmpYSUgOz -wJqPfmPWuuXuu6h0Z2DazUan+2EiecX6C4ywkm+qk1I= ------END RSA PRIVATE KEY----- diff --git a/vendor/league/oauth1-client/tests/test_rsa_publickey.pem b/vendor/league/oauth1-client/tests/test_rsa_publickey.pem deleted file mode 100644 index 574902b92..000000000 --- a/vendor/league/oauth1-client/tests/test_rsa_publickey.pem +++ /dev/null @@ -1,19 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIDEDCCAnmgAwIBAgIJAMhMVuHMz+EgMA0GCSqGSIb3DQEBBQUAMGQxCzAJBgNV -BAYTAlVTMQswCQYDVQQIEwJUWDEPMA0GA1UEBxMGQXVzdGluMSEwHwYDVQQKExhJ -bnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQxFDASBgNVBAMTC2V4YW1wbGUuY29tMB4X -DTE2MTEwMjIxMDUzNVoXDTIxMTEwMTIxMDUzNVowZDELMAkGA1UEBhMCVVMxCzAJ -BgNVBAgTAlRYMQ8wDQYDVQQHEwZBdXN0aW4xITAfBgNVBAoTGEludGVybmV0IFdp -ZGdpdHMgUHR5IEx0ZDEUMBIGA1UEAxMLZXhhbXBsZS5jb20wgZ8wDQYJKoZIhvcN -AQEBBQADgY0AMIGJAoGBAMlJw8Kkcc9qTD2/ieHGL5wG6YKaXdakw0NoTcLGeR/o -cAvOiLx9A/HddF8pKgsbpvu5Mb68OgsIvj1kLJjCueCCwUXTxskyoiFQeVmuSLJP -lSF1MiFcQQV9vpeaJ4c22tr66vwTc9VqXg8R04ISYl6EEwmSIKzE04n+QJ5hIx1t -AgMBAAGjgckwgcYwHQYDVR0OBBYEFLYKQbsK2oqRO83NbNXC2R6MkNcRMIGWBgNV -HSMEgY4wgYuAFLYKQbsK2oqRO83NbNXC2R6MkNcRoWikZjBkMQswCQYDVQQGEwJV -UzELMAkGA1UECBMCVFgxDzANBgNVBAcTBkF1c3RpbjEhMB8GA1UEChMYSW50ZXJu -ZXQgV2lkZ2l0cyBQdHkgTHRkMRQwEgYDVQQDEwtleGFtcGxlLmNvbYIJAMhMVuHM -z+EgMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADgYEASwEwGQnRCqcNrb6k -g6/xpeyHE9/ruTBIE4dtArQI0NosaERC3i4nRKbgfJfIuYEaYiga4dC51CQqKrbH -YZ0dgYMzzp21OMQyKdz3E7csMJv5xxe5D2svdPzbBGU5+N80FYLx17f3UqsYFaAC -X0/YTQsdlM5tHZOd1ZbQUrERqLs= ------END CERTIFICATE----- diff --git a/vendor/nikic/fast-route/.gitignore b/vendor/nikic/fast-route/.gitignore new file mode 100644 index 000000000..e378a07da --- /dev/null +++ b/vendor/nikic/fast-route/.gitignore @@ -0,0 +1,5 @@ +/vendor/ +.idea/ + +# ignore lock file since we have no extra dependencies +composer.lock diff --git a/vendor/nikic/fast-route/.hhconfig b/vendor/nikic/fast-route/.hhconfig new file mode 100644 index 000000000..0c2153ceb --- /dev/null +++ b/vendor/nikic/fast-route/.hhconfig @@ -0,0 +1 @@ +assume_php=false diff --git a/vendor/nikic/fast-route/.travis.yml b/vendor/nikic/fast-route/.travis.yml new file mode 100644 index 000000000..10f83819e --- /dev/null +++ b/vendor/nikic/fast-route/.travis.yml @@ -0,0 +1,20 @@ +sudo: false +language: php + +php: + - 5.4 + - 5.5 + - 5.6 + - 7.0 + - 7.1 + - 7.2 + - hhvm + +script: + - ./vendor/bin/phpunit + +before_install: + - travis_retry composer self-update + +install: + - composer install diff --git a/vendor/nikic/fast-route/composer.json b/vendor/nikic/fast-route/composer.json new file mode 100644 index 000000000..fb446a2ab --- /dev/null +++ b/vendor/nikic/fast-route/composer.json @@ -0,0 +1,24 @@ +{ + "name": "nikic/fast-route", + "description": "Fast request router for PHP", + "keywords": ["routing", "router"], + "license": "BSD-3-Clause", + "authors": [ + { + "name": "Nikita Popov", + "email": "nikic@php.net" + } + ], + "autoload": { + "psr-4": { + "FastRoute\\": "src/" + }, + "files": ["src/functions.php"] + }, + "require": { + "php": ">=5.4.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.8.35|~5.7" + } +} diff --git a/vendor/phpmailer/phpmailer/composer.json b/vendor/phpmailer/phpmailer/composer.json new file mode 100644 index 000000000..7388bd98b --- /dev/null +++ b/vendor/phpmailer/phpmailer/composer.json @@ -0,0 +1,61 @@ +{ + "name": "phpmailer/phpmailer", + "type": "library", + "description": "PHPMailer is a full-featured email creation and transfer class for PHP", + "authors": [ + { + "name": "Marcus Bointon", + "email": "phpmailer@synchromedia.co.uk" + }, + { + "name": "Jim Jagielski", + "email": "jimjag@gmail.com" + }, + { + "name": "Andy Prevost", + "email": "codeworxtech@users.sourceforge.net" + }, + { + "name": "Brent R. Matzelle" + } + ], + "funding": [ + { + "url": "https://github.com/Synchro", + "type": "github" + } + ], + "require": { + "php": ">=5.5.0", + "ext-ctype": "*", + "ext-filter": "*", + "ext-hash": "*" + }, + "require-dev": { + "dealerdirect/phpcodesniffer-composer-installer": "^0.7.0", + "doctrine/annotations": "^1.2", + "phpcompatibility/php-compatibility": "^9.3.5", + "roave/security-advisories": "dev-latest", + "squizlabs/php_codesniffer": "^3.5.6", + "yoast/phpunit-polyfills": "^0.2.0" + }, + "suggest": { + "ext-mbstring": "Needed to send email in multibyte encoding charset", + "hayageek/oauth2-yahoo": "Needed for Yahoo XOAUTH2 authentication", + "league/oauth2-google": "Needed for Google XOAUTH2 authentication", + "psr/log": "For optional PSR-3 debug logging", + "stevenmaguire/oauth2-microsoft": "Needed for Microsoft XOAUTH2 authentication", + "symfony/polyfill-mbstring": "To support UTF-8 if the Mbstring PHP extension is not enabled (^1.2)" + }, + "autoload": { + "psr-4": { + "PHPMailer\\PHPMailer\\": "src/" + } + }, + "autoload-dev": { + "psr-4": { + "PHPMailer\\Test\\": "test/" + } + }, + "license": "LGPL-2.1-only" +} diff --git a/vendor/rakit/validation/.editorconfig b/vendor/rakit/validation/.editorconfig new file mode 100644 index 000000000..35f6e5e1e --- /dev/null +++ b/vendor/rakit/validation/.editorconfig @@ -0,0 +1,8 @@ +root = true + +[*.php] +indent_size = 4 +indent_style = space +end_of_line = lf +trim_trailing_whitespace = true +insert_final_newline = true diff --git a/vendor/rakit/validation/.gitattributes b/vendor/rakit/validation/.gitattributes new file mode 100644 index 000000000..d09a0a371 --- /dev/null +++ b/vendor/rakit/validation/.gitattributes @@ -0,0 +1,4 @@ +# Exclude unused files +/tests export-ignore +/phpunit.xml.dist export-ignore +/.travis.yml export-ignore diff --git a/vendor/rakit/validation/.gitignore b/vendor/rakit/validation/.gitignore new file mode 100644 index 000000000..d1502b087 --- /dev/null +++ b/vendor/rakit/validation/.gitignore @@ -0,0 +1,2 @@ +vendor/ +composer.lock diff --git a/vendor/rakit/validation/composer.json b/vendor/rakit/validation/composer.json new file mode 100644 index 000000000..c316baa69 --- /dev/null +++ b/vendor/rakit/validation/composer.json @@ -0,0 +1,23 @@ +{ + "name": "rakit/validation", + "description": "PHP Laravel like standalone validation library", + "license": "MIT", + "authors": [ + { + "email": "emsifa@gmail.com", + "name": "Muhammad Syifa" + } + ], + "autoload": { + "psr-4": { + "Rakit\\Validation\\": "src" + } + }, + "require": { + "php": ">=5.5.0", + "ext-mbstring": "*" + }, + "require-dev": { + "phpunit/phpunit": "4.*" + } +} \ No newline at end of file diff --git a/vendor/ralouphie/getallheaders/composer.json b/vendor/ralouphie/getallheaders/composer.json new file mode 100644 index 000000000..de8ce62e4 --- /dev/null +++ b/vendor/ralouphie/getallheaders/composer.json @@ -0,0 +1,26 @@ +{ + "name": "ralouphie/getallheaders", + "description": "A polyfill for getallheaders.", + "license": "MIT", + "authors": [ + { + "name": "Ralph Khattar", + "email": "ralph.khattar@gmail.com" + } + ], + "require": { + "php": ">=5.6" + }, + "require-dev": { + "phpunit/phpunit": "^5 || ^6.5", + "php-coveralls/php-coveralls": "^2.1" + }, + "autoload": { + "files": ["src/getallheaders.php"] + }, + "autoload-dev": { + "psr-4": { + "getallheaders\\Tests\\": "tests/" + } + } +} diff --git a/vendor/sabre/dav/.gitignore b/vendor/sabre/dav/.gitignore new file mode 100644 index 000000000..6cf245883 --- /dev/null +++ b/vendor/sabre/dav/.gitignore @@ -0,0 +1,43 @@ +# Unit tests +tests/temp +tests/.sabredav +tests/cov + +# Custom settings for tests +tests/config.user.php + +# ViM +*.swp + +# Composer +composer.lock +vendor + +# Composer binaries +bin/phing +bin/phpunit +bin/vobject +bin/generate_vcards +bin/phpdocmd +bin/phpunit +bin/php-cs-fixer +bin/sabre-cs-fixer + +# Assuming every .php file in the root is for testing +/*.php + +# Other testing stuff +/tmpdata +/data +/public + +# Build +build +build.properties + +# Docs +docs/api +docs/wikidocs + +# Mac +.DS_Store diff --git a/vendor/sabre/dav/.travis.yml b/vendor/sabre/dav/.travis.yml new file mode 100644 index 000000000..85637048a --- /dev/null +++ b/vendor/sabre/dav/.travis.yml @@ -0,0 +1,36 @@ +language: php +php: + - 5.5 + - 5.6 + - 7.0 + - 7.1 + + +env: + matrix: + - LOWEST_DEPS="" TEST_DEPS="" + - LOWEST_DEPS="--prefer-lowest" TEST_DEPS="tests/Sabre/" + +services: + - mysql + - postgresql + +sudo: false + +before_script: + - mysql -e 'create database sabredav_test' + - psql -c "create database sabredav_test" -U postgres + - psql -c "create user sabredav with PASSWORD 'sabredav';GRANT ALL PRIVILEGES ON DATABASE sabredav_test TO sabredav" -U postgres + # - composer self-update + - composer update --prefer-dist $LOWEST_DEPS + +# addons: +# postgresql: "9.5" + +script: + - ./bin/phpunit --configuration tests/phpunit.xml.dist $TEST_DEPS + - ./bin/sabre-cs-fixer fix . --dry-run --diff + +cache: + directories: + - $HOME/.composer/cache diff --git a/vendor/sabre/dav/bin/build.php b/vendor/sabre/dav/bin/build.php old mode 100644 new mode 100755 diff --git a/vendor/sabre/dav/bin/googlecode_upload.py b/vendor/sabre/dav/bin/googlecode_upload.py old mode 100644 new mode 100755 diff --git a/vendor/sabre/dav/bin/migrateto20.php b/vendor/sabre/dav/bin/migrateto20.php old mode 100644 new mode 100755 diff --git a/vendor/sabre/dav/bin/migrateto21.php b/vendor/sabre/dav/bin/migrateto21.php old mode 100644 new mode 100755 diff --git a/vendor/sabre/dav/bin/migrateto30.php b/vendor/sabre/dav/bin/migrateto30.php old mode 100644 new mode 100755 diff --git a/vendor/sabre/dav/bin/migrateto32.php b/vendor/sabre/dav/bin/migrateto32.php old mode 100644 new mode 100755 diff --git a/vendor/sabre/dav/bin/naturalselection b/vendor/sabre/dav/bin/naturalselection old mode 100644 new mode 100755 diff --git a/vendor/sabre/dav/bin/sabredav b/vendor/sabre/dav/bin/sabredav old mode 100644 new mode 100755 diff --git a/vendor/sabre/dav/bin/sabredav.php b/vendor/sabre/dav/bin/sabredav.php old mode 100644 new mode 100755 diff --git a/vendor/sabre/dav/composer.json b/vendor/sabre/dav/composer.json new file mode 100644 index 000000000..fca0e07fb --- /dev/null +++ b/vendor/sabre/dav/composer.json @@ -0,0 +1,68 @@ +{ + "name": "sabre/dav", + "type": "library", + "description": "WebDAV Framework for PHP", + "keywords": ["Framework", "WebDAV", "CalDAV", "CardDAV", "iCalendar"], + "homepage": "http://sabre.io/", + "license" : "BSD-3-Clause", + "authors": [ + { + "name": "Evert Pot", + "email": "me@evertpot.com", + "homepage" : "http://evertpot.com/", + "role" : "Developer" + } + ], + "require": { + "php": ">=5.5.0", + "sabre/vobject": "^4.1.0", + "sabre/event" : ">=2.0.0, <4.0.0", + "sabre/xml" : "^1.4.0", + "sabre/http" : "^4.2.1", + "sabre/uri" : "^1.0.1", + "ext-dom": "*", + "ext-pcre": "*", + "ext-spl": "*", + "ext-simplexml": "*", + "ext-mbstring" : "*", + "ext-ctype" : "*", + "ext-date" : "*", + "ext-iconv" : "*", + "lib-libxml" : ">=2.7.0", + "psr/log": "^1.0" + }, + "require-dev" : { + "phpunit/phpunit" : "> 4.8, <6.0.0", + "evert/phpdoc-md" : "~0.1.0", + "sabre/cs" : "^1.0.0", + "monolog/monolog": "^1.18" + }, + "suggest" : { + "ext-curl" : "*", + "ext-pdo" : "*" + }, + "autoload": { + "psr-4" : { + "Sabre\\DAV\\" : "lib/DAV/", + "Sabre\\DAVACL\\" : "lib/DAVACL/", + "Sabre\\CalDAV\\" : "lib/CalDAV/", + "Sabre\\CardDAV\\" : "lib/CardDAV/" + } + }, + "support" : { + "forum" : "https://groups.google.com/group/sabredav-discuss", + "source" : "https://github.com/fruux/sabre-dav" + }, + "bin" : [ + "bin/sabredav", + "bin/naturalselection" + ], + "config" : { + "bin-dir" : "./bin" + }, + "extra" : { + "branch-alias": { + "dev-master": "3.1.0-dev" + } + } +} diff --git a/vendor/sabre/dav/tests/Sabre/CalDAV/Backend/AbstractPDOTest.php b/vendor/sabre/dav/tests/Sabre/CalDAV/Backend/AbstractPDOTest.php new file mode 100644 index 000000000..406dbe0e8 --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/CalDAV/Backend/AbstractPDOTest.php @@ -0,0 +1,1431 @@ +dropTables([ + 'calendarobjects', + 'calendars', + 'calendarinstances', + 'calendarchanges', + 'calendarsubscriptions', + 'schedulingobjects', + ]); + $this->createSchema('calendars'); + + $this->pdo = $this->getDb(); + + } + + function testConstruct() { + + $backend = new PDO($this->pdo); + $this->assertTrue($backend instanceof PDO); + + } + + /** + * @depends testConstruct + */ + function testGetCalendarsForUserNoCalendars() { + + $backend = new PDO($this->pdo); + $calendars = $backend->getCalendarsForUser('principals/user2'); + $this->assertEquals([], $calendars); + + } + + /** + * @depends testConstruct + */ + function testCreateCalendarAndFetch() { + + $backend = new PDO($this->pdo); + $returnedId = $backend->createCalendar('principals/user2', 'somerandomid', [ + '{urn:ietf:params:xml:ns:caldav}supported-calendar-component-set' => new CalDAV\Xml\Property\SupportedCalendarComponentSet(['VEVENT']), + '{DAV:}displayname' => 'Hello!', + '{urn:ietf:params:xml:ns:caldav}schedule-calendar-transp' => new CalDAV\Xml\Property\ScheduleCalendarTransp('transparent'), + ]); + $calendars = $backend->getCalendarsForUser('principals/user2'); + + $elementCheck = [ + 'uri' => 'somerandomid', + '{DAV:}displayname' => 'Hello!', + '{urn:ietf:params:xml:ns:caldav}calendar-description' => '', + '{urn:ietf:params:xml:ns:caldav}schedule-calendar-transp' => new CalDAV\Xml\Property\ScheduleCalendarTransp('transparent'), + 'share-access' => \Sabre\DAV\Sharing\Plugin::ACCESS_SHAREDOWNER, + ]; + + $this->assertInternalType('array', $calendars); + $this->assertEquals(1, count($calendars)); + + foreach ($elementCheck as $name => $value) { + + $this->assertArrayHasKey($name, $calendars[0]); + $this->assertEquals($value, $calendars[0][$name]); + + } + + } + + /** + * @depends testConstruct + */ + function testUpdateCalendarAndFetch() { + + $backend = new PDO($this->pdo); + + //Creating a new calendar + $newId = $backend->createCalendar('principals/user2', 'somerandomid', []); + + $propPatch = new PropPatch([ + '{DAV:}displayname' => 'myCalendar', + '{urn:ietf:params:xml:ns:caldav}schedule-calendar-transp' => new CalDAV\Xml\Property\ScheduleCalendarTransp('transparent'), + ]); + + // Updating the calendar + $backend->updateCalendar($newId, $propPatch); + $result = $propPatch->commit(); + + // Verifying the result of the update + $this->assertTrue($result); + + // Fetching all calendars from this user + $calendars = $backend->getCalendarsForUser('principals/user2'); + + // Checking if all the information is still correct + $elementCheck = [ + 'id' => $newId, + 'uri' => 'somerandomid', + '{DAV:}displayname' => 'myCalendar', + '{urn:ietf:params:xml:ns:caldav}calendar-description' => '', + '{urn:ietf:params:xml:ns:caldav}calendar-timezone' => '', + '{http://calendarserver.org/ns/}getctag' => 'http://sabre.io/ns/sync/2', + '{urn:ietf:params:xml:ns:caldav}schedule-calendar-transp' => new CalDAV\Xml\Property\ScheduleCalendarTransp('transparent'), + ]; + + $this->assertInternalType('array', $calendars); + $this->assertEquals(1, count($calendars)); + + foreach ($elementCheck as $name => $value) { + + $this->assertArrayHasKey($name, $calendars[0]); + $this->assertEquals($value, $calendars[0][$name]); + + } + + } + + /** + * @depends testConstruct + * @expectedException \InvalidArgumentException + */ + function testUpdateCalendarBadId() { + + $backend = new PDO($this->pdo); + + //Creating a new calendar + $newId = $backend->createCalendar('principals/user2', 'somerandomid', []); + + $propPatch = new PropPatch([ + '{DAV:}displayname' => 'myCalendar', + '{urn:ietf:params:xml:ns:caldav}schedule-calendar-transp' => new CalDAV\Xml\Property\ScheduleCalendarTransp('transparent'), + ]); + + // Updating the calendar + $backend->updateCalendar('raaaa', $propPatch); + + } + + /** + * @depends testUpdateCalendarAndFetch + */ + function testUpdateCalendarUnknownProperty() { + + $backend = new PDO($this->pdo); + + //Creating a new calendar + $newId = $backend->createCalendar('principals/user2', 'somerandomid', []); + + $propPatch = new PropPatch([ + '{DAV:}displayname' => 'myCalendar', + '{DAV:}yourmom' => 'wittycomment', + ]); + + // Updating the calendar + $backend->updateCalendar($newId, $propPatch); + $propPatch->commit(); + + // Verifying the result of the update + $this->assertEquals([ + '{DAV:}yourmom' => 403, + '{DAV:}displayname' => 424, + ], $propPatch->getResult()); + + } + + /** + * @depends testCreateCalendarAndFetch + */ + function testDeleteCalendar() { + + $backend = new PDO($this->pdo); + $returnedId = $backend->createCalendar('principals/user2', 'somerandomid', [ + '{urn:ietf:params:xml:ns:caldav}supported-calendar-component-set' => new CalDAV\Xml\Property\SupportedCalendarComponentSet(['VEVENT']), + '{DAV:}displayname' => 'Hello!', + ]); + + $backend->deleteCalendar($returnedId); + + $calendars = $backend->getCalendarsForUser('principals/user2'); + $this->assertEquals([], $calendars); + + } + + /** + * @depends testCreateCalendarAndFetch + * @expectedException \InvalidArgumentException + */ + function testDeleteCalendarBadID() { + + $backend = new PDO($this->pdo); + $returnedId = $backend->createCalendar('principals/user2', 'somerandomid', [ + '{urn:ietf:params:xml:ns:caldav}supported-calendar-component-set' => new CalDAV\Xml\Property\SupportedCalendarComponentSet(['VEVENT']), + '{DAV:}displayname' => 'Hello!', + ]); + + $backend->deleteCalendar('bad-id'); + + } + + /** + * @depends testCreateCalendarAndFetch + * @expectedException \Sabre\DAV\Exception + */ + function testCreateCalendarIncorrectComponentSet() {; + + $backend = new PDO($this->pdo); + + //Creating a new calendar + $newId = $backend->createCalendar('principals/user2', 'somerandomid', [ + '{urn:ietf:params:xml:ns:caldav}supported-calendar-component-set' => 'blabla', + ]); + + } + + function testCreateCalendarObject() { + + $backend = new PDO($this->pdo); + $returnedId = $backend->createCalendar('principals/user2', 'somerandomid', []); + + $object = "BEGIN:VCALENDAR\r\nBEGIN:VEVENT\r\nDTSTART;VALUE=DATE:20120101\r\nEND:VEVENT\r\nEND:VCALENDAR\r\n"; + + $backend->createCalendarObject($returnedId, 'random-id', $object); + + $result = $this->pdo->query('SELECT etag, size, calendardata, firstoccurence, lastoccurence, componenttype FROM calendarobjects WHERE uri = \'random-id\''); + + $row = $result->fetch(\PDO::FETCH_ASSOC); + if (is_resource($row['calendardata'])) { + $row['calendardata'] = stream_get_contents($row['calendardata']); + } + + $this->assertEquals([ + 'etag' => md5($object), + 'size' => strlen($object), + 'calendardata' => $object, + 'firstoccurence' => strtotime('20120101'), + 'lastoccurence' => strtotime('20120101') + (3600 * 24), + 'componenttype' => 'VEVENT', + ], $row); + + } + function testGetMultipleObjects() { + + $backend = new PDO($this->pdo); + $returnedId = $backend->createCalendar('principals/user2', 'somerandomid', []); + + $object = "BEGIN:VCALENDAR\r\nBEGIN:VEVENT\r\nDTSTART;VALUE=DATE:20120101\r\nEND:VEVENT\r\nEND:VCALENDAR\r\n"; + + $backend->createCalendarObject($returnedId, 'id-1', $object); + $backend->createCalendarObject($returnedId, 'id-2', $object); + + $check = [ + [ + 'id' => 1, + 'etag' => '"' . md5($object) . '"', + 'uri' => 'id-1', + 'size' => strlen($object), + 'calendardata' => $object, + 'lastmodified' => null, + ], + [ + 'id' => 2, + 'etag' => '"' . md5($object) . '"', + 'uri' => 'id-2', + 'size' => strlen($object), + 'calendardata' => $object, + 'lastmodified' => null, + ], + ]; + + $result = $backend->getMultipleCalendarObjects($returnedId, ['id-1', 'id-2']); + + foreach ($check as $index => $props) { + + foreach ($props as $key => $expected) { + + $actual = $result[$index][$key]; + + switch ($key) { + case 'lastmodified' : + $this->assertInternalType('int', $actual); + break; + case 'calendardata' : + if (is_resource($actual)) { + $actual = stream_get_contents($actual); + } + // no break intentional + default : + $this->assertEquals($expected, $actual); + + } + + } + + } + + } + + /** + * @depends testGetMultipleObjects + * @expectedException \InvalidArgumentException + */ + function testGetMultipleObjectsBadId() { + + $backend = new PDO($this->pdo); + $backend->getMultipleCalendarObjects('bad-id', ['foo-bar']); + + } + + /** + * @expectedException Sabre\DAV\Exception\BadRequest + * @depends testCreateCalendarObject + */ + function testCreateCalendarObjectNoComponent() { + + $backend = new PDO($this->pdo); + $returnedId = $backend->createCalendar('principals/user2', 'somerandomid', []); + + $object = "BEGIN:VCALENDAR\r\nBEGIN:VTIMEZONE\r\nEND:VTIMEZONE\r\nEND:VCALENDAR\r\n"; + + $backend->createCalendarObject($returnedId, 'random-id', $object); + + } + + /** + * @depends testCreateCalendarObject + */ + function testCreateCalendarObjectDuration() { + + $backend = new PDO($this->pdo); + $returnedId = $backend->createCalendar('principals/user2', 'somerandomid', []); + + $object = "BEGIN:VCALENDAR\r\nBEGIN:VEVENT\r\nDTSTART;VALUE=DATE:20120101\r\nDURATION:P2D\r\nEND:VEVENT\r\nEND:VCALENDAR\r\n"; + + $backend->createCalendarObject($returnedId, 'random-id', $object); + + $result = $this->pdo->query('SELECT etag, size, calendardata, firstoccurence, lastoccurence, componenttype FROM calendarobjects WHERE uri = \'random-id\''); + + $row = $result->fetch(\PDO::FETCH_ASSOC); + if (is_resource($row['calendardata'])) { + $row['calendardata'] = stream_get_contents($row['calendardata']); + } + + $this->assertEquals([ + 'etag' => md5($object), + 'size' => strlen($object), + 'calendardata' => $object, + 'firstoccurence' => strtotime('20120101'), + 'lastoccurence' => strtotime('20120101') + (3600 * 48), + 'componenttype' => 'VEVENT', + ], $row); + + } + + /** + * @depends testCreateCalendarObject + * @expectedException \InvalidArgumentException + */ + function testCreateCalendarObjectBadId() { + + $backend = new PDO($this->pdo); + $returnedId = $backend->createCalendar('principals/user2', 'somerandomid', []); + + $object = "BEGIN:VCALENDAR\r\nBEGIN:VEVENT\r\nDTSTART;VALUE=DATE:20120101\r\nDURATION:P2D\r\nEND:VEVENT\r\nEND:VCALENDAR\r\n"; + + $backend->createCalendarObject('bad-id', 'random-id', $object); + + } + + + /** + * @depends testCreateCalendarObject + */ + function testCreateCalendarObjectNoDTEND() { + + $backend = new PDO($this->pdo); + $returnedId = $backend->createCalendar('principals/user2', 'somerandomid', []); + + $object = "BEGIN:VCALENDAR\r\nBEGIN:VEVENT\r\nDTSTART;VALUE=DATE-TIME:20120101T100000Z\r\nEND:VEVENT\r\nEND:VCALENDAR\r\n"; + + $backend->createCalendarObject($returnedId, 'random-id', $object); + + $result = $this->pdo->query('SELECT etag, size, calendardata, firstoccurence, lastoccurence, componenttype FROM calendarobjects WHERE uri = \'random-id\''); + $row = $result->fetch(\PDO::FETCH_ASSOC); + if (is_resource($row['calendardata'])) { + $row['calendardata'] = stream_get_contents($row['calendardata']); + } + + $this->assertEquals([ + 'etag' => md5($object), + 'size' => strlen($object), + 'calendardata' => $object, + 'firstoccurence' => strtotime('2012-01-01 10:00:00'), + 'lastoccurence' => strtotime('2012-01-01 10:00:00'), + 'componenttype' => 'VEVENT', + ], $row); + + } + + /** + * @depends testCreateCalendarObject + */ + function testCreateCalendarObjectWithDTEND() { + + $backend = new PDO($this->pdo); + $returnedId = $backend->createCalendar('principals/user2', 'somerandomid', []); + + $object = "BEGIN:VCALENDAR\r\nBEGIN:VEVENT\r\nDTSTART;VALUE=DATE-TIME:20120101T100000Z\r\nDTEND:20120101T110000Z\r\nEND:VEVENT\r\nEND:VCALENDAR\r\n"; + + $backend->createCalendarObject($returnedId, 'random-id', $object); + + $result = $this->pdo->query('SELECT etag, size, calendardata, firstoccurence, lastoccurence, componenttype FROM calendarobjects WHERE uri = \'random-id\''); + $row = $result->fetch(\PDO::FETCH_ASSOC); + if (is_resource($row['calendardata'])) { + $row['calendardata'] = stream_get_contents($row['calendardata']); + } + + $this->assertEquals([ + 'etag' => md5($object), + 'size' => strlen($object), + 'calendardata' => $object, + 'firstoccurence' => strtotime('2012-01-01 10:00:00'), + 'lastoccurence' => strtotime('2012-01-01 11:00:00'), + 'componenttype' => 'VEVENT', + ], $row); + + } + + /** + * @depends testCreateCalendarObject + */ + function testCreateCalendarObjectInfiniteRecurrence() { + + $backend = new PDO($this->pdo); + $returnedId = $backend->createCalendar('principals/user2', 'somerandomid', []); + + $object = "BEGIN:VCALENDAR\r\nBEGIN:VEVENT\r\nDTSTART;VALUE=DATE-TIME:20120101T100000Z\r\nRRULE:FREQ=DAILY\r\nUID:foo\r\nEND:VEVENT\r\nEND:VCALENDAR\r\n"; + + $backend->createCalendarObject($returnedId, 'random-id', $object); + + $result = $this->pdo->query('SELECT etag, size, calendardata, firstoccurence, lastoccurence, componenttype FROM calendarobjects WHERE uri = \'random-id\''); + $row = $result->fetch(\PDO::FETCH_ASSOC); + if (is_resource($row['calendardata'])) { + $row['calendardata'] = stream_get_contents($row['calendardata']); + } + + $this->assertEquals([ + 'etag' => md5($object), + 'size' => strlen($object), + 'calendardata' => $object, + 'firstoccurence' => strtotime('2012-01-01 10:00:00'), + 'lastoccurence' => strtotime(PDO::MAX_DATE), + 'componenttype' => 'VEVENT', + ], $row); + + } + + /** + * @depends testCreateCalendarObject + */ + function testCreateCalendarObjectEndingRecurrence() { + + $backend = new PDO($this->pdo); + $returnedId = $backend->createCalendar('principals/user2', 'somerandomid', []); + + $object = "BEGIN:VCALENDAR\r\nBEGIN:VEVENT\r\nDTSTART;VALUE=DATE-TIME:20120101T100000Z\r\nDTEND;VALUE=DATE-TIME:20120101T110000Z\r\nUID:foo\r\nRRULE:FREQ=DAILY;COUNT=1000\r\nEND:VEVENT\r\nEND:VCALENDAR\r\n"; + + $backend->createCalendarObject($returnedId, 'random-id', $object); + + $result = $this->pdo->query('SELECT etag, size, calendardata, firstoccurence, lastoccurence, componenttype FROM calendarobjects WHERE uri = \'random-id\''); + $row = $result->fetch(\PDO::FETCH_ASSOC); + if (is_resource($row['calendardata'])) { + $row['calendardata'] = stream_get_contents($row['calendardata']); + } + + $this->assertEquals([ + 'etag' => md5($object), + 'size' => strlen($object), + 'calendardata' => $object, + 'firstoccurence' => strtotime('2012-01-01 10:00:00'), + 'lastoccurence' => strtotime('2012-01-01 11:00:00') + (3600 * 24 * 999), + 'componenttype' => 'VEVENT', + ], $row); + + } + + /** + * @depends testCreateCalendarObject + */ + function testCreateCalendarObjectTask() { + + $backend = new PDO($this->pdo); + $returnedId = $backend->createCalendar('principals/user2', 'somerandomid', []); + + $object = "BEGIN:VCALENDAR\r\nBEGIN:VTODO\r\nDUE;VALUE=DATE-TIME:20120101T100000Z\r\nEND:VTODO\r\nEND:VCALENDAR\r\n"; + + $backend->createCalendarObject($returnedId, 'random-id', $object); + + $result = $this->pdo->query('SELECT etag, size, calendardata, firstoccurence, lastoccurence, componenttype FROM calendarobjects WHERE uri = \'random-id\''); + $row = $result->fetch(\PDO::FETCH_ASSOC); + if (is_resource($row['calendardata'])) { + $row['calendardata'] = stream_get_contents($row['calendardata']); + } + + $this->assertEquals([ + 'etag' => md5($object), + 'size' => strlen($object), + 'calendardata' => $object, + 'firstoccurence' => null, + 'lastoccurence' => null, + 'componenttype' => 'VTODO', + ], $row); + + } + + /** + * @depends testCreateCalendarObject + */ + function testGetCalendarObjects() { + + $backend = new PDO($this->pdo); + $returnedId = $backend->createCalendar('principals/user2', 'somerandomid', []); + + $object = "BEGIN:VCALENDAR\r\nBEGIN:VEVENT\r\nDTSTART;VALUE=DATE:20120101\r\nEND:VEVENT\r\nEND:VCALENDAR\r\n"; + $backend->createCalendarObject($returnedId, 'random-id', $object); + + $data = $backend->getCalendarObjects($returnedId); + + $this->assertEquals(1, count($data)); + $data = $data[0]; + + $this->assertEquals('random-id', $data['uri']); + $this->assertEquals(strlen($object), $data['size']); + + } + + /** + * @depends testGetCalendarObjects + * @expectedException \InvalidArgumentException + */ + function testGetCalendarObjectsBadId() { + + $backend = new PDO($this->pdo); + $backend->getCalendarObjects('bad-id'); + + } + + /** + * @depends testGetCalendarObjects + * @expectedException \InvalidArgumentException + */ + function testGetCalendarObjectBadId() { + + $backend = new PDO($this->pdo); + $backend->getCalendarObject('bad-id', 'foo-bar'); + + } + + /** + * @depends testCreateCalendarObject + */ + function testGetCalendarObjectByUID() { + + $backend = new PDO($this->pdo); + $returnedId = $backend->createCalendar('principals/user2', 'somerandomid', []); + + $object = "BEGIN:VCALENDAR\r\nBEGIN:VEVENT\r\nUID:foo\r\nDTSTART;VALUE=DATE:20120101\r\nEND:VEVENT\r\nEND:VCALENDAR\r\n"; + $backend->createCalendarObject($returnedId, 'random-id', $object); + + $this->assertNull( + $backend->getCalendarObjectByUID('principals/user2', 'bar') + ); + $this->assertEquals( + 'somerandomid/random-id', + $backend->getCalendarObjectByUID('principals/user2', 'foo') + ); + + } + + /** + * @depends testCreateCalendarObject + */ + function testUpdateCalendarObject() { + + $backend = new PDO($this->pdo); + $returnedId = $backend->createCalendar('principals/user2', 'somerandomid', []); + + $object = "BEGIN:VCALENDAR\r\nBEGIN:VEVENT\r\nDTSTART;VALUE=DATE:20120101\r\nEND:VEVENT\r\nEND:VCALENDAR\r\n"; + $object2 = "BEGIN:VCALENDAR\r\nBEGIN:VEVENT\r\nDTSTART;VALUE=DATE:20130101\r\nEND:VEVENT\r\nEND:VCALENDAR\r\n"; + $backend->createCalendarObject($returnedId, 'random-id', $object); + $backend->updateCalendarObject($returnedId, 'random-id', $object2); + + $data = $backend->getCalendarObject($returnedId, 'random-id'); + + if (is_resource($data['calendardata'])) { + $data['calendardata'] = stream_get_contents($data['calendardata']); + } + + $this->assertEquals($object2, $data['calendardata']); + $this->assertEquals('random-id', $data['uri']); + + + } + + /** + * @depends testUpdateCalendarObject + * @expectedException \InvalidArgumentException + */ + function testUpdateCalendarObjectBadId() { + + $backend = new PDO($this->pdo); + $backend->updateCalendarObject('bad-id', 'object-id', 'objectdata'); + + } + + /** + * @depends testCreateCalendarObject + */ + function testDeleteCalendarObject() { + + $backend = new PDO($this->pdo); + $returnedId = $backend->createCalendar('principals/user2', 'somerandomid', []); + + $object = "BEGIN:VCALENDAR\r\nBEGIN:VEVENT\r\nDTSTART;VALUE=DATE:20120101\r\nEND:VEVENT\r\nEND:VCALENDAR\r\n"; + $backend->createCalendarObject($returnedId, 'random-id', $object); + $backend->deleteCalendarObject($returnedId, 'random-id'); + + $data = $backend->getCalendarObject($returnedId, 'random-id'); + $this->assertNull($data); + + } + + /** + * @depends testDeleteCalendarObject + * @expectedException \InvalidArgumentException + */ + function testDeleteCalendarObjectBadId() { + + $backend = new PDO($this->pdo); + $returnedId = $backend->createCalendar('principals/user2', 'somerandomid', []); + + $object = "BEGIN:VCALENDAR\r\nBEGIN:VEVENT\r\nDTSTART;VALUE=DATE:20120101\r\nEND:VEVENT\r\nEND:VCALENDAR\r\n"; + $backend->createCalendarObject($returnedId, 'random-id', $object); + $backend->deleteCalendarObject('bad-id', 'random-id'); + + } + + function testCalendarQueryNoResult() { + + $abstract = new PDO($this->pdo); + $filters = [ + 'name' => 'VCALENDAR', + 'comp-filters' => [ + [ + 'name' => 'VJOURNAL', + 'comp-filters' => [], + 'prop-filters' => [], + 'is-not-defined' => false, + 'time-range' => null, + ], + ], + 'prop-filters' => [], + 'is-not-defined' => false, + 'time-range' => null, + ]; + + $this->assertEquals([ + ], $abstract->calendarQuery([1, 1], $filters)); + + } + + /** + * @expectedException \InvalidArgumentException + * @depends testCalendarQueryNoResult + */ + function testCalendarQueryBadId() { + + $abstract = new PDO($this->pdo); + $filters = [ + 'name' => 'VCALENDAR', + 'comp-filters' => [ + [ + 'name' => 'VJOURNAL', + 'comp-filters' => [], + 'prop-filters' => [], + 'is-not-defined' => false, + 'time-range' => null, + ], + ], + 'prop-filters' => [], + 'is-not-defined' => false, + 'time-range' => null, + ]; + + $abstract->calendarQuery('bad-id', $filters); + + } + + function testCalendarQueryTodo() { + + $backend = new PDO($this->pdo); + $backend->createCalendarObject([1, 1], "todo", "BEGIN:VCALENDAR\r\nBEGIN:VTODO\r\nEND:VTODO\r\nEND:VCALENDAR\r\n"); + $backend->createCalendarObject([1, 1], "event", "BEGIN:VCALENDAR\r\nBEGIN:VEVENT\r\nDTSTART:20120101\r\nEND:VEVENT\r\nEND:VCALENDAR\r\n"); + + $filters = [ + 'name' => 'VCALENDAR', + 'comp-filters' => [ + [ + 'name' => 'VTODO', + 'comp-filters' => [], + 'prop-filters' => [], + 'is-not-defined' => false, + 'time-range' => null, + ], + ], + 'prop-filters' => [], + 'is-not-defined' => false, + 'time-range' => null, + ]; + + $this->assertEquals([ + "todo", + ], $backend->calendarQuery([1, 1], $filters)); + + } + function testCalendarQueryTodoNotMatch() { + + $backend = new PDO($this->pdo); + $backend->createCalendarObject([1, 1], "todo", "BEGIN:VCALENDAR\r\nBEGIN:VTODO\r\nEND:VTODO\r\nEND:VCALENDAR\r\n"); + $backend->createCalendarObject([1, 1], "event", "BEGIN:VCALENDAR\r\nBEGIN:VEVENT\r\nDTSTART:20120101\r\nEND:VEVENT\r\nEND:VCALENDAR\r\n"); + + $filters = [ + 'name' => 'VCALENDAR', + 'comp-filters' => [ + [ + 'name' => 'VTODO', + 'comp-filters' => [], + 'prop-filters' => [ + [ + 'name' => 'summary', + 'text-match' => null, + 'time-range' => null, + 'param-filters' => [], + 'is-not-defined' => false, + ], + ], + 'is-not-defined' => false, + 'time-range' => null, + ], + ], + 'prop-filters' => [], + 'is-not-defined' => false, + 'time-range' => null, + ]; + + $this->assertEquals([ + ], $backend->calendarQuery([1, 1], $filters)); + + } + + function testCalendarQueryNoFilter() { + + $backend = new PDO($this->pdo); + $backend->createCalendarObject([1, 1], "todo", "BEGIN:VCALENDAR\r\nBEGIN:VTODO\r\nEND:VTODO\r\nEND:VCALENDAR\r\n"); + $backend->createCalendarObject([1, 1], "event", "BEGIN:VCALENDAR\r\nBEGIN:VEVENT\r\nDTSTART:20120101\r\nEND:VEVENT\r\nEND:VCALENDAR\r\n"); + + $filters = [ + 'name' => 'VCALENDAR', + 'comp-filters' => [], + 'prop-filters' => [], + 'is-not-defined' => false, + 'time-range' => null, + ]; + + $result = $backend->calendarQuery([1, 1], $filters); + $this->assertTrue(in_array('todo', $result)); + $this->assertTrue(in_array('event', $result)); + + } + + function testCalendarQueryTimeRange() { + + $backend = new PDO($this->pdo); + $backend->createCalendarObject([1, 1], "todo", "BEGIN:VCALENDAR\r\nBEGIN:VTODO\r\nEND:VTODO\r\nEND:VCALENDAR\r\n"); + $backend->createCalendarObject([1, 1], "event", "BEGIN:VCALENDAR\r\nBEGIN:VEVENT\r\nDTSTART;VALUE=DATE:20120101\r\nEND:VEVENT\r\nEND:VCALENDAR\r\n"); + $backend->createCalendarObject([1, 1], "event2", "BEGIN:VCALENDAR\r\nBEGIN:VEVENT\r\nDTSTART;VALUE=DATE:20120103\r\nEND:VEVENT\r\nEND:VCALENDAR\r\n"); + + $filters = [ + 'name' => 'VCALENDAR', + 'comp-filters' => [ + [ + 'name' => 'VEVENT', + 'comp-filters' => [], + 'prop-filters' => [], + 'is-not-defined' => false, + 'time-range' => [ + 'start' => new \DateTime('20120103'), + 'end' => new \DateTime('20120104'), + ], + ], + ], + 'prop-filters' => [], + 'is-not-defined' => false, + 'time-range' => null, + ]; + + $this->assertEquals([ + "event2", + ], $backend->calendarQuery([1, 1], $filters)); + + } + function testCalendarQueryTimeRangeNoEnd() { + + $backend = new PDO($this->pdo); + $backend->createCalendarObject([1, 1], "todo", "BEGIN:VCALENDAR\r\nBEGIN:VTODO\r\nEND:VTODO\r\nEND:VCALENDAR\r\n"); + $backend->createCalendarObject([1, 1], "event", "BEGIN:VCALENDAR\r\nBEGIN:VEVENT\r\nDTSTART:20120101\r\nEND:VEVENT\r\nEND:VCALENDAR\r\n"); + $backend->createCalendarObject([1, 1], "event2", "BEGIN:VCALENDAR\r\nBEGIN:VEVENT\r\nDTSTART:20120103\r\nEND:VEVENT\r\nEND:VCALENDAR\r\n"); + + $filters = [ + 'name' => 'VCALENDAR', + 'comp-filters' => [ + [ + 'name' => 'VEVENT', + 'comp-filters' => [], + 'prop-filters' => [], + 'is-not-defined' => false, + 'time-range' => [ + 'start' => new \DateTime('20120102'), + 'end' => null, + ], + ], + ], + 'prop-filters' => [], + 'is-not-defined' => false, + 'time-range' => null, + ]; + + $this->assertEquals([ + "event2", + ], $backend->calendarQuery([1, 1], $filters)); + + } + + function testGetChanges() { + + $backend = new PDO($this->pdo); + $id = $backend->createCalendar( + 'principals/user1', + 'bla', + [] + ); + $result = $backend->getChangesForCalendar($id, null, 1); + + $this->assertEquals([ + 'syncToken' => 1, + 'modified' => [], + 'deleted' => [], + 'added' => [], + ], $result); + + $currentToken = $result['syncToken']; + + $dummyTodo = "BEGIN:VCALENDAR\r\nBEGIN:VTODO\r\nEND:VTODO\r\nEND:VCALENDAR\r\n"; + + $backend->createCalendarObject($id, "todo1.ics", $dummyTodo); + $backend->createCalendarObject($id, "todo2.ics", $dummyTodo); + $backend->createCalendarObject($id, "todo3.ics", $dummyTodo); + $backend->updateCalendarObject($id, "todo1.ics", $dummyTodo); + $backend->deleteCalendarObject($id, "todo2.ics"); + + $result = $backend->getChangesForCalendar($id, $currentToken, 1); + + $this->assertEquals([ + 'syncToken' => 6, + 'modified' => ["todo1.ics"], + 'deleted' => ["todo2.ics"], + 'added' => ["todo3.ics"], + ], $result); + + $result = $backend->getChangesForCalendar($id, null, 1); + + $this->assertEquals([ + 'syncToken' => 6, + 'modified' => [], + 'deleted' => [], + 'added' => ["todo1.ics", "todo3.ics"], + ], $result); + } + + /** + * @depends testGetChanges + * @expectedException \InvalidArgumentException + */ + function testGetChangesBadId() { + + $backend = new PDO($this->pdo); + $id = $backend->createCalendar( + 'principals/user1', + 'bla', + [] + ); + $backend->getChangesForCalendar('bad-id', null, 1); + + } + + function testCreateSubscriptions() { + + $props = [ + '{http://calendarserver.org/ns/}source' => new \Sabre\DAV\Xml\Property\Href('http://example.org/cal.ics', false), + '{DAV:}displayname' => 'cal', + '{http://apple.com/ns/ical/}refreshrate' => 'P1W', + '{http://apple.com/ns/ical/}calendar-color' => '#FF00FFFF', + '{http://calendarserver.org/ns/}subscribed-strip-todos' => true, + //'{http://calendarserver.org/ns/}subscribed-strip-alarms' => true, + '{http://calendarserver.org/ns/}subscribed-strip-attachments' => true, + ]; + + $backend = new PDO($this->pdo); + $backend->createSubscription('principals/user1', 'sub1', $props); + + $subs = $backend->getSubscriptionsForUser('principals/user1'); + + $expected = $props; + $expected['id'] = 1; + $expected['uri'] = 'sub1'; + $expected['principaluri'] = 'principals/user1'; + + unset($expected['{http://calendarserver.org/ns/}source']); + $expected['source'] = 'http://example.org/cal.ics'; + + $this->assertEquals(1, count($subs)); + foreach ($expected as $k => $v) { + $this->assertEquals($subs[0][$k], $expected[$k]); + } + + } + + /** + * @expectedException \Sabre\DAV\Exception\Forbidden + */ + function testCreateSubscriptionFail() { + + $props = [ + ]; + + $backend = new PDO($this->pdo); + $backend->createSubscription('principals/user1', 'sub1', $props); + + } + + function testUpdateSubscriptions() { + + $props = [ + '{http://calendarserver.org/ns/}source' => new \Sabre\DAV\Xml\Property\Href('http://example.org/cal.ics', false), + '{DAV:}displayname' => 'cal', + '{http://apple.com/ns/ical/}refreshrate' => 'P1W', + '{http://apple.com/ns/ical/}calendar-color' => '#FF00FFFF', + '{http://calendarserver.org/ns/}subscribed-strip-todos' => true, + //'{http://calendarserver.org/ns/}subscribed-strip-alarms' => true, + '{http://calendarserver.org/ns/}subscribed-strip-attachments' => true, + ]; + + $backend = new PDO($this->pdo); + $backend->createSubscription('principals/user1', 'sub1', $props); + + $newProps = [ + '{DAV:}displayname' => 'new displayname', + '{http://calendarserver.org/ns/}source' => new \Sabre\DAV\Xml\Property\Href('http://example.org/cal2.ics', false), + ]; + + $propPatch = new DAV\PropPatch($newProps); + $backend->updateSubscription(1, $propPatch); + $result = $propPatch->commit(); + + $this->assertTrue($result); + + $subs = $backend->getSubscriptionsForUser('principals/user1'); + + $expected = array_merge($props, $newProps); + $expected['id'] = 1; + $expected['uri'] = 'sub1'; + $expected['principaluri'] = 'principals/user1'; + + unset($expected['{http://calendarserver.org/ns/}source']); + $expected['source'] = 'http://example.org/cal2.ics'; + + $this->assertEquals(1, count($subs)); + foreach ($expected as $k => $v) { + $this->assertEquals($subs[0][$k], $expected[$k]); + } + + } + + function testUpdateSubscriptionsFail() { + + $props = [ + '{http://calendarserver.org/ns/}source' => new \Sabre\DAV\Xml\Property\Href('http://example.org/cal.ics', false), + '{DAV:}displayname' => 'cal', + '{http://apple.com/ns/ical/}refreshrate' => 'P1W', + '{http://apple.com/ns/ical/}calendar-color' => '#FF00FFFF', + '{http://calendarserver.org/ns/}subscribed-strip-todos' => true, + //'{http://calendarserver.org/ns/}subscribed-strip-alarms' => true, + '{http://calendarserver.org/ns/}subscribed-strip-attachments' => true, + ]; + + $backend = new PDO($this->pdo); + $backend->createSubscription('principals/user1', 'sub1', $props); + + $propPatch = new DAV\PropPatch([ + '{DAV:}displayname' => 'new displayname', + '{http://calendarserver.org/ns/}source' => new \Sabre\DAV\Xml\Property\Href('http://example.org/cal2.ics', false), + '{DAV:}unknown' => 'foo', + ]); + + $backend->updateSubscription(1, $propPatch); + $propPatch->commit(); + + $this->assertEquals([ + '{DAV:}unknown' => 403, + '{DAV:}displayname' => 424, + '{http://calendarserver.org/ns/}source' => 424, + ], $propPatch->getResult()); + + } + + function testDeleteSubscriptions() { + + $props = [ + '{http://calendarserver.org/ns/}source' => new \Sabre\DAV\Xml\Property\Href('http://example.org/cal.ics', false), + '{DAV:}displayname' => 'cal', + '{http://apple.com/ns/ical/}refreshrate' => 'P1W', + '{http://apple.com/ns/ical/}calendar-color' => '#FF00FFFF', + '{http://calendarserver.org/ns/}subscribed-strip-todos' => true, + //'{http://calendarserver.org/ns/}subscribed-strip-alarms' => true, + '{http://calendarserver.org/ns/}subscribed-strip-attachments' => true, + ]; + + $backend = new PDO($this->pdo); + $backend->createSubscription('principals/user1', 'sub1', $props); + + $newProps = [ + '{DAV:}displayname' => 'new displayname', + '{http://calendarserver.org/ns/}source' => new \Sabre\DAV\Xml\Property\Href('http://example.org/cal2.ics', false), + ]; + + $backend->deleteSubscription(1); + + $subs = $backend->getSubscriptionsForUser('principals/user1'); + $this->assertEquals(0, count($subs)); + } + + function testSchedulingMethods() { + + $backend = new PDO($this->pdo); + + $calData = "BEGIN:VCALENDAR\r\nEND:VCALENDAR\r\n"; + + $backend->createSchedulingObject( + 'principals/user1', + 'schedule1.ics', + $calData + ); + + $expected = [ + 'calendardata' => $calData, + 'uri' => 'schedule1.ics', + 'etag' => '"' . md5($calData) . '"', + 'size' => strlen($calData) + ]; + + $result = $backend->getSchedulingObject('principals/user1', 'schedule1.ics'); + foreach ($expected as $k => $v) { + $this->assertArrayHasKey($k, $result); + if (is_resource($result[$k])) { + $result[$k] = stream_get_contents($result[$k]); + } + $this->assertEquals($v, $result[$k]); + } + + $results = $backend->getSchedulingObjects('principals/user1'); + + $this->assertEquals(1, count($results)); + $result = $results[0]; + foreach ($expected as $k => $v) { + if (is_resource($result[$k])) { + $result[$k] = stream_get_contents($result[$k]); + } + $this->assertEquals($v, $result[$k]); + } + + $backend->deleteSchedulingObject('principals/user1', 'schedule1.ics'); + $result = $backend->getSchedulingObject('principals/user1', 'schedule1.ics'); + + $this->assertNull($result); + + } + + function testGetInvites() { + + $backend = new PDO($this->pdo); + + // creating a new calendar + $backend->createCalendar('principals/user1', 'somerandomid', []); + $calendar = $backend->getCalendarsForUser('principals/user1')[0]; + + $result = $backend->getInvites($calendar['id']); + $expected = [ + new Sharee([ + 'href' => 'principals/user1', + 'principal' => 'principals/user1', + 'access' => \Sabre\DAV\Sharing\Plugin::ACCESS_SHAREDOWNER, + 'inviteStatus' => \Sabre\DAV\Sharing\Plugin::INVITE_ACCEPTED, + ]) + ]; + + $this->assertEquals($expected, $result); + + } + + /** + * @depends testGetInvites + * @expectedException \InvalidArgumentException + */ + function testGetInvitesBadId() { + + $backend = new PDO($this->pdo); + + // creating a new calendar + $backend->createCalendar('principals/user1', 'somerandomid', []); + $calendar = $backend->getCalendarsForUser('principals/user1')[0]; + + $backend->getInvites('bad-id'); + + } + + /** + * @depends testCreateCalendarAndFetch + */ + function testUpdateInvites() { + + $backend = new PDO($this->pdo); + + // creating a new calendar + $backend->createCalendar('principals/user1', 'somerandomid', []); + $calendar = $backend->getCalendarsForUser('principals/user1')[0]; + + $ownerSharee = new Sharee([ + 'href' => 'principals/user1', + 'principal' => 'principals/user1', + 'access' => \Sabre\DAV\Sharing\Plugin::ACCESS_SHAREDOWNER, + 'inviteStatus' => \Sabre\DAV\Sharing\Plugin::INVITE_ACCEPTED, + ]); + + // Add a new invite + $backend->updateInvites( + $calendar['id'], + [ + new Sharee([ + 'href' => 'mailto:user@example.org', + 'principal' => 'principals/user2', + 'access' => \Sabre\DAV\Sharing\Plugin::ACCESS_READ, + 'inviteStatus' => \Sabre\DAV\Sharing\Plugin::INVITE_ACCEPTED, + 'properties' => ['{DAV:}displayname' => 'User 2'], + ]) + ] + ); + + $result = $backend->getInvites($calendar['id']); + $expected = [ + $ownerSharee, + new Sharee([ + 'href' => 'mailto:user@example.org', + 'principal' => 'principals/user2', + 'access' => \Sabre\DAV\Sharing\Plugin::ACCESS_READ, + 'inviteStatus' => \Sabre\DAV\Sharing\Plugin::INVITE_ACCEPTED, + 'properties' => [ + '{DAV:}displayname' => 'User 2', + ], + ]) + ]; + $this->assertEquals($expected, $result); + + // Checking calendar_instances too + $expectedCalendar = [ + 'id' => [1,2], + 'principaluri' => 'principals/user2', + '{http://calendarserver.org/ns/}getctag' => 'http://sabre.io/ns/sync/1', + '{http://sabredav.org/ns}sync-token' => '1', + 'share-access' => \Sabre\DAV\Sharing\Plugin::ACCESS_READ, + 'read-only' => true, + 'share-resource-uri' => '/ns/share/1', + ]; + $calendars = $backend->getCalendarsForUser('principals/user2'); + + foreach ($expectedCalendar as $k => $v) { + $this->assertEquals( + $v, + $calendars[0][$k], + "Key " . $k . " in calendars array did not have the expected value." + ); + } + + + // Updating an invite + $backend->updateInvites( + $calendar['id'], + [ + new Sharee([ + 'href' => 'mailto:user@example.org', + 'principal' => 'principals/user2', + 'access' => \Sabre\DAV\Sharing\Plugin::ACCESS_READWRITE, + 'inviteStatus' => \Sabre\DAV\Sharing\Plugin::INVITE_ACCEPTED, + ]) + ] + ); + + $result = $backend->getInvites($calendar['id']); + $expected = [ + $ownerSharee, + new Sharee([ + 'href' => 'mailto:user@example.org', + 'principal' => 'principals/user2', + 'access' => \Sabre\DAV\Sharing\Plugin::ACCESS_READWRITE, + 'inviteStatus' => \Sabre\DAV\Sharing\Plugin::INVITE_ACCEPTED, + 'properties' => [ + '{DAV:}displayname' => 'User 2', + ], + ]) + ]; + $this->assertEquals($expected, $result); + + // Removing an invite + $backend->updateInvites( + $calendar['id'], + [ + new Sharee([ + 'href' => 'mailto:user@example.org', + 'access' => \Sabre\DAV\Sharing\Plugin::ACCESS_NOACCESS, + ]) + ] + ); + + $result = $backend->getInvites($calendar['id']); + $expected = [ + $ownerSharee + ]; + $this->assertEquals($expected, $result); + + // Preventing the owner share from being removed + $backend->updateInvites( + $calendar['id'], + [ + new Sharee([ + 'href' => 'principals/user2', + 'access' => \Sabre\DAV\Sharing\Plugin::ACCESS_NOACCESS, + ]) + ] + ); + + $result = $backend->getInvites($calendar['id']); + $expected = [ + new Sharee([ + 'href' => 'principals/user1', + 'principal' => 'principals/user1', + 'access' => \Sabre\DAV\Sharing\Plugin::ACCESS_SHAREDOWNER, + 'inviteStatus' => \Sabre\DAV\Sharing\Plugin::INVITE_ACCEPTED, + ]), + ]; + $this->assertEquals($expected, $result); + + } + + /** + * @depends testUpdateInvites + * @expectedException \InvalidArgumentException + */ + function testUpdateInvitesBadId() { + + $backend = new PDO($this->pdo); + // Add a new invite + $backend->updateInvites( + 'bad-id', + [] + ); + + } + + /** + * @depends testUpdateInvites + */ + function testUpdateInvitesNoPrincipal() { + + $backend = new PDO($this->pdo); + + // creating a new calendar + $backend->createCalendar('principals/user1', 'somerandomid', []); + $calendar = $backend->getCalendarsForUser('principals/user1')[0]; + + $ownerSharee = new Sharee([ + 'href' => 'principals/user1', + 'principal' => 'principals/user1', + 'access' => \Sabre\DAV\Sharing\Plugin::ACCESS_SHAREDOWNER, + 'inviteStatus' => \Sabre\DAV\Sharing\Plugin::INVITE_ACCEPTED, + ]); + + // Add a new invite + $backend->updateInvites( + $calendar['id'], + [ + new Sharee([ + 'href' => 'mailto:user@example.org', + 'principal' => null, + 'access' => \Sabre\DAV\Sharing\Plugin::ACCESS_READ, + 'inviteStatus' => \Sabre\DAV\Sharing\Plugin::INVITE_ACCEPTED, + 'properties' => ['{DAV:}displayname' => 'User 2'], + ]) + ] + ); + + $result = $backend->getInvites($calendar['id']); + $expected = [ + $ownerSharee, + new Sharee([ + 'href' => 'mailto:user@example.org', + 'principal' => null, + 'access' => \Sabre\DAV\Sharing\Plugin::ACCESS_READ, + 'inviteStatus' => \Sabre\DAV\Sharing\Plugin::INVITE_INVALID, + 'properties' => [ + '{DAV:}displayname' => 'User 2', + ], + ]) + ]; + $this->assertEquals($expected, $result, null, 0.0, 10, true); // Last argument is $canonicalize = true, which allows us to compare, ignoring the order, because it's different between MySQL and Sqlite. + + } + + /** + * @depends testUpdateInvites + */ + function testDeleteSharedCalendar() { + + $backend = new PDO($this->pdo); + + // creating a new calendar + $backend->createCalendar('principals/user1', 'somerandomid', []); + $calendar = $backend->getCalendarsForUser('principals/user1')[0]; + + $ownerSharee = new Sharee([ + 'href' => 'principals/user1', + 'principal' => 'principals/user1', + 'access' => \Sabre\DAV\Sharing\Plugin::ACCESS_SHAREDOWNER, + 'inviteStatus' => \Sabre\DAV\Sharing\Plugin::INVITE_ACCEPTED, + ]); + + // Add a new invite + $backend->updateInvites( + $calendar['id'], + [ + new Sharee([ + 'href' => 'mailto:user@example.org', + 'principal' => 'principals/user2', + 'access' => \Sabre\DAV\Sharing\Plugin::ACCESS_READ, + 'inviteStatus' => \Sabre\DAV\Sharing\Plugin::INVITE_ACCEPTED, + 'properties' => ['{DAV:}displayname' => 'User 2'], + ]) + ] + ); + + $expectedCalendar = [ + 'id' => [1,2], + 'principaluri' => 'principals/user2', + '{http://calendarserver.org/ns/}getctag' => 'http://sabre.io/ns/sync/1', + '{http://sabredav.org/ns}sync-token' => '1', + 'share-access' => \Sabre\DAV\Sharing\Plugin::ACCESS_READ, + 'read-only' => true, + 'share-resource-uri' => '/ns/share/1', + ]; + $calendars = $backend->getCalendarsForUser('principals/user2'); + + foreach ($expectedCalendar as $k => $v) { + $this->assertEquals( + $v, + $calendars[0][$k], + "Key " . $k . " in calendars array did not have the expected value." + ); + } + + // Removing the shared calendar. + $backend->deleteCalendar($calendars[0]['id']); + + $this->assertEquals( + [], + $backend->getCalendarsForUser('principals/user2') + ); + + $result = $backend->getInvites($calendar['id']); + $expected = [ + new Sharee([ + 'href' => 'principals/user1', + 'principal' => 'principals/user1', + 'access' => \Sabre\DAV\Sharing\Plugin::ACCESS_SHAREDOWNER, + 'inviteStatus' => \Sabre\DAV\Sharing\Plugin::INVITE_ACCEPTED, + ]), + ]; + $this->assertEquals($expected, $result); + + } + + /** + * @expectedException \Sabre\DAV\Exception\NotImplemented + */ + function testSetPublishStatus() { + + $backend = new PDO($this->pdo); + $backend->setPublishStatus([1, 1], true); + + } + +} diff --git a/vendor/sabre/dav/tests/Sabre/CalDAV/Backend/AbstractTest.php b/vendor/sabre/dav/tests/Sabre/CalDAV/Backend/AbstractTest.php new file mode 100644 index 000000000..7f642efc9 --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/CalDAV/Backend/AbstractTest.php @@ -0,0 +1,178 @@ + 'anything']); + + $abstract->updateCalendar('randomid', $propPatch); + $result = $propPatch->commit(); + + $this->assertFalse($result); + + } + + function testCalendarQuery() { + + $abstract = new AbstractMock(); + $filters = [ + 'name' => 'VCALENDAR', + 'comp-filters' => [ + [ + 'name' => 'VEVENT', + 'comp-filters' => [], + 'prop-filters' => [], + 'is-not-defined' => false, + 'time-range' => null, + ], + ], + 'prop-filters' => [], + 'is-not-defined' => false, + 'time-range' => null, + ]; + + $this->assertEquals([ + 'event1.ics', + ], $abstract->calendarQuery(1, $filters)); + + } + + function testGetCalendarObjectByUID() { + + $abstract = new AbstractMock(); + $this->assertNull( + $abstract->getCalendarObjectByUID('principal1', 'zim') + ); + $this->assertEquals( + 'cal1/event1.ics', + $abstract->getCalendarObjectByUID('principal1', 'foo') + ); + $this->assertNull( + $abstract->getCalendarObjectByUID('principal3', 'foo') + ); + $this->assertNull( + $abstract->getCalendarObjectByUID('principal1', 'shared') + ); + + } + + function testGetMultipleCalendarObjects() { + + $abstract = new AbstractMock(); + $result = $abstract->getMultipleCalendarObjects(1, [ + 'event1.ics', + 'task1.ics', + ]); + + $expected = [ + [ + 'id' => 1, + 'calendarid' => 1, + 'uri' => 'event1.ics', + 'calendardata' => "BEGIN:VCALENDAR\r\nBEGIN:VEVENT\r\nUID:foo\r\nEND:VEVENT\r\nEND:VCALENDAR\r\n", + ], + [ + 'id' => 2, + 'calendarid' => 1, + 'uri' => 'task1.ics', + 'calendardata' => "BEGIN:VCALENDAR\r\nBEGIN:VTODO\r\nEND:VTODO\r\nEND:VCALENDAR\r\n", + ], + ]; + + $this->assertEquals($expected, $result); + + + } + +} + +class AbstractMock extends AbstractBackend { + + function getCalendarsForUser($principalUri) { + + return [ + [ + 'id' => 1, + 'principaluri' => 'principal1', + 'uri' => 'cal1', + ], + [ + 'id' => 2, + 'principaluri' => 'principal1', + '{http://sabredav.org/ns}owner-principal' => 'principal2', + 'uri' => 'cal1', + ], + ]; + + } + function createCalendar($principalUri, $calendarUri, array $properties) { } + function deleteCalendar($calendarId) { } + function getCalendarObjects($calendarId) { + + switch ($calendarId) { + case 1: + return [ + [ + 'id' => 1, + 'calendarid' => 1, + 'uri' => 'event1.ics', + ], + [ + 'id' => 2, + 'calendarid' => 1, + 'uri' => 'task1.ics', + ], + ]; + case 2: + return [ + [ + 'id' => 3, + 'calendarid' => 2, + 'uri' => 'shared-event.ics', + ] + ]; + } + + } + + function getCalendarObject($calendarId, $objectUri) { + + switch ($objectUri) { + + case 'event1.ics' : + return [ + 'id' => 1, + 'calendarid' => 1, + 'uri' => 'event1.ics', + 'calendardata' => "BEGIN:VCALENDAR\r\nBEGIN:VEVENT\r\nUID:foo\r\nEND:VEVENT\r\nEND:VCALENDAR\r\n", + ]; + case 'task1.ics' : + return [ + 'id' => 2, + 'calendarid' => 1, + 'uri' => 'task1.ics', + 'calendardata' => "BEGIN:VCALENDAR\r\nBEGIN:VTODO\r\nEND:VTODO\r\nEND:VCALENDAR\r\n", + ]; + case 'shared-event.ics' : + return [ + 'id' => 3, + 'calendarid' => 2, + 'uri' => 'event1.ics', + 'calendardata' => "BEGIN:VCALENDAR\r\nBEGIN:VEVENT\r\nUID:shared\r\nEND:VEVENT\r\nEND:VCALENDAR\r\n", + ]; + + } + + } + function createCalendarObject($calendarId, $objectUri, $calendarData) { } + function updateCalendarObject($calendarId, $objectUri, $calendarData) { } + function deleteCalendarObject($calendarId, $objectUri) { } + +} diff --git a/vendor/sabre/dav/tests/Sabre/CalDAV/Backend/Mock.php b/vendor/sabre/dav/tests/Sabre/CalDAV/Backend/Mock.php new file mode 100644 index 000000000..cc665cd8f --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/CalDAV/Backend/Mock.php @@ -0,0 +1,258 @@ +calendars = $calendars; + $this->calendarData = $calendarData; + + } + + /** + * Returns a list of calendars for a principal. + * + * Every project is an array with the following keys: + * * id, a unique id that will be used by other functions to modify the + * calendar. This can be the same as the uri or a database key. + * * uri, which the basename of the uri with which the calendar is + * accessed. + * * principalUri. The owner of the calendar. Almost always the same as + * principalUri passed to this method. + * + * Furthermore it can contain webdav properties in clark notation. A very + * common one is '{DAV:}displayname'. + * + * @param string $principalUri + * @return array + */ + function getCalendarsForUser($principalUri) { + + $r = []; + foreach ($this->calendars as $row) { + if ($row['principaluri'] == $principalUri) { + $r[] = $row; + } + } + + return $r; + + } + + /** + * Creates a new calendar for a principal. + * + * If the creation was a success, an id must be returned that can be used to reference + * this calendar in other methods, such as updateCalendar. + * + * This function must return a server-wide unique id that can be used + * later to reference the calendar. + * + * @param string $principalUri + * @param string $calendarUri + * @param array $properties + * @return string|int + */ + function createCalendar($principalUri, $calendarUri, array $properties) { + + $id = DAV\UUIDUtil::getUUID(); + $this->calendars[] = array_merge([ + 'id' => $id, + 'principaluri' => $principalUri, + 'uri' => $calendarUri, + '{' . CalDAV\Plugin::NS_CALDAV . '}supported-calendar-component-set' => new CalDAV\Xml\Property\SupportedCalendarComponentSet(['VEVENT', 'VTODO']), + ], $properties); + + return $id; + + } + + /** + * Updates properties for a calendar. + * + * The list of mutations is stored in a Sabre\DAV\PropPatch object. + * To do the actual updates, you must tell this object which properties + * you're going to process with the handle() method. + * + * Calling the handle method is like telling the PropPatch object "I + * promise I can handle updating this property". + * + * Read the PropPatch documentation for more info and examples. + * + * @param mixed $calendarId + * @param \Sabre\DAV\PropPatch $propPatch + * @return void + */ + function updateCalendar($calendarId, \Sabre\DAV\PropPatch $propPatch) { + + $propPatch->handleRemaining(function($props) use ($calendarId) { + + foreach ($this->calendars as $k => $calendar) { + + if ($calendar['id'] === $calendarId) { + foreach ($props as $propName => $propValue) { + if (is_null($propValue)) { + unset($this->calendars[$k][$propName]); + } else { + $this->calendars[$k][$propName] = $propValue; + } + } + return true; + + } + + } + + }); + + } + + /** + * Delete a calendar and all it's objects + * + * @param string $calendarId + * @return void + */ + function deleteCalendar($calendarId) { + + foreach ($this->calendars as $k => $calendar) { + if ($calendar['id'] === $calendarId) { + unset($this->calendars[$k]); + } + } + + } + + /** + * Returns all calendar objects within a calendar object. + * + * Every item contains an array with the following keys: + * * id - unique identifier which will be used for subsequent updates + * * calendardata - The iCalendar-compatible calendar data + * * uri - a unique key which will be used to construct the uri. This can be any arbitrary string. + * * lastmodified - a timestamp of the last modification time + * * etag - An arbitrary string, surrounded by double-quotes. (e.g.: + * ' "abcdef"') + * * calendarid - The calendarid as it was passed to this function. + * + * Note that the etag is optional, but it's highly encouraged to return for + * speed reasons. + * + * The calendardata is also optional. If it's not returned + * 'getCalendarObject' will be called later, which *is* expected to return + * calendardata. + * + * @param string $calendarId + * @return array + */ + function getCalendarObjects($calendarId) { + + if (!isset($this->calendarData[$calendarId])) + return []; + + $objects = $this->calendarData[$calendarId]; + + foreach ($objects as $uri => &$object) { + $object['calendarid'] = $calendarId; + $object['uri'] = $uri; + $object['lastmodified'] = null; + } + return $objects; + + } + + /** + * Returns information from a single calendar object, based on it's object + * uri. + * + * The object uri is only the basename, or filename and not a full path. + * + * The returned array must have the same keys as getCalendarObjects. The + * 'calendardata' object is required here though, while it's not required + * for getCalendarObjects. + * + * This method must return null if the object did not exist. + * + * @param mixed $calendarId + * @param string $objectUri + * @return array|null + */ + function getCalendarObject($calendarId, $objectUri) { + + if (!isset($this->calendarData[$calendarId][$objectUri])) { + return null; + } + $object = $this->calendarData[$calendarId][$objectUri]; + $object['calendarid'] = $calendarId; + $object['uri'] = $objectUri; + $object['lastmodified'] = null; + return $object; + + } + + /** + * Creates a new calendar object. + * + * @param string $calendarId + * @param string $objectUri + * @param string $calendarData + * @return void + */ + function createCalendarObject($calendarId, $objectUri, $calendarData) { + + $this->calendarData[$calendarId][$objectUri] = [ + 'calendardata' => $calendarData, + 'calendarid' => $calendarId, + 'uri' => $objectUri, + ]; + return '"' . md5($calendarData) . '"'; + + } + + /** + * Updates an existing calendarobject, based on it's uri. + * + * @param string $calendarId + * @param string $objectUri + * @param string $calendarData + * @return void + */ + function updateCalendarObject($calendarId, $objectUri, $calendarData) { + + $this->calendarData[$calendarId][$objectUri] = [ + 'calendardata' => $calendarData, + 'calendarid' => $calendarId, + 'uri' => $objectUri, + ]; + return '"' . md5($calendarData) . '"'; + + } + + /** + * Deletes an existing calendar object. + * + * @param string $calendarId + * @param string $objectUri + * @return void + */ + function deleteCalendarObject($calendarId, $objectUri) { + + unset($this->calendarData[$calendarId][$objectUri]); + + } + +} diff --git a/vendor/sabre/dav/tests/Sabre/CalDAV/Backend/MockScheduling.php b/vendor/sabre/dav/tests/Sabre/CalDAV/Backend/MockScheduling.php new file mode 100644 index 000000000..3ac22f474 --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/CalDAV/Backend/MockScheduling.php @@ -0,0 +1,91 @@ +schedulingObjects[$principalUri][$objectUri])) { + return $this->schedulingObjects[$principalUri][$objectUri]; + } + + } + + /** + * Returns all scheduling objects for the inbox collection. + * + * These objects should be returned as an array. Every item in the array + * should follow the same structure as returned from getSchedulingObject. + * + * The main difference is that 'calendardata' is optional. + * + * @param string $principalUri + * @return array + */ + function getSchedulingObjects($principalUri) { + + if (isset($this->schedulingObjects[$principalUri])) { + return array_values($this->schedulingObjects[$principalUri]); + } + return []; + + } + + /** + * Deletes a scheduling object + * + * @param string $principalUri + * @param string $objectUri + * @return void + */ + function deleteSchedulingObject($principalUri, $objectUri) { + + if (isset($this->schedulingObjects[$principalUri][$objectUri])) { + unset($this->schedulingObjects[$principalUri][$objectUri]); + } + + } + + /** + * Creates a new scheduling object. This should land in a users' inbox. + * + * @param string $principalUri + * @param string $objectUri + * @param string $objectData; + * @return void + */ + function createSchedulingObject($principalUri, $objectUri, $objectData) { + + if (!isset($this->schedulingObjects[$principalUri])) { + $this->schedulingObjects[$principalUri] = []; + } + $this->schedulingObjects[$principalUri][$objectUri] = [ + 'uri' => $objectUri, + 'calendardata' => $objectData, + 'lastmodified' => null, + 'etag' => '"' . md5($objectData) . '"', + 'size' => strlen($objectData) + ]; + + } + +} diff --git a/vendor/sabre/dav/tests/Sabre/CalDAV/Backend/MockSharing.php b/vendor/sabre/dav/tests/Sabre/CalDAV/Backend/MockSharing.php new file mode 100644 index 000000000..eaf52e32f --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/CalDAV/Backend/MockSharing.php @@ -0,0 +1,204 @@ +notifications = $notifications; + + } + + /** + * Returns a list of calendars for a principal. + * + * Every project is an array with the following keys: + * * id, a unique id that will be used by other functions to modify the + * calendar. This can be the same as the uri or a database key. + * * uri, which the basename of the uri with which the calendar is + * accessed. + * * principalUri. The owner of the calendar. Almost always the same as + * principalUri passed to this method. + * + * Furthermore it can contain webdav properties in clark notation. A very + * common one is '{DAV:}displayname'. + * + * @param string $principalUri + * @return array + */ + function getCalendarsForUser($principalUri) { + + $calendars = parent::getCalendarsForUser($principalUri); + foreach ($calendars as $k => $calendar) { + + if (isset($calendar['share-access'])) { + continue; + } + if (!empty($this->shares[$calendar['id']])) { + $calendar['share-access'] = DAV\Sharing\Plugin::ACCESS_SHAREDOWNER; + } else { + $calendar['share-access'] = DAV\Sharing\Plugin::ACCESS_NOTSHARED; + } + $calendars[$k] = $calendar; + + } + return $calendars; + + } + + /** + * Returns a list of notifications for a given principal url. + * + * The returned array should only consist of implementations of + * Sabre\CalDAV\Notifications\INotificationType. + * + * @param string $principalUri + * @return array + */ + function getNotificationsForPrincipal($principalUri) { + + if (isset($this->notifications[$principalUri])) { + return $this->notifications[$principalUri]; + } + return []; + + } + + /** + * This deletes a specific notifcation. + * + * This may be called by a client once it deems a notification handled. + * + * @param string $principalUri + * @param NotificationInterface $notification + * @return void + */ + function deleteNotification($principalUri, NotificationInterface $notification) { + + foreach ($this->notifications[$principalUri] as $key => $value) { + if ($notification === $value) { + unset($this->notifications[$principalUri][$key]); + } + } + + } + + /** + * Updates the list of shares. + * + * @param mixed $calendarId + * @param \Sabre\DAV\Xml\Element\Sharee[] $sharees + * @return void + */ + function updateInvites($calendarId, array $sharees) { + + if (!isset($this->shares[$calendarId])) { + $this->shares[$calendarId] = []; + } + + foreach ($sharees as $sharee) { + + $existingKey = null; + foreach ($this->shares[$calendarId] as $k => $existingSharee) { + if ($sharee->href === $existingSharee->href) { + $existingKey = $k; + } + } + // Just making sure we're not affecting an existing copy. + $sharee = clone $sharee; + $sharee->inviteStatus = DAV\Sharing\Plugin::INVITE_NORESPONSE; + + if ($sharee->access === DAV\Sharing\Plugin::ACCESS_NOACCESS) { + // It's a removal + unset($this->shares[$calendarId][$existingKey]); + } elseif ($existingKey) { + // It's an update + $this->shares[$calendarId][$existingKey] = $sharee; + } else { + // It's an addition + $this->shares[$calendarId][] = $sharee; + } + } + + // Re-numbering keys + $this->shares[$calendarId] = array_values($this->shares[$calendarId]); + + } + + /** + * Returns the list of people whom this calendar is shared with. + * + * Every item in the returned list must be a Sharee object with at + * least the following properties set: + * $href + * $shareAccess + * $inviteStatus + * + * and optionally: + * $properties + * + * @param mixed $calendarId + * @return \Sabre\DAV\Xml\Element\Sharee[] + */ + function getInvites($calendarId) { + + if (!isset($this->shares[$calendarId])) { + return []; + } + + return $this->shares[$calendarId]; + + } + + /** + * This method is called when a user replied to a request to share. + * + * @param string href The sharee who is replying (often a mailto: address) + * @param int status One of the \Sabre\DAV\Sharing\Plugin::INVITE_* constants + * @param string $calendarUri The url to the calendar thats being shared + * @param string $inReplyTo The unique id this message is a response to + * @param string $summary A description of the reply + * @return void + */ + function shareReply($href, $status, $calendarUri, $inReplyTo, $summary = null) { + + // This operation basically doesn't do anything yet + if ($status === DAV\Sharing\Plugin::INVITE_ACCEPTED) { + return 'calendars/blabla/calendar'; + } + + } + + /** + * Publishes a calendar + * + * @param mixed $calendarId + * @param bool $value + * @return void + */ + function setPublishStatus($calendarId, $value) { + + foreach ($this->calendars as $k => $cal) { + if ($cal['id'] === $calendarId) { + if (!$value) { + unset($cal['{http://calendarserver.org/ns/}publish-url']); + } else { + $cal['{http://calendarserver.org/ns/}publish-url'] = 'http://example.org/public/ ' . $calendarId . '.ics'; + } + return; + } + } + + throw new DAV\Exception('Calendar with id "' . $calendarId . '" not found'); + + } + +} diff --git a/vendor/sabre/dav/tests/Sabre/CalDAV/Backend/MockSubscriptionSupport.php b/vendor/sabre/dav/tests/Sabre/CalDAV/Backend/MockSubscriptionSupport.php new file mode 100644 index 000000000..adf9c8a17 --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/CalDAV/Backend/MockSubscriptionSupport.php @@ -0,0 +1,156 @@ +subs[$principalUri])) { + return $this->subs[$principalUri]; + } + return []; + + } + + /** + * Creates a new subscription for a principal. + * + * If the creation was a success, an id must be returned that can be used to reference + * this subscription in other methods, such as updateSubscription. + * + * @param string $principalUri + * @param string $uri + * @param array $properties + * @return mixed + */ + function createSubscription($principalUri, $uri, array $properties) { + + $properties['uri'] = $uri; + $properties['principaluri'] = $principalUri; + $properties['source'] = $properties['{http://calendarserver.org/ns/}source']->getHref(); + + if (!isset($this->subs[$principalUri])) { + $this->subs[$principalUri] = []; + } + + $id = [$principalUri, count($this->subs[$principalUri]) + 1]; + + $properties['id'] = $id; + + $this->subs[$principalUri][] = array_merge($properties, [ + 'id' => $id, + ]); + + return $id; + + } + + /** + * Updates a subscription + * + * The list of mutations is stored in a Sabre\DAV\PropPatch object. + * To do the actual updates, you must tell this object which properties + * you're going to process with the handle() method. + * + * Calling the handle method is like telling the PropPatch object "I + * promise I can handle updating this property". + * + * Read the PropPatch documentation for more info and examples. + * + * @param mixed $subscriptionId + * @param \Sabre\DAV\PropPatch $propPatch + * @return void + */ + function updateSubscription($subscriptionId, DAV\PropPatch $propPatch) { + + $found = null; + foreach ($this->subs[$subscriptionId[0]] as &$sub) { + + if ($sub['id'][1] === $subscriptionId[1]) { + $found = & $sub; + break; + } + + } + + if (!$found) return; + + $propPatch->handleRemaining(function($mutations) use (&$found) { + foreach ($mutations as $k => $v) { + $found[$k] = $v; + } + return true; + }); + + } + + /** + * Deletes a subscription + * + * @param mixed $subscriptionId + * @return void + */ + function deleteSubscription($subscriptionId) { + + foreach ($this->subs[$subscriptionId[0]] as $index => $sub) { + + if ($sub['id'][1] === $subscriptionId[1]) { + unset($this->subs[$subscriptionId[0]][$index]); + return true; + } + + } + + return false; + + } + +} diff --git a/vendor/sabre/dav/tests/Sabre/CalDAV/Backend/PDOMySQLTest.php b/vendor/sabre/dav/tests/Sabre/CalDAV/Backend/PDOMySQLTest.php new file mode 100644 index 000000000..e068ff1e7 --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/CalDAV/Backend/PDOMySQLTest.php @@ -0,0 +1,9 @@ +markTestSkipped('SQLite driver is not available'); + + if (file_exists(SABRE_TEMPDIR . '/testdb.sqlite')) + unlink(SABRE_TEMPDIR . '/testdb.sqlite'); + + $pdo = new \PDO('sqlite:' . SABRE_TEMPDIR . '/testdb.sqlite'); + $pdo->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION); + + $pdo->exec(<<exec(<<pdo = $pdo; + + } + + function testConstruct() { + + $backend = new SimplePDO($this->pdo); + $this->assertTrue($backend instanceof SimplePDO); + + } + + /** + * @depends testConstruct + */ + function testGetCalendarsForUserNoCalendars() { + + $backend = new SimplePDO($this->pdo); + $calendars = $backend->getCalendarsForUser('principals/user2'); + $this->assertEquals([], $calendars); + + } + + /** + * @depends testConstruct + */ + function testCreateCalendarAndFetch() { + + $backend = new SimplePDO($this->pdo); + $returnedId = $backend->createCalendar('principals/user2', 'somerandomid', [ + '{urn:ietf:params:xml:ns:caldav}supported-calendar-component-set' => new CalDAV\Xml\Property\SupportedCalendarComponentSet(['VEVENT']), + '{DAV:}displayname' => 'Hello!', + '{urn:ietf:params:xml:ns:caldav}schedule-calendar-transp' => new CalDAV\Xml\Property\ScheduleCalendarTransp('transparent'), + ]); + $calendars = $backend->getCalendarsForUser('principals/user2'); + + $elementCheck = [ + 'uri' => 'somerandomid', + ]; + + $this->assertInternalType('array', $calendars); + $this->assertEquals(1, count($calendars)); + + foreach ($elementCheck as $name => $value) { + + $this->assertArrayHasKey($name, $calendars[0]); + $this->assertEquals($value, $calendars[0][$name]); + + } + + } + + /** + * @depends testConstruct + */ + function testUpdateCalendarAndFetch() { + + $backend = new SimplePDO($this->pdo); + + //Creating a new calendar + $newId = $backend->createCalendar('principals/user2', 'somerandomid', []); + + $propPatch = new PropPatch([ + '{DAV:}displayname' => 'myCalendar', + '{urn:ietf:params:xml:ns:caldav}schedule-calendar-transp' => new CalDAV\Xml\Property\ScheduleCalendarTransp('transparent'), + ]); + + // Updating the calendar + $backend->updateCalendar($newId, $propPatch); + $result = $propPatch->commit(); + + // Verifying the result of the update + $this->assertFalse($result); + + } + + /** + * @depends testCreateCalendarAndFetch + */ + function testDeleteCalendar() { + + $backend = new SimplePDO($this->pdo); + $returnedId = $backend->createCalendar('principals/user2', 'somerandomid', [ + '{urn:ietf:params:xml:ns:caldav}supported-calendar-component-set' => new CalDAV\Xml\Property\SupportedCalendarComponentSet(['VEVENT']), + '{DAV:}displayname' => 'Hello!', + ]); + + $backend->deleteCalendar($returnedId); + + $calendars = $backend->getCalendarsForUser('principals/user2'); + $this->assertEquals([], $calendars); + + } + + function testCreateCalendarObject() { + + $backend = new SimplePDO($this->pdo); + $returnedId = $backend->createCalendar('principals/user2', 'somerandomid', []); + + $object = "BEGIN:VCALENDAR\r\nBEGIN:VEVENT\r\nDTSTART;VALUE=DATE:20120101\r\nEND:VEVENT\r\nEND:VCALENDAR\r\n"; + + $backend->createCalendarObject($returnedId, 'random-id', $object); + + $result = $this->pdo->query('SELECT calendardata FROM simple_calendarobjects WHERE uri = "random-id"'); + $this->assertEquals([ + 'calendardata' => $object, + ], $result->fetch(\PDO::FETCH_ASSOC)); + + } + function testGetMultipleObjects() { + + $backend = new SimplePDO($this->pdo); + $returnedId = $backend->createCalendar('principals/user2', 'somerandomid', []); + + $object = "BEGIN:VCALENDAR\r\nBEGIN:VEVENT\r\nDTSTART;VALUE=DATE:20120101\r\nEND:VEVENT\r\nEND:VCALENDAR\r\n"; + + $backend->createCalendarObject($returnedId, 'id-1', $object); + $backend->createCalendarObject($returnedId, 'id-2', $object); + + $check = [ + [ + 'id' => 1, + 'etag' => '"' . md5($object) . '"', + 'uri' => 'id-1', + 'size' => strlen($object), + 'calendardata' => $object, + ], + [ + 'id' => 2, + 'etag' => '"' . md5($object) . '"', + 'uri' => 'id-2', + 'size' => strlen($object), + 'calendardata' => $object, + ], + ]; + + $result = $backend->getMultipleCalendarObjects($returnedId, ['id-1', 'id-2']); + + foreach ($check as $index => $props) { + + foreach ($props as $key => $value) { + + if ($key !== 'lastmodified') { + $this->assertEquals($value, $result[$index][$key]); + } else { + $this->assertTrue(isset($result[$index][$key])); + } + + } + + } + + } + + /** + * @depends testCreateCalendarObject + */ + function testGetCalendarObjects() { + + $backend = new SimplePDO($this->pdo); + $returnedId = $backend->createCalendar('principals/user2', 'somerandomid', []); + + $object = "BEGIN:VCALENDAR\r\nBEGIN:VEVENT\r\nDTSTART;VALUE=DATE:20120101\r\nEND:VEVENT\r\nEND:VCALENDAR\r\n"; + $backend->createCalendarObject($returnedId, 'random-id', $object); + + $data = $backend->getCalendarObjects($returnedId); + + $this->assertEquals(1, count($data)); + $data = $data[0]; + + $this->assertEquals('random-id', $data['uri']); + $this->assertEquals(strlen($object), $data['size']); + + } + + /** + * @depends testCreateCalendarObject + */ + function testGetCalendarObjectByUID() { + + $backend = new SimplePDO($this->pdo); + $returnedId = $backend->createCalendar('principals/user2', 'somerandomid', []); + + $object = "BEGIN:VCALENDAR\r\nBEGIN:VEVENT\r\nUID:foo\r\nDTSTART;VALUE=DATE:20120101\r\nEND:VEVENT\r\nEND:VCALENDAR\r\n"; + $backend->createCalendarObject($returnedId, 'random-id', $object); + + $this->assertNull( + $backend->getCalendarObjectByUID('principals/user2', 'bar') + ); + $this->assertEquals( + 'somerandomid/random-id', + $backend->getCalendarObjectByUID('principals/user2', 'foo') + ); + + } + + /** + * @depends testCreateCalendarObject + */ + function testUpdateCalendarObject() { + + $backend = new SimplePDO($this->pdo); + $returnedId = $backend->createCalendar('principals/user2', 'somerandomid', []); + + $object = "BEGIN:VCALENDAR\r\nBEGIN:VEVENT\r\nDTSTART;VALUE=DATE:20120101\r\nEND:VEVENT\r\nEND:VCALENDAR\r\n"; + $object2 = "BEGIN:VCALENDAR\r\nBEGIN:VEVENT\r\nDTSTART;VALUE=DATE:20130101\r\nEND:VEVENT\r\nEND:VCALENDAR\r\n"; + $backend->createCalendarObject($returnedId, 'random-id', $object); + $backend->updateCalendarObject($returnedId, 'random-id', $object2); + + $data = $backend->getCalendarObject($returnedId, 'random-id'); + + $this->assertEquals($object2, $data['calendardata']); + $this->assertEquals('random-id', $data['uri']); + + + } + + + /** + * @depends testCreateCalendarObject + */ + function testDeleteCalendarObject() { + + $backend = new SimplePDO($this->pdo); + $returnedId = $backend->createCalendar('principals/user2', 'somerandomid', []); + + $object = "BEGIN:VCALENDAR\r\nBEGIN:VEVENT\r\nDTSTART;VALUE=DATE:20120101\r\nEND:VEVENT\r\nEND:VCALENDAR\r\n"; + $backend->createCalendarObject($returnedId, 'random-id', $object); + $backend->deleteCalendarObject($returnedId, 'random-id'); + + $data = $backend->getCalendarObject($returnedId, 'random-id'); + $this->assertNull($data); + + } + + + function testCalendarQueryNoResult() { + + $abstract = new SimplePDO($this->pdo); + $filters = [ + 'name' => 'VCALENDAR', + 'comp-filters' => [ + [ + 'name' => 'VJOURNAL', + 'comp-filters' => [], + 'prop-filters' => [], + 'is-not-defined' => false, + 'time-range' => null, + ], + ], + 'prop-filters' => [], + 'is-not-defined' => false, + 'time-range' => null, + ]; + + $this->assertEquals([ + ], $abstract->calendarQuery(1, $filters)); + + } + + function testCalendarQueryTodo() { + + $backend = new SimplePDO($this->pdo); + $backend->createCalendarObject(1, "todo", "BEGIN:VCALENDAR\r\nBEGIN:VTODO\r\nEND:VTODO\r\nEND:VCALENDAR\r\n"); + $backend->createCalendarObject(1, "event", "BEGIN:VCALENDAR\r\nBEGIN:VEVENT\r\nDTSTART:20120101\r\nEND:VEVENT\r\nEND:VCALENDAR\r\n"); + + $filters = [ + 'name' => 'VCALENDAR', + 'comp-filters' => [ + [ + 'name' => 'VTODO', + 'comp-filters' => [], + 'prop-filters' => [], + 'is-not-defined' => false, + 'time-range' => null, + ], + ], + 'prop-filters' => [], + 'is-not-defined' => false, + 'time-range' => null, + ]; + + $this->assertEquals([ + "todo", + ], $backend->calendarQuery(1, $filters)); + + } + function testCalendarQueryTodoNotMatch() { + + $backend = new SimplePDO($this->pdo); + $backend->createCalendarObject(1, "todo", "BEGIN:VCALENDAR\r\nBEGIN:VTODO\r\nEND:VTODO\r\nEND:VCALENDAR\r\n"); + $backend->createCalendarObject(1, "event", "BEGIN:VCALENDAR\r\nBEGIN:VEVENT\r\nDTSTART:20120101\r\nEND:VEVENT\r\nEND:VCALENDAR\r\n"); + + $filters = [ + 'name' => 'VCALENDAR', + 'comp-filters' => [ + [ + 'name' => 'VTODO', + 'comp-filters' => [], + 'prop-filters' => [ + [ + 'name' => 'summary', + 'text-match' => null, + 'time-range' => null, + 'param-filters' => [], + 'is-not-defined' => false, + ], + ], + 'is-not-defined' => false, + 'time-range' => null, + ], + ], + 'prop-filters' => [], + 'is-not-defined' => false, + 'time-range' => null, + ]; + + $this->assertEquals([ + ], $backend->calendarQuery(1, $filters)); + + } + + function testCalendarQueryNoFilter() { + + $backend = new SimplePDO($this->pdo); + $backend->createCalendarObject(1, "todo", "BEGIN:VCALENDAR\r\nBEGIN:VTODO\r\nEND:VTODO\r\nEND:VCALENDAR\r\n"); + $backend->createCalendarObject(1, "event", "BEGIN:VCALENDAR\r\nBEGIN:VEVENT\r\nDTSTART:20120101\r\nEND:VEVENT\r\nEND:VCALENDAR\r\n"); + + $filters = [ + 'name' => 'VCALENDAR', + 'comp-filters' => [], + 'prop-filters' => [], + 'is-not-defined' => false, + 'time-range' => null, + ]; + + $result = $backend->calendarQuery(1, $filters); + $this->assertTrue(in_array('todo', $result)); + $this->assertTrue(in_array('event', $result)); + + } + + function testCalendarQueryTimeRange() { + + $backend = new SimplePDO($this->pdo); + $backend->createCalendarObject(1, "todo", "BEGIN:VCALENDAR\r\nBEGIN:VTODO\r\nEND:VTODO\r\nEND:VCALENDAR\r\n"); + $backend->createCalendarObject(1, "event", "BEGIN:VCALENDAR\r\nBEGIN:VEVENT\r\nDTSTART;VALUE=DATE:20120101\r\nEND:VEVENT\r\nEND:VCALENDAR\r\n"); + $backend->createCalendarObject(1, "event2", "BEGIN:VCALENDAR\r\nBEGIN:VEVENT\r\nDTSTART;VALUE=DATE:20120103\r\nEND:VEVENT\r\nEND:VCALENDAR\r\n"); + + $filters = [ + 'name' => 'VCALENDAR', + 'comp-filters' => [ + [ + 'name' => 'VEVENT', + 'comp-filters' => [], + 'prop-filters' => [], + 'is-not-defined' => false, + 'time-range' => [ + 'start' => new \DateTime('20120103'), + 'end' => new \DateTime('20120104'), + ], + ], + ], + 'prop-filters' => [], + 'is-not-defined' => false, + 'time-range' => null, + ]; + + $this->assertEquals([ + "event2", + ], $backend->calendarQuery(1, $filters)); + + } + function testCalendarQueryTimeRangeNoEnd() { + + $backend = new SimplePDO($this->pdo); + $backend->createCalendarObject(1, "todo", "BEGIN:VCALENDAR\r\nBEGIN:VTODO\r\nEND:VTODO\r\nEND:VCALENDAR\r\n"); + $backend->createCalendarObject(1, "event", "BEGIN:VCALENDAR\r\nBEGIN:VEVENT\r\nDTSTART:20120101\r\nEND:VEVENT\r\nEND:VCALENDAR\r\n"); + $backend->createCalendarObject(1, "event2", "BEGIN:VCALENDAR\r\nBEGIN:VEVENT\r\nDTSTART:20120103\r\nEND:VEVENT\r\nEND:VCALENDAR\r\n"); + + $filters = [ + 'name' => 'VCALENDAR', + 'comp-filters' => [ + [ + 'name' => 'VEVENT', + 'comp-filters' => [], + 'prop-filters' => [], + 'is-not-defined' => false, + 'time-range' => [ + 'start' => new \DateTime('20120102'), + 'end' => null, + ], + ], + ], + 'prop-filters' => [], + 'is-not-defined' => false, + 'time-range' => null, + ]; + + $this->assertEquals([ + "event2", + ], $backend->calendarQuery(1, $filters)); + + } + +} diff --git a/vendor/sabre/dav/tests/Sabre/CalDAV/CalendarHomeNotificationsTest.php b/vendor/sabre/dav/tests/Sabre/CalDAV/CalendarHomeNotificationsTest.php new file mode 100644 index 000000000..36302cc35 --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/CalDAV/CalendarHomeNotificationsTest.php @@ -0,0 +1,49 @@ + 'principals/user']); + + $this->assertEquals( + [], + $calendarHome->getChildren() + ); + + } + + /** + * @expectedException \Sabre\DAV\Exception\NotFound + */ + function testGetChildNoSupport() { + + $backend = new Backend\Mock(); + $calendarHome = new CalendarHome($backend, ['uri' => 'principals/user']); + $calendarHome->getChild('notifications'); + + } + + function testGetChildren() { + + $backend = new Backend\MockSharing(); + $calendarHome = new CalendarHome($backend, ['uri' => 'principals/user']); + + $result = $calendarHome->getChildren(); + $this->assertEquals('notifications', $result[0]->getName()); + + } + + function testGetChild() { + + $backend = new Backend\MockSharing(); + $calendarHome = new CalendarHome($backend, ['uri' => 'principals/user']); + $result = $calendarHome->getChild('notifications'); + $this->assertEquals('notifications', $result->getName()); + + } + +} diff --git a/vendor/sabre/dav/tests/Sabre/CalDAV/CalendarHomeSharedCalendarsTest.php b/vendor/sabre/dav/tests/Sabre/CalDAV/CalendarHomeSharedCalendarsTest.php new file mode 100644 index 000000000..9079fdecd --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/CalDAV/CalendarHomeSharedCalendarsTest.php @@ -0,0 +1,80 @@ + 1, + 'principaluri' => 'principals/user1', + ], + [ + 'id' => 2, + '{http://calendarserver.org/ns/}shared-url' => 'calendars/owner/cal1', + '{http://sabredav.org/ns}owner-principal' => 'principal/owner', + '{http://sabredav.org/ns}read-only' => false, + 'principaluri' => 'principals/user1', + ], + ]; + + $this->backend = new Backend\MockSharing( + $calendars, + [], + [] + ); + + return new CalendarHome($this->backend, [ + 'uri' => 'principals/user1' + ]); + + } + + function testSimple() { + + $instance = $this->getInstance(); + $this->assertEquals('user1', $instance->getName()); + + } + + function testGetChildren() { + + $instance = $this->getInstance(); + $children = $instance->getChildren(); + $this->assertEquals(3, count($children)); + + // Testing if we got all the objects back. + $sharedCalendars = 0; + $hasOutbox = false; + $hasNotifications = false; + + foreach ($children as $child) { + + if ($child instanceof ISharedCalendar) { + $sharedCalendars++; + } + if ($child instanceof Notifications\ICollection) { + $hasNotifications = true; + } + + } + $this->assertEquals(2, $sharedCalendars); + $this->assertTrue($hasNotifications); + + } + + function testShareReply() { + + $instance = $this->getInstance(); + $result = $instance->shareReply('uri', DAV\Sharing\Plugin::INVITE_DECLINED, 'curi', '1'); + $this->assertNull($result); + + } + +} diff --git a/vendor/sabre/dav/tests/Sabre/CalDAV/CalendarHomeSubscriptionsTest.php b/vendor/sabre/dav/tests/Sabre/CalDAV/CalendarHomeSubscriptionsTest.php new file mode 100644 index 000000000..4a479c816 --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/CalDAV/CalendarHomeSubscriptionsTest.php @@ -0,0 +1,85 @@ + 'baz', + '{http://calendarserver.org/ns/}source' => new \Sabre\DAV\Xml\Property\Href('http://example.org/test.ics'), + ]; + $principal = [ + 'uri' => 'principals/user1' + ]; + $this->backend = new Backend\MockSubscriptionSupport([], []); + $this->backend->createSubscription('principals/user1', 'uri', $props); + + return new CalendarHome($this->backend, $principal); + + } + + function testSimple() { + + $instance = $this->getInstance(); + $this->assertEquals('user1', $instance->getName()); + + } + + function testGetChildren() { + + $instance = $this->getInstance(); + $children = $instance->getChildren(); + $this->assertEquals(1, count($children)); + foreach ($children as $child) { + if ($child instanceof Subscriptions\Subscription) { + return; + } + } + $this->fail('There were no subscription nodes in the calendar home'); + + } + + function testCreateSubscription() { + + $instance = $this->getInstance(); + $rt = ['{DAV:}collection', '{http://calendarserver.org/ns/}subscribed']; + + $props = [ + '{DAV:}displayname' => 'baz', + '{http://calendarserver.org/ns/}source' => new \Sabre\DAV\Xml\Property\Href('http://example.org/test2.ics'), + ]; + $instance->createExtendedCollection('sub2', new MkCol($rt, $props)); + + $children = $instance->getChildren(); + $this->assertEquals(2, count($children)); + + } + + /** + * @expectedException \Sabre\DAV\Exception\InvalidResourceType + */ + function testNoSubscriptionSupport() { + + $principal = [ + 'uri' => 'principals/user1' + ]; + $backend = new Backend\Mock([], []); + $uC = new CalendarHome($backend, $principal); + + $rt = ['{DAV:}collection', '{http://calendarserver.org/ns/}subscribed']; + + $props = [ + '{DAV:}displayname' => 'baz', + '{http://calendarserver.org/ns/}source' => new \Sabre\DAV\Xml\Property\Href('http://example.org/test2.ics'), + ]; + $uC->createExtendedCollection('sub2', new MkCol($rt, $props)); + + } + +} diff --git a/vendor/sabre/dav/tests/Sabre/CalDAV/CalendarHomeTest.php b/vendor/sabre/dav/tests/Sabre/CalDAV/CalendarHomeTest.php new file mode 100644 index 000000000..ff52ea6ad --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/CalDAV/CalendarHomeTest.php @@ -0,0 +1,215 @@ +backend = TestUtil::getBackend(); + $this->usercalendars = new CalendarHome($this->backend, [ + 'uri' => 'principals/user1' + ]); + + } + + function testSimple() { + + $this->assertEquals('user1', $this->usercalendars->getName()); + + } + + /** + * @expectedException Sabre\DAV\Exception\NotFound + * @depends testSimple + */ + function testGetChildNotFound() { + + $this->usercalendars->getChild('randomname'); + + } + + function testChildExists() { + + $this->assertFalse($this->usercalendars->childExists('foo')); + $this->assertTrue($this->usercalendars->childExists('UUID-123467')); + + } + + function testGetOwner() { + + $this->assertEquals('principals/user1', $this->usercalendars->getOwner()); + + } + + function testGetGroup() { + + $this->assertNull($this->usercalendars->getGroup()); + + } + + function testGetACL() { + + $expected = [ + [ + 'privilege' => '{DAV:}read', + 'principal' => 'principals/user1', + 'protected' => true, + ], + [ + 'privilege' => '{DAV:}write', + 'principal' => 'principals/user1', + 'protected' => true, + ], + [ + 'privilege' => '{DAV:}read', + 'principal' => 'principals/user1/calendar-proxy-write', + 'protected' => true, + ], + [ + 'privilege' => '{DAV:}write', + 'principal' => 'principals/user1/calendar-proxy-write', + 'protected' => true, + ], + [ + 'privilege' => '{DAV:}read', + 'principal' => 'principals/user1/calendar-proxy-read', + 'protected' => true, + ], + ]; + $this->assertEquals($expected, $this->usercalendars->getACL()); + + } + + /** + * @expectedException \Sabre\DAV\Exception\Forbidden + */ + function testSetACL() { + + $this->usercalendars->setACL([]); + + } + + /** + * @expectedException \Sabre\DAV\Exception\Forbidden + * @depends testSimple + */ + function testSetName() { + + $this->usercalendars->setName('bla'); + + } + + /** + * @expectedException \Sabre\DAV\Exception\Forbidden + * @depends testSimple + */ + function testDelete() { + + $this->usercalendars->delete(); + + } + + /** + * @depends testSimple + */ + function testGetLastModified() { + + $this->assertNull($this->usercalendars->getLastModified()); + + } + + /** + * @expectedException \Sabre\DAV\Exception\MethodNotAllowed + * @depends testSimple + */ + function testCreateFile() { + + $this->usercalendars->createFile('bla'); + + } + + + /** + * @expectedException Sabre\DAV\Exception\MethodNotAllowed + * @depends testSimple + */ + function testCreateDirectory() { + + $this->usercalendars->createDirectory('bla'); + + } + + /** + * @depends testSimple + */ + function testCreateExtendedCollection() { + + $mkCol = new MkCol( + ['{DAV:}collection', '{urn:ietf:params:xml:ns:caldav}calendar'], + [] + ); + $result = $this->usercalendars->createExtendedCollection('newcalendar', $mkCol); + $this->assertNull($result); + $cals = $this->backend->getCalendarsForUser('principals/user1'); + $this->assertEquals(3, count($cals)); + + } + + /** + * @expectedException Sabre\DAV\Exception\InvalidResourceType + * @depends testSimple + */ + function testCreateExtendedCollectionBadResourceType() { + + $mkCol = new MkCol( + ['{DAV:}collection', '{DAV:}blabla'], + [] + ); + $this->usercalendars->createExtendedCollection('newcalendar', $mkCol); + + } + + /** + * @expectedException Sabre\DAV\Exception\InvalidResourceType + * @depends testSimple + */ + function testCreateExtendedCollectionNotACalendar() { + + $mkCol = new MkCol( + ['{DAV:}collection'], + [] + ); + $this->usercalendars->createExtendedCollection('newcalendar', $mkCol); + + } + + function testGetSupportedPrivilegesSet() { + + $this->assertNull($this->usercalendars->getSupportedPrivilegeSet()); + + } + + /** + * @expectedException Sabre\DAV\Exception\NotImplemented + */ + function testShareReplyFail() { + + $this->usercalendars->shareReply('uri', DAV\Sharing\Plugin::INVITE_DECLINED, 'curi', '1'); + + } + +} diff --git a/vendor/sabre/dav/tests/Sabre/CalDAV/CalendarObjectTest.php b/vendor/sabre/dav/tests/Sabre/CalDAV/CalendarObjectTest.php new file mode 100644 index 000000000..c92cde661 --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/CalDAV/CalendarObjectTest.php @@ -0,0 +1,383 @@ +backend = TestUtil::getBackend(); + + $calendars = $this->backend->getCalendarsForUser('principals/user1'); + $this->assertEquals(2, count($calendars)); + $this->calendar = new Calendar($this->backend, $calendars[0]); + + } + + function teardown() { + + unset($this->calendar); + unset($this->backend); + + } + + function testSetup() { + + $children = $this->calendar->getChildren(); + $this->assertTrue($children[0] instanceof CalendarObject); + + $this->assertInternalType('string', $children[0]->getName()); + $this->assertInternalType('string', $children[0]->get()); + $this->assertInternalType('string', $children[0]->getETag()); + $this->assertEquals('text/calendar; charset=utf-8', $children[0]->getContentType()); + + } + + /** + * @expectedException InvalidArgumentException + */ + function testInvalidArg1() { + + $obj = new CalendarObject( + new Backend\Mock([], []), + [], + [] + ); + + } + + /** + * @expectedException InvalidArgumentException + */ + function testInvalidArg2() { + + $obj = new CalendarObject( + new Backend\Mock([], []), + [], + ['calendarid' => '1'] + ); + + } + + /** + * @depends testSetup + */ + function testPut() { + + $children = $this->calendar->getChildren(); + $this->assertTrue($children[0] instanceof CalendarObject); + $newData = TestUtil::getTestCalendarData(); + + $children[0]->put($newData); + $this->assertEquals($newData, $children[0]->get()); + + } + + /** + * @depends testSetup + */ + function testPutStream() { + + $children = $this->calendar->getChildren(); + $this->assertTrue($children[0] instanceof CalendarObject); + $newData = TestUtil::getTestCalendarData(); + + $stream = fopen('php://temp', 'r+'); + fwrite($stream, $newData); + rewind($stream); + $children[0]->put($stream); + $this->assertEquals($newData, $children[0]->get()); + + } + + + /** + * @depends testSetup + */ + function testDelete() { + + $children = $this->calendar->getChildren(); + $this->assertTrue($children[0] instanceof CalendarObject); + + $obj = $children[0]; + $obj->delete(); + + $children2 = $this->calendar->getChildren(); + $this->assertEquals(count($children) - 1, count($children2)); + + } + + /** + * @depends testSetup + */ + function testGetLastModified() { + + $children = $this->calendar->getChildren(); + $this->assertTrue($children[0] instanceof CalendarObject); + + $obj = $children[0]; + + $lastMod = $obj->getLastModified(); + $this->assertTrue(is_int($lastMod) || ctype_digit($lastMod) || is_null($lastMod)); + + } + + /** + * @depends testSetup + */ + function testGetSize() { + + $children = $this->calendar->getChildren(); + $this->assertTrue($children[0] instanceof CalendarObject); + + $obj = $children[0]; + + $size = $obj->getSize(); + $this->assertInternalType('int', $size); + + } + + function testGetOwner() { + + $children = $this->calendar->getChildren(); + $this->assertTrue($children[0] instanceof CalendarObject); + + $obj = $children[0]; + $this->assertEquals('principals/user1', $obj->getOwner()); + + } + + function testGetGroup() { + + $children = $this->calendar->getChildren(); + $this->assertTrue($children[0] instanceof CalendarObject); + + $obj = $children[0]; + $this->assertNull($obj->getGroup()); + + } + + function testGetACL() { + + $expected = [ + [ + 'privilege' => '{DAV:}read', + 'principal' => 'principals/user1', + 'protected' => true, + ], + [ + 'privilege' => '{DAV:}read', + 'principal' => 'principals/user1/calendar-proxy-write', + 'protected' => true, + ], + [ + 'privilege' => '{DAV:}read', + 'principal' => 'principals/user1/calendar-proxy-read', + 'protected' => true, + ], + [ + 'privilege' => '{DAV:}write', + 'principal' => 'principals/user1', + 'protected' => true, + ], + [ + 'privilege' => '{DAV:}write', + 'principal' => 'principals/user1/calendar-proxy-write', + 'protected' => true, + ], + ]; + + $children = $this->calendar->getChildren(); + $this->assertTrue($children[0] instanceof CalendarObject); + + $obj = $children[0]; + $this->assertEquals($expected, $obj->getACL()); + + } + + function testDefaultACL() { + + $backend = new Backend\Mock([], []); + $calendarObject = new CalendarObject($backend, ['principaluri' => 'principals/user1'], ['calendarid' => 1, 'uri' => 'foo']); + $expected = [ + [ + 'privilege' => '{DAV:}all', + 'principal' => 'principals/user1', + 'protected' => true, + ], + [ + 'privilege' => '{DAV:}all', + 'principal' => 'principals/user1/calendar-proxy-write', + 'protected' => true, + ], + [ + 'privilege' => '{DAV:}read', + 'principal' => 'principals/user1/calendar-proxy-read', + 'protected' => true, + ], + ]; + $this->assertEquals($expected, $calendarObject->getACL()); + + + } + + /** + * @expectedException \Sabre\DAV\Exception\Forbidden + */ + function testSetACL() { + + $children = $this->calendar->getChildren(); + $this->assertTrue($children[0] instanceof CalendarObject); + + $obj = $children[0]; + $obj->setACL([]); + + } + + function testGet() { + + $children = $this->calendar->getChildren(); + $this->assertTrue($children[0] instanceof CalendarObject); + + $obj = $children[0]; + + $expected = "BEGIN:VCALENDAR +VERSION:2.0 +PRODID:-//Apple Inc.//iCal 4.0.1//EN +CALSCALE:GREGORIAN +BEGIN:VTIMEZONE +TZID:Asia/Seoul +BEGIN:DAYLIGHT +TZOFFSETFROM:+0900 +RRULE:FREQ=YEARLY;UNTIL=19880507T150000Z;BYMONTH=5;BYDAY=2SU +DTSTART:19870510T000000 +TZNAME:GMT+09:00 +TZOFFSETTO:+1000 +END:DAYLIGHT +BEGIN:STANDARD +TZOFFSETFROM:+1000 +DTSTART:19881009T000000 +TZNAME:GMT+09:00 +TZOFFSETTO:+0900 +END:STANDARD +END:VTIMEZONE +BEGIN:VEVENT +CREATED:20100225T154229Z +UID:39A6B5ED-DD51-4AFE-A683-C35EE3749627 +TRANSP:TRANSPARENT +SUMMARY:Something here +DTSTAMP:20100228T130202Z +DTSTART;TZID=Asia/Seoul:20100223T060000 +DTEND;TZID=Asia/Seoul:20100223T070000 +ATTENDEE;PARTSTAT=NEEDS-ACTION:mailto:lisa@example.com +SEQUENCE:2 +END:VEVENT +END:VCALENDAR"; + + + + $this->assertEquals($expected, $obj->get()); + + } + + function testGetRefetch() { + + $backend = new Backend\Mock([], [ + 1 => [ + 'foo' => [ + 'calendardata' => 'foo', + 'uri' => 'foo' + ], + ] + ]); + $obj = new CalendarObject($backend, ['id' => 1], ['uri' => 'foo']); + + $this->assertEquals('foo', $obj->get()); + + } + + function testGetEtag1() { + + $objectInfo = [ + 'calendardata' => 'foo', + 'uri' => 'foo', + 'etag' => 'bar', + 'calendarid' => 1 + ]; + + $backend = new Backend\Mock([], []); + $obj = new CalendarObject($backend, [], $objectInfo); + + $this->assertEquals('bar', $obj->getETag()); + + } + + function testGetEtag2() { + + $objectInfo = [ + 'calendardata' => 'foo', + 'uri' => 'foo', + 'calendarid' => 1 + ]; + + $backend = new Backend\Mock([], []); + $obj = new CalendarObject($backend, [], $objectInfo); + + $this->assertEquals('"' . md5('foo') . '"', $obj->getETag()); + + } + + function testGetSupportedPrivilegesSet() { + + $objectInfo = [ + 'calendardata' => 'foo', + 'uri' => 'foo', + 'calendarid' => 1 + ]; + + $backend = new Backend\Mock([], []); + $obj = new CalendarObject($backend, [], $objectInfo); + $this->assertNull($obj->getSupportedPrivilegeSet()); + + } + + function testGetSize1() { + + $objectInfo = [ + 'calendardata' => 'foo', + 'uri' => 'foo', + 'calendarid' => 1 + ]; + + $backend = new Backend\Mock([], []); + $obj = new CalendarObject($backend, [], $objectInfo); + $this->assertEquals(3, $obj->getSize()); + + } + + function testGetSize2() { + + $objectInfo = [ + 'uri' => 'foo', + 'calendarid' => 1, + 'size' => 4, + ]; + + $backend = new Backend\Mock([], []); + $obj = new CalendarObject($backend, [], $objectInfo); + $this->assertEquals(4, $obj->getSize()); + + } +} diff --git a/vendor/sabre/dav/tests/Sabre/CalDAV/CalendarQueryVAlarmTest.php b/vendor/sabre/dav/tests/Sabre/CalDAV/CalendarQueryVAlarmTest.php new file mode 100644 index 000000000..ca06d8ffa --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/CalDAV/CalendarQueryVAlarmTest.php @@ -0,0 +1,122 @@ +createComponent('VEVENT'); + $vevent->RRULE = 'FREQ=MONTHLY'; + $vevent->DTSTART = '20120101T120000Z'; + $vevent->UID = 'bla'; + + $valarm = $vcalendar->createComponent('VALARM'); + $valarm->TRIGGER = '-P15D'; + $vevent->add($valarm); + + + $vcalendar->add($vevent); + + $filter = [ + 'name' => 'VCALENDAR', + 'is-not-defined' => false, + 'time-range' => null, + 'prop-filters' => [], + 'comp-filters' => [ + [ + 'name' => 'VEVENT', + 'is-not-defined' => false, + 'time-range' => null, + 'prop-filters' => [], + 'comp-filters' => [ + [ + 'name' => 'VALARM', + 'is-not-defined' => false, + 'prop-filters' => [], + 'comp-filters' => [], + 'time-range' => [ + 'start' => new \DateTime('2012-05-10'), + 'end' => new \DateTime('2012-05-20'), + ], + ], + ], + ], + ], + ]; + + $validator = new CalendarQueryValidator(); + $this->assertTrue($validator->validate($vcalendar, $filter)); + + $vcalendar = new VObject\Component\VCalendar(); + + // A limited recurrence rule, should return false + $vevent = $vcalendar->createComponent('VEVENT'); + $vevent->RRULE = 'FREQ=MONTHLY;COUNT=1'; + $vevent->DTSTART = '20120101T120000Z'; + $vevent->UID = 'bla'; + + $valarm = $vcalendar->createComponent('VALARM'); + $valarm->TRIGGER = '-P15D'; + $vevent->add($valarm); + + $vcalendar->add($vevent); + + $this->assertFalse($validator->validate($vcalendar, $filter)); + } + + function testAlarmWayBefore() { + + $vcalendar = new VObject\Component\VCalendar(); + + $vevent = $vcalendar->createComponent('VEVENT'); + $vevent->DTSTART = '20120101T120000Z'; + $vevent->UID = 'bla'; + + $valarm = $vcalendar->createComponent('VALARM'); + $valarm->TRIGGER = '-P2W1D'; + $vevent->add($valarm); + + $vcalendar->add($vevent); + + $filter = [ + 'name' => 'VCALENDAR', + 'is-not-defined' => false, + 'time-range' => null, + 'prop-filters' => [], + 'comp-filters' => [ + [ + 'name' => 'VEVENT', + 'is-not-defined' => false, + 'time-range' => null, + 'prop-filters' => [], + 'comp-filters' => [ + [ + 'name' => 'VALARM', + 'is-not-defined' => false, + 'prop-filters' => [], + 'comp-filters' => [], + 'time-range' => [ + 'start' => new \DateTime('2011-12-10'), + 'end' => new \DateTime('2011-12-20'), + ], + ], + ], + ], + ], + ]; + + $validator = new CalendarQueryValidator(); + $this->assertTrue($validator->validate($vcalendar, $filter)); + + } + +} diff --git a/vendor/sabre/dav/tests/Sabre/CalDAV/CalendarQueryValidatorTest.php b/vendor/sabre/dav/tests/Sabre/CalDAV/CalendarQueryValidatorTest.php new file mode 100644 index 000000000..f3305163b --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/CalDAV/CalendarQueryValidatorTest.php @@ -0,0 +1,829 @@ +assertFalse($validator->validate($vcal, ['name' => 'VFOO'])); + + } + + /** + * @param string $icalObject + * @param array $filters + * @param int $outcome + * @dataProvider provider + */ + function testValid($icalObject, $filters, $outcome) { + + $validator = new CalendarQueryValidator(); + + // Wrapping filter in a VCALENDAR component filter, as this is always + // there anyway. + $filters = [ + 'name' => 'VCALENDAR', + 'comp-filters' => [$filters], + 'prop-filters' => [], + 'is-not-defined' => false, + 'time-range' => null, + ]; + + $vObject = VObject\Reader::read($icalObject); + + switch ($outcome) { + case 0 : + $this->assertFalse($validator->validate($vObject, $filters)); + break; + case 1 : + $this->assertTrue($validator->validate($vObject, $filters)); + break; + case -1 : + try { + $validator->validate($vObject, $filters); + $this->fail('This test was supposed to fail'); + } catch (\Exception $e) { + // We need to test something to be valid for phpunit strict + // mode. + $this->assertTrue(true); + } catch (\Throwable $e) { + // PHP7 + $this->assertTrue(true); + } + break; + + } + + } + + function provider() { + + $blob1 = << 'VEVENT', + 'comp-filters' => [], + 'prop-filters' => [], + 'is-not-defined' => false, + 'time-range' => null, + ]; + $filter2 = $filter1; + $filter2['name'] = 'VTODO'; + + $filter3 = $filter1; + $filter3['is-not-defined'] = true; + + $filter4 = $filter1; + $filter4['name'] = 'VTODO'; + $filter4['is-not-defined'] = true; + + $filter5 = $filter1; + $filter5['comp-filters'] = [ + [ + 'name' => 'VALARM', + 'is-not-defined' => false, + 'comp-filters' => [], + 'prop-filters' => [], + 'time-range' => null, + ], + ]; + $filter6 = $filter1; + $filter6['prop-filters'] = [ + [ + 'name' => 'SUMMARY', + 'is-not-defined' => false, + 'param-filters' => [], + 'time-range' => null, + 'text-match' => null, + ], + ]; + $filter7 = $filter6; + $filter7['prop-filters'][0]['name'] = 'DESCRIPTION'; + + $filter8 = $filter6; + $filter8['prop-filters'][0]['is-not-defined'] = true; + + $filter9 = $filter7; + $filter9['prop-filters'][0]['is-not-defined'] = true; + + $filter10 = $filter5; + $filter10['prop-filters'] = $filter6['prop-filters']; + + // Param filters + $filter11 = $filter1; + $filter11['prop-filters'] = [ + [ + 'name' => 'DTSTART', + 'is-not-defined' => false, + 'param-filters' => [ + [ + 'name' => 'VALUE', + 'is-not-defined' => false, + 'text-match' => null, + ], + ], + 'time-range' => null, + 'text-match' => null, + ], + ]; + + $filter12 = $filter11; + $filter12['prop-filters'][0]['param-filters'][0]['name'] = 'TZID'; + + $filter13 = $filter11; + $filter13['prop-filters'][0]['param-filters'][0]['is-not-defined'] = true; + + $filter14 = $filter12; + $filter14['prop-filters'][0]['param-filters'][0]['is-not-defined'] = true; + + // Param text filter + $filter15 = $filter11; + $filter15['prop-filters'][0]['param-filters'][0]['text-match'] = [ + 'collation' => 'i;ascii-casemap', + 'value' => 'dAtE', + 'negate-condition' => false, + ]; + $filter16 = $filter15; + $filter16['prop-filters'][0]['param-filters'][0]['text-match']['collation'] = 'i;octet'; + + $filter17 = $filter15; + $filter17['prop-filters'][0]['param-filters'][0]['text-match']['negate-condition'] = true; + + $filter18 = $filter15; + $filter18['prop-filters'][0]['param-filters'][0]['text-match']['negate-condition'] = true; + $filter18['prop-filters'][0]['param-filters'][0]['text-match']['collation'] = 'i;octet'; + + // prop + text + $filter19 = $filter5; + $filter19['comp-filters'][0]['prop-filters'] = [ + [ + 'name' => 'action', + 'is-not-defined' => false, + 'time-range' => null, + 'param-filters' => [], + 'text-match' => [ + 'collation' => 'i;ascii-casemap', + 'value' => 'display', + 'negate-condition' => false, + ], + ], + ]; + + // Time range + $filter20 = [ + 'name' => 'VEVENT', + 'comp-filters' => [], + 'prop-filters' => [], + 'is-not-defined' => false, + 'time-range' => [ + 'start' => new \DateTime('2011-01-01 10:00:00', new \DateTimeZone('GMT')), + 'end' => new \DateTime('2011-01-01 13:00:00', new \DateTimeZone('GMT')), + ], + ]; + // Time range, no end date + $filter21 = $filter20; + $filter21['time-range']['end'] = null; + + // Time range, no start date + $filter22 = $filter20; + $filter22['time-range']['start'] = null; + + // Time range, other dates + $filter23 = $filter20; + $filter23['time-range'] = [ + 'start' => new \DateTime('2011-02-01 10:00:00', new \DateTimeZone('GMT')), + 'end' => new \DateTime('2011-02-01 13:00:00', new \DateTimeZone('GMT')), + ]; + // Time range + $filter24 = [ + 'name' => 'VTODO', + 'comp-filters' => [], + 'prop-filters' => [], + 'is-not-defined' => false, + 'time-range' => [ + 'start' => new \DateTime('2011-01-01 12:45:00', new \DateTimeZone('GMT')), + 'end' => new \DateTime('2011-01-01 13:15:00', new \DateTimeZone('GMT')), + ], + ]; + // Time range, other dates (1 month in the future) + $filter25 = $filter24; + $filter25['time-range'] = [ + 'start' => new \DateTime('2011-02-01 10:00:00', new \DateTimeZone('GMT')), + 'end' => new \DateTime('2011-02-01 13:00:00', new \DateTimeZone('GMT')), + ]; + $filter26 = $filter24; + $filter26['time-range'] = [ + 'start' => new \DateTime('2011-01-01 11:45:00', new \DateTimeZone('GMT')), + 'end' => new \DateTime('2011-01-01 12:15:00', new \DateTimeZone('GMT')), + ]; + + // Time range for VJOURNAL + $filter27 = [ + 'name' => 'VJOURNAL', + 'comp-filters' => [], + 'prop-filters' => [], + 'is-not-defined' => false, + 'time-range' => [ + 'start' => new \DateTime('2011-01-01 12:45:00', new \DateTimeZone('GMT')), + 'end' => new \DateTime('2011-01-01 13:15:00', new \DateTimeZone('GMT')), + ], + ]; + $filter28 = $filter27; + $filter28['time-range'] = [ + 'start' => new \DateTime('2011-01-01 11:45:00', new \DateTimeZone('GMT')), + 'end' => new \DateTime('2011-01-01 12:15:00', new \DateTimeZone('GMT')), + ]; + // Time range for VFREEBUSY + $filter29 = [ + 'name' => 'VFREEBUSY', + 'comp-filters' => [], + 'prop-filters' => [], + 'is-not-defined' => false, + 'time-range' => [ + 'start' => new \DateTime('2011-01-01 12:45:00', new \DateTimeZone('GMT')), + 'end' => new \DateTime('2011-01-01 13:15:00', new \DateTimeZone('GMT')), + ], + ]; + // Time range filter on property + $filter30 = [ + 'name' => 'VEVENT', + 'comp-filters' => [], + 'prop-filters' => [ + [ + 'name' => 'DTSTART', + 'is-not-defined' => false, + 'param-filters' => [], + 'time-range' => [ + 'start' => new \DateTime('2011-01-01 10:00:00', new \DateTimeZone('GMT')), + 'end' => new \DateTime('2011-01-01 13:00:00', new \DateTimeZone('GMT')), + ], + 'text-match' => null, + ], + ], + 'is-not-defined' => false, + 'time-range' => null, + ]; + + // Time range for alarm + $filter31 = [ + 'name' => 'VEVENT', + 'prop-filters' => [], + 'comp-filters' => [ + [ + 'name' => 'VALARM', + 'is-not-defined' => false, + 'comp-filters' => [], + 'prop-filters' => [], + 'time-range' => [ + 'start' => new \DateTime('2011-01-01 10:45:00', new \DateTimeZone('GMT')), + 'end' => new \DateTime('2011-01-01 11:15:00', new \DateTimeZone('GMT')), + ], + 'text-match' => null, + ], + ], + 'is-not-defined' => false, + 'time-range' => null, + ]; + $filter32 = $filter31; + $filter32['comp-filters'][0]['time-range'] = [ + 'start' => new \DateTime('2011-01-01 11:45:00', new \DateTimeZone('GMT')), + 'end' => new \DateTime('2011-01-01 12:15:00', new \DateTimeZone('GMT')), + ]; + + $filter33 = $filter31; + $filter33['name'] = 'VTODO'; + $filter34 = $filter32; + $filter34['name'] = 'VTODO'; + $filter35 = $filter31; + $filter35['name'] = 'VJOURNAL'; + $filter36 = $filter32; + $filter36['name'] = 'VJOURNAL'; + + // Time range filter on non-datetime property + $filter37 = [ + 'name' => 'VEVENT', + 'comp-filters' => [], + 'prop-filters' => [ + [ + 'name' => 'SUMMARY', + 'is-not-defined' => false, + 'param-filters' => [], + 'time-range' => [ + 'start' => new \DateTime('2011-01-01 10:00:00', new \DateTimeZone('GMT')), + 'end' => new \DateTime('2011-01-01 13:00:00', new \DateTimeZone('GMT')), + ], + 'text-match' => null, + ], + ], + 'is-not-defined' => false, + 'time-range' => null, + ]; + + $filter38 = [ + 'name' => 'VEVENT', + 'comp-filters' => [], + 'prop-filters' => [], + 'is-not-defined' => false, + 'time-range' => [ + 'start' => new \DateTime('2012-07-01 00:00:00', new \DateTimeZone('UTC')), + 'end' => new \DateTime('2012-08-01 00:00:00', new \DateTimeZone('UTC')), + ] + ]; + $filter39 = [ + 'name' => 'VEVENT', + 'comp-filters' => [ + [ + 'name' => 'VALARM', + 'comp-filters' => [], + 'prop-filters' => [], + 'is-not-defined' => false, + 'time-range' => [ + 'start' => new \DateTime('2012-09-01 00:00:00', new \DateTimeZone('UTC')), + 'end' => new \DateTime('2012-10-01 00:00:00', new \DateTimeZone('UTC')), + ] + ], + ], + 'prop-filters' => [], + 'is-not-defined' => false, + 'time-range' => null, + ]; + + return [ + + // Component check + + [$blob1, $filter1, 1], + [$blob1, $filter2, 0], + [$blob1, $filter3, 0], + [$blob1, $filter4, 1], + + // Subcomponent check (4) + [$blob1, $filter5, 0], + [$blob2, $filter5, 1], + + // Property checki (6) + [$blob1, $filter6, 1], + [$blob1, $filter7, 0], + [$blob1, $filter8, 0], + [$blob1, $filter9, 1], + + // Subcomponent + property (10) + [$blob2, $filter10, 1], + + // Param filter (11) + [$blob3, $filter11, 1], + [$blob3, $filter12, 0], + [$blob3, $filter13, 0], + [$blob3, $filter14, 1], + + // Param + text (15) + [$blob3, $filter15, 1], + [$blob3, $filter16, 0], + [$blob3, $filter17, 0], + [$blob3, $filter18, 1], + + // Prop + text (19) + [$blob2, $filter19, 1], + + // Incorrect object (vcard) (20) + [$blob4, $filter1, -1], + + // Time-range for event (21) + [$blob5, $filter20, 1], + [$blob6, $filter20, 1], + [$blob7, $filter20, 1], + [$blob8, $filter20, 1], + + [$blob5, $filter21, 1], + [$blob5, $filter22, 1], + + [$blob5, $filter23, 0], + [$blob6, $filter23, 0], + [$blob7, $filter23, 0], + [$blob8, $filter23, 0], + + // Time-range for todo (31) + [$blob9, $filter24, 1], + [$blob9, $filter25, 0], + [$blob9, $filter26, 1], + [$blob10, $filter24, 1], + [$blob10, $filter25, 0], + [$blob10, $filter26, 1], + + [$blob11, $filter24, 0], + [$blob11, $filter25, 0], + [$blob11, $filter26, 1], + + [$blob12, $filter24, 1], + [$blob12, $filter25, 0], + [$blob12, $filter26, 0], + + [$blob13, $filter24, 1], + [$blob13, $filter25, 0], + [$blob13, $filter26, 1], + + [$blob14, $filter24, 1], + [$blob14, $filter25, 0], + [$blob14, $filter26, 0], + + [$blob15, $filter24, 1], + [$blob15, $filter25, 1], + [$blob15, $filter26, 1], + + [$blob16, $filter24, 1], + [$blob16, $filter25, 1], + [$blob16, $filter26, 1], + + // Time-range for journals (55) + [$blob17, $filter27, 0], + [$blob17, $filter28, 0], + [$blob18, $filter27, 0], + [$blob18, $filter28, 1], + [$blob19, $filter27, 1], + [$blob19, $filter28, 1], + + // Time-range for free-busy (61) + [$blob20, $filter29, -1], + + // Time-range on property (62) + [$blob5, $filter30, 1], + [$blob3, $filter37, -1], + [$blob3, $filter30, 0], + + // Time-range on alarm in vevent (65) + [$blob21, $filter31, 1], + [$blob21, $filter32, 0], + [$blob22, $filter31, 1], + [$blob22, $filter32, 0], + [$blob23, $filter31, 1], + [$blob23, $filter32, 0], + [$blob24, $filter31, 1], + [$blob24, $filter32, 0], + [$blob25, $filter31, 1], + [$blob25, $filter32, 0], + [$blob26, $filter31, 1], + [$blob26, $filter32, 0], + + // Time-range on alarm for vtodo (77) + [$blob27, $filter33, 1], + [$blob27, $filter34, 0], + + // Time-range on alarm for vjournal (79) + [$blob28, $filter35, -1], + [$blob28, $filter36, -1], + + // Time-range on alarm with duration (81) + [$blob29, $filter31, 1], + [$blob29, $filter32, 0], + [$blob30, $filter31, 0], + [$blob30, $filter32, 0], + + // Time-range with RRULE (85) + [$blob31, $filter20, 1], + [$blob32, $filter20, 0], + + // Bug reported on mailing list, related to all-day events (87) + //array($blob33, $filter38, 1), + + // Event in timerange, but filtered alarm is in the far future (88). + [$blob34, $filter39, 0], + ]; + + } + +} diff --git a/vendor/sabre/dav/tests/Sabre/CalDAV/CalendarTest.php b/vendor/sabre/dav/tests/Sabre/CalDAV/CalendarTest.php new file mode 100644 index 000000000..df85b6ded --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/CalDAV/CalendarTest.php @@ -0,0 +1,256 @@ +backend = TestUtil::getBackend(); + + $this->calendars = $this->backend->getCalendarsForUser('principals/user1'); + $this->assertEquals(2, count($this->calendars)); + $this->calendar = new Calendar($this->backend, $this->calendars[0]); + + + } + + function teardown() { + + unset($this->backend); + + } + + function testSimple() { + + $this->assertEquals($this->calendars[0]['uri'], $this->calendar->getName()); + + } + + /** + * @depends testSimple + */ + function testUpdateProperties() { + + $propPatch = new PropPatch([ + '{DAV:}displayname' => 'NewName', + ]); + + $result = $this->calendar->propPatch($propPatch); + $result = $propPatch->commit(); + + $this->assertEquals(true, $result); + + $calendars2 = $this->backend->getCalendarsForUser('principals/user1'); + $this->assertEquals('NewName', $calendars2[0]['{DAV:}displayname']); + + } + + /** + * @depends testSimple + */ + function testGetProperties() { + + $question = [ + '{urn:ietf:params:xml:ns:caldav}supported-calendar-component-set', + ]; + + $result = $this->calendar->getProperties($question); + + foreach ($question as $q) $this->assertArrayHasKey($q, $result); + + $this->assertEquals(['VEVENT', 'VTODO'], $result['{urn:ietf:params:xml:ns:caldav}supported-calendar-component-set']->getValue()); + + } + + /** + * @expectedException Sabre\DAV\Exception\NotFound + * @depends testSimple + */ + function testGetChildNotFound() { + + $this->calendar->getChild('randomname'); + + } + + /** + * @depends testSimple + */ + function testGetChildren() { + + $children = $this->calendar->getChildren(); + $this->assertEquals(1, count($children)); + + $this->assertTrue($children[0] instanceof CalendarObject); + + } + + /** + * @depends testGetChildren + */ + function testChildExists() { + + $this->assertFalse($this->calendar->childExists('foo')); + + $children = $this->calendar->getChildren(); + $this->assertTrue($this->calendar->childExists($children[0]->getName())); + } + + + + /** + * @expectedException Sabre\DAV\Exception\MethodNotAllowed + */ + function testCreateDirectory() { + + $this->calendar->createDirectory('hello'); + + } + + /** + * @expectedException Sabre\DAV\Exception\MethodNotAllowed + */ + function testSetName() { + + $this->calendar->setName('hello'); + + } + + function testGetLastModified() { + + $this->assertNull($this->calendar->getLastModified()); + + } + + function testCreateFile() { + + $file = fopen('php://memory', 'r+'); + fwrite($file, TestUtil::getTestCalendarData()); + rewind($file); + + $this->calendar->createFile('hello', $file); + + $file = $this->calendar->getChild('hello'); + $this->assertTrue($file instanceof CalendarObject); + + } + + function testCreateFileNoSupportedComponents() { + + $file = fopen('php://memory', 'r+'); + fwrite($file, TestUtil::getTestCalendarData()); + rewind($file); + + $calendar = new Calendar($this->backend, $this->calendars[1]); + $calendar->createFile('hello', $file); + + $file = $calendar->getChild('hello'); + $this->assertTrue($file instanceof CalendarObject); + + } + + function testDelete() { + + $this->calendar->delete(); + + $calendars = $this->backend->getCalendarsForUser('principals/user1'); + $this->assertEquals(1, count($calendars)); + } + + function testGetOwner() { + + $this->assertEquals('principals/user1', $this->calendar->getOwner()); + + } + + function testGetGroup() { + + $this->assertNull($this->calendar->getGroup()); + + } + + function testGetACL() { + + $expected = [ + [ + 'privilege' => '{DAV:}read', + 'principal' => 'principals/user1', + 'protected' => true, + ], + [ + 'privilege' => '{DAV:}read', + 'principal' => 'principals/user1/calendar-proxy-write', + 'protected' => true, + ], + [ + 'privilege' => '{DAV:}read', + 'principal' => 'principals/user1/calendar-proxy-read', + 'protected' => true, + ], + [ + 'privilege' => '{' . Plugin::NS_CALDAV . '}read-free-busy', + 'principal' => '{DAV:}authenticated', + 'protected' => true, + ], + [ + 'privilege' => '{DAV:}write', + 'principal' => 'principals/user1', + 'protected' => true, + ], + [ + 'privilege' => '{DAV:}write', + 'principal' => 'principals/user1/calendar-proxy-write', + 'protected' => true, + ], + ]; + $this->assertEquals($expected, $this->calendar->getACL()); + + } + + /** + * @expectedException \Sabre\DAV\Exception\Forbidden + */ + function testSetACL() { + + $this->calendar->setACL([]); + + } + + function testGetSyncToken() { + + $this->assertNull($this->calendar->getSyncToken()); + + } + + function testGetSyncTokenNoSyncSupport() { + + $calendar = new Calendar(new Backend\Mock([], []), []); + $this->assertNull($calendar->getSyncToken()); + + } + + function testGetChanges() { + + $this->assertNull($this->calendar->getChanges(1, 1)); + + } + +} diff --git a/vendor/sabre/dav/tests/Sabre/CalDAV/ExpandEventsDTSTARTandDTENDTest.php b/vendor/sabre/dav/tests/Sabre/CalDAV/ExpandEventsDTSTARTandDTENDTest.php new file mode 100644 index 000000000..9a3d47828 --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/CalDAV/ExpandEventsDTSTARTandDTENDTest.php @@ -0,0 +1,113 @@ + 1, + 'name' => 'Calendar', + 'principaluri' => 'principals/user1', + 'uri' => 'calendar1', + ] + ]; + + protected $caldavCalendarObjects = [ + 1 => [ + 'event.ics' => [ + 'calendardata' => 'BEGIN:VCALENDAR +VERSION:2.0 +BEGIN:VEVENT +UID:foobar +DTEND;TZID=Europe/Berlin:20120207T191500 +RRULE:FREQ=DAILY;INTERVAL=1;COUNT=3 +SUMMARY:RecurringEvents 3 times +DTSTART;TZID=Europe/Berlin:20120207T181500 +END:VEVENT +BEGIN:VEVENT +CREATED:20120207T111900Z +UID:foobar +DTEND;TZID=Europe/Berlin:20120208T191500 +SUMMARY:RecurringEvents 3 times OVERWRITTEN +DTSTART;TZID=Europe/Berlin:20120208T181500 +RECURRENCE-ID;TZID=Europe/Berlin:20120208T181500 +END:VEVENT +END:VCALENDAR +', + ], + ], + ]; + + function testExpand() { + + $request = HTTP\Sapi::createFromServerArray([ + 'REQUEST_METHOD' => 'REPORT', + 'HTTP_CONTENT_TYPE' => 'application/xml', + 'REQUEST_URI' => '/calendars/user1/calendar1', + 'HTTP_DEPTH' => '1', + ]); + + $request->setBody(' + + + + + + + + + + + + + + +'); + + $response = $this->request($request); + + // Everts super awesome xml parser. + $body = substr( + $response->body, + $start = strpos($response->body, 'BEGIN:VCALENDAR'), + strpos($response->body, 'END:VCALENDAR') - $start + 13 + ); + $body = str_replace(' ', '', $body); + + try { + $vObject = VObject\Reader::read($body); + } catch (VObject\ParseException $e) { + $this->fail('Could not parse object. Error:' . $e->getMessage() . ' full object: ' . $response->getBodyAsString()); + } + + // check if DTSTARTs and DTENDs are correct + foreach ($vObject->VEVENT as $vevent) { + /** @var $vevent Sabre\VObject\Component\VEvent */ + foreach ($vevent->children() as $child) { + /** @var $child Sabre\VObject\Property */ + if ($child->name == 'DTSTART') { + // DTSTART has to be one of three valid values + $this->assertContains($child->getValue(), ['20120207T171500Z', '20120208T171500Z', '20120209T171500Z'], 'DTSTART is not a valid value: ' . $child->getValue()); + } elseif ($child->name == 'DTEND') { + // DTEND has to be one of three valid values + $this->assertContains($child->getValue(), ['20120207T181500Z', '20120208T181500Z', '20120209T181500Z'], 'DTEND is not a valid value: ' . $child->getValue()); + } + } + } + } + +} diff --git a/vendor/sabre/dav/tests/Sabre/CalDAV/ExpandEventsDTSTARTandDTENDbyDayTest.php b/vendor/sabre/dav/tests/Sabre/CalDAV/ExpandEventsDTSTARTandDTENDbyDayTest.php new file mode 100644 index 000000000..efc49673f --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/CalDAV/ExpandEventsDTSTARTandDTENDbyDayTest.php @@ -0,0 +1,102 @@ + 1, + 'name' => 'Calendar', + 'principaluri' => 'principals/user1', + 'uri' => 'calendar1', + ] + ]; + + protected $caldavCalendarObjects = [ + 1 => [ + 'event.ics' => [ + 'calendardata' => 'BEGIN:VCALENDAR +VERSION:2.0 +BEGIN:VEVENT +UID:foobar +DTEND;TZID=Europe/Berlin:20120207T191500 +RRULE:FREQ=WEEKLY;INTERVAL=1;BYDAY=TU,TH +SUMMARY:RecurringEvents on tuesday and thursday +DTSTART;TZID=Europe/Berlin:20120207T181500 +END:VEVENT +END:VCALENDAR +', + ], + ], + ]; + + function testExpandRecurringByDayEvent() { + + $request = HTTP\Sapi::createFromServerArray([ + 'REQUEST_METHOD' => 'REPORT', + 'HTTP_CONTENT_TYPE' => 'application/xml', + 'REQUEST_URI' => '/calendars/user1/calendar1', + 'HTTP_DEPTH' => '1', + ]); + + $request->setBody(' + + + + + + + + + + + + + + +'); + + $response = $this->request($request); + + // Everts super awesome xml parser. + $body = substr( + $response->body, + $start = strpos($response->body, 'BEGIN:VCALENDAR'), + strpos($response->body, 'END:VCALENDAR') - $start + 13 + ); + $body = str_replace(' ', '', $body); + + $vObject = VObject\Reader::read($body); + + $this->assertEquals(2, count($vObject->VEVENT)); + + // check if DTSTARTs and DTENDs are correct + foreach ($vObject->VEVENT as $vevent) { + /** @var $vevent Sabre\VObject\Component\VEvent */ + foreach ($vevent->children() as $child) { + /** @var $child Sabre\VObject\Property */ + if ($child->name == 'DTSTART') { + // DTSTART has to be one of two valid values + $this->assertContains($child->getValue(), ['20120214T171500Z', '20120216T171500Z'], 'DTSTART is not a valid value: ' . $child->getValue()); + } elseif ($child->name == 'DTEND') { + // DTEND has to be one of two valid values + $this->assertContains($child->getValue(), ['20120214T181500Z', '20120216T181500Z'], 'DTEND is not a valid value: ' . $child->getValue()); + } + } + } + } + +} diff --git a/vendor/sabre/dav/tests/Sabre/CalDAV/ExpandEventsDoubleEventsTest.php b/vendor/sabre/dav/tests/Sabre/CalDAV/ExpandEventsDoubleEventsTest.php new file mode 100644 index 000000000..3a22e03d4 --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/CalDAV/ExpandEventsDoubleEventsTest.php @@ -0,0 +1,103 @@ + 1, + 'name' => 'Calendar', + 'principaluri' => 'principals/user1', + 'uri' => 'calendar1', + ] + ]; + + protected $caldavCalendarObjects = [ + 1 => [ + 'event.ics' => [ + 'calendardata' => 'BEGIN:VCALENDAR +VERSION:2.0 +BEGIN:VEVENT +UID:foobar +DTEND;TZID=Europe/Berlin:20120207T191500 +RRULE:FREQ=DAILY;INTERVAL=1;COUNT=3 +SUMMARY:RecurringEvents 3 times +DTSTART;TZID=Europe/Berlin:20120207T181500 +END:VEVENT +BEGIN:VEVENT +CREATED:20120207T111900Z +UID:foobar +DTEND;TZID=Europe/Berlin:20120208T191500 +SUMMARY:RecurringEvents 3 times OVERWRITTEN +DTSTART;TZID=Europe/Berlin:20120208T181500 +RECURRENCE-ID;TZID=Europe/Berlin:20120208T181500 +END:VEVENT +END:VCALENDAR +', + ], + ], + ]; + + function testExpand() { + + $request = HTTP\Sapi::createFromServerArray([ + 'REQUEST_METHOD' => 'REPORT', + 'HTTP_CONTENT_TYPE' => 'application/xml', + 'REQUEST_URI' => '/calendars/user1/calendar1', + 'HTTP_DEPTH' => '1', + ]); + + $request->setBody(' + + + + + + + + + + + + + + +'); + + $response = $this->request($request); + + // Everts super awesome xml parser. + $body = substr( + $response->body, + $start = strpos($response->body, 'BEGIN:VCALENDAR'), + strpos($response->body, 'END:VCALENDAR') - $start + 13 + ); + $body = str_replace(' ', '', $body); + + $vObject = VObject\Reader::read($body); + + // We only expect 3 events + $this->assertEquals(3, count($vObject->VEVENT), 'We got 6 events instead of 3. Output: ' . $body); + + // TZID should be gone + $this->assertFalse(isset($vObject->VEVENT->DTSTART['TZID'])); + + } + +} diff --git a/vendor/sabre/dav/tests/Sabre/CalDAV/ExpandEventsFloatingTimeTest.php b/vendor/sabre/dav/tests/Sabre/CalDAV/ExpandEventsFloatingTimeTest.php new file mode 100644 index 000000000..fba47d79b --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/CalDAV/ExpandEventsFloatingTimeTest.php @@ -0,0 +1,207 @@ + 1, + 'name' => 'Calendar', + 'principaluri' => 'principals/user1', + 'uri' => 'calendar1', + '{urn:ietf:params:xml:ns:caldav}calendar-timezone' => 'BEGIN:VCALENDAR +VERSION:2.0 +CALSCALE:GREGORIAN +BEGIN:VTIMEZONE +TZID:Europe/Berlin +BEGIN:DAYLIGHT +TZOFFSETFROM:+0100 +RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU +DTSTART:19810329T020000 +TZNAME:GMT+2 +TZOFFSETTO:+0200 +END:DAYLIGHT +BEGIN:STANDARD +TZOFFSETFROM:+0200 +RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU +DTSTART:19961027T030000 +TZNAME:GMT+1 +TZOFFSETTO:+0100 +END:STANDARD +END:VTIMEZONE +END:VCALENDAR', + ] + ]; + + protected $caldavCalendarObjects = [ + 1 => [ + 'event.ics' => [ + 'calendardata' => 'BEGIN:VCALENDAR +VERSION:2.0 +CALSCALE:GREGORIAN +BEGIN:VEVENT +CREATED:20140701T143658Z +UID:dba46fe8-1631-4d98-a575-97963c364dfe +DTEND:20141108T073000 +TRANSP:OPAQUE +SUMMARY:Floating Time event, starting 05:30am Europe/Berlin +DTSTART:20141108T053000 +DTSTAMP:20140701T143706Z +SEQUENCE:1 +END:VEVENT +END:VCALENDAR +', + ], + ], + ]; + + function testExpandCalendarQuery() { + + $request = new HTTP\Request('REPORT', '/calendars/user1/calendar1', [ + 'Depth' => 1, + 'Content-Type' => 'application/xml', + ]); + + $request->setBody(' + + + + + + + + + + + + + + +'); + + $response = $this->request($request); + + // Everts super awesome xml parser. + $body = substr( + $response->body, + $start = strpos($response->body, 'BEGIN:VCALENDAR'), + strpos($response->body, 'END:VCALENDAR') - $start + 13 + ); + $body = str_replace(' ', '', $body); + + $vObject = VObject\Reader::read($body); + + // check if DTSTARTs and DTENDs are correct + foreach ($vObject->VEVENT as $vevent) { + /** @var $vevent Sabre\VObject\Component\VEvent */ + foreach ($vevent->children() as $child) { + /** @var $child Sabre\VObject\Property */ + if ($child->name == 'DTSTART') { + // DTSTART should be the UTC equivalent of given floating time + $this->assertEquals('20141108T043000Z', $child->getValue()); + } elseif ($child->name == 'DTEND') { + // DTEND should be the UTC equivalent of given floating time + $this->assertEquals('20141108T063000Z', $child->getValue()); + } + } + } + } + + function testExpandMultiGet() { + + $request = new HTTP\Request('REPORT', '/calendars/user1/calendar1', [ + 'Depth' => 1, + 'Content-Type' => 'application/xml', + ]); + + $request->setBody(' + + + + + + + + /calendars/user1/calendar1/event.ics +'); + + $response = $this->request($request); + + $this->assertEquals(207, $response->getStatus()); + + // Everts super awesome xml parser. + $body = substr( + $response->body, + $start = strpos($response->body, 'BEGIN:VCALENDAR'), + strpos($response->body, 'END:VCALENDAR') - $start + 13 + ); + $body = str_replace(' ', '', $body); + + $vObject = VObject\Reader::read($body); + + // check if DTSTARTs and DTENDs are correct + foreach ($vObject->VEVENT as $vevent) { + /** @var $vevent Sabre\VObject\Component\VEvent */ + foreach ($vevent->children() as $child) { + /** @var $child Sabre\VObject\Property */ + if ($child->name == 'DTSTART') { + // DTSTART should be the UTC equivalent of given floating time + $this->assertEquals($child->getValue(), '20141108T043000Z'); + } elseif ($child->name == 'DTEND') { + // DTEND should be the UTC equivalent of given floating time + $this->assertEquals($child->getValue(), '20141108T063000Z'); + } + } + } + } + + function testExpandExport() { + + $request = new HTTP\Request('GET', '/calendars/user1/calendar1?export&start=1&end=2000000000&expand=1', [ + 'Depth' => 1, + 'Content-Type' => 'application/xml', + ]); + + $response = $this->request($request); + + $this->assertEquals(200, $response->getStatus()); + + // Everts super awesome xml parser. + $body = substr( + $response->body, + $start = strpos($response->body, 'BEGIN:VCALENDAR'), + strpos($response->body, 'END:VCALENDAR') - $start + 13 + ); + $body = str_replace(' ', '', $body); + + $vObject = VObject\Reader::read($body); + + // check if DTSTARTs and DTENDs are correct + foreach ($vObject->VEVENT as $vevent) { + /** @var $vevent Sabre\VObject\Component\VEvent */ + foreach ($vevent->children() as $child) { + /** @var $child Sabre\VObject\Property */ + if ($child->name == 'DTSTART') { + // DTSTART should be the UTC equivalent of given floating time + $this->assertEquals('20141108T043000Z', $child->getValue()); + } elseif ($child->name == 'DTEND') { + // DTEND should be the UTC equivalent of given floating time + $this->assertEquals('20141108T063000Z', $child->getValue()); + } + } + } + } + +} diff --git a/vendor/sabre/dav/tests/Sabre/CalDAV/FreeBusyReportTest.php b/vendor/sabre/dav/tests/Sabre/CalDAV/FreeBusyReportTest.php new file mode 100644 index 000000000..7604c7f4c --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/CalDAV/FreeBusyReportTest.php @@ -0,0 +1,174 @@ + [ + 'obj1' => [ + 'calendarid' => 1, + 'uri' => 'event1.ics', + 'calendardata' => $obj1, + ], + 'obj2' => [ + 'calendarid' => 1, + 'uri' => 'event2.ics', + 'calendardata' => $obj2 + ], + 'obj3' => [ + 'calendarid' => 1, + 'uri' => 'event3.ics', + 'calendardata' => $obj3 + ] + ], + ]; + + + $caldavBackend = new Backend\Mock([], $calendarData); + + $calendar = new Calendar($caldavBackend, [ + 'id' => 1, + 'uri' => 'calendar', + 'principaluri' => 'principals/user1', + '{' . Plugin::NS_CALDAV . '}calendar-timezone' => "BEGIN:VCALENDAR\r\nBEGIN:VTIMEZONE\r\nTZID:Europe/Berlin\r\nEND:VTIMEZONE\r\nEND:VCALENDAR", + ]); + + $this->server = new DAV\Server([$calendar]); + + $request = HTTP\Sapi::createFromServerArray([ + 'REQUEST_URI' => '/calendar', + ]); + $this->server->httpRequest = $request; + $this->server->httpResponse = new HTTP\ResponseMock(); + + $this->plugin = new Plugin(); + $this->server->addPlugin($this->plugin); + + } + + function testFreeBusyReport() { + + $reportXML = << + + + +XML; + + $report = $this->server->xml->parse($reportXML, null, $rootElem); + $this->plugin->report($rootElem, $report, null); + + $this->assertEquals(200, $this->server->httpResponse->status); + $this->assertEquals('text/calendar', $this->server->httpResponse->getHeader('Content-Type')); + $this->assertTrue(strpos($this->server->httpResponse->body, 'BEGIN:VFREEBUSY') !== false); + $this->assertTrue(strpos($this->server->httpResponse->body, '20111005T120000Z/20111005T130000Z') !== false); + $this->assertTrue(strpos($this->server->httpResponse->body, '20111006T100000Z/20111006T110000Z') !== false); + + } + + /** + * @expectedException Sabre\DAV\Exception\BadRequest + */ + function testFreeBusyReportNoTimeRange() { + + $reportXML = << + + +XML; + + $report = $this->server->xml->parse($reportXML, null, $rootElem); + + } + + /** + * @expectedException Sabre\DAV\Exception\NotImplemented + */ + function testFreeBusyReportWrongNode() { + + $request = HTTP\Sapi::createFromServerArray([ + 'REQUEST_URI' => '/', + ]); + $this->server->httpRequest = $request; + + $reportXML = << + + + +XML; + + $report = $this->server->xml->parse($reportXML, null, $rootElem); + $this->plugin->report($rootElem, $report, null); + + } + + /** + * @expectedException Sabre\DAV\Exception + */ + function testFreeBusyReportNoACLPlugin() { + + $this->server = new DAV\Server(); + $this->plugin = new Plugin(); + $this->server->addPlugin($this->plugin); + + $reportXML = << + + + +XML; + + $report = $this->server->xml->parse($reportXML, null, $rootElem); + $this->plugin->report($rootElem, $report, null); + + } +} diff --git a/vendor/sabre/dav/tests/Sabre/CalDAV/GetEventsByTimerangeTest.php b/vendor/sabre/dav/tests/Sabre/CalDAV/GetEventsByTimerangeTest.php new file mode 100644 index 000000000..5fd8d29a1 --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/CalDAV/GetEventsByTimerangeTest.php @@ -0,0 +1,82 @@ + 1, + 'name' => 'Calendar', + 'principaluri' => 'principals/user1', + 'uri' => 'calendar1', + ] + ]; + + protected $caldavCalendarObjects = [ + 1 => [ + 'event.ics' => [ + 'calendardata' => 'BEGIN:VCALENDAR +VERSION:2.0 +BEGIN:VEVENT +CREATED:20120313T142342Z +UID:171EBEFC-C951-499D-B234-7BA7D677B45D +DTEND;TZID=Europe/Berlin:20120227T010000 +TRANSP:OPAQUE +SUMMARY:Monday 0h +DTSTART;TZID=Europe/Berlin:20120227T000000 +DTSTAMP:20120313T142416Z +SEQUENCE:4 +END:VEVENT +END:VCALENDAR +', + ], + ], + ]; + + function testQueryTimerange() { + + $request = new HTTP\Request( + 'REPORT', + '/calendars/user1/calendar1', + [ + 'Content-Type' => 'application/xml', + 'Depth' => '1', + ] + ); + + $request->setBody(' + + + + + + + + + + + + + + +'); + + $response = $this->request($request); + + $this->assertTrue(strpos($response->body, 'BEGIN:VCALENDAR') !== false); + + } + +} diff --git a/vendor/sabre/dav/tests/Sabre/CalDAV/ICSExportPluginTest.php b/vendor/sabre/dav/tests/Sabre/CalDAV/ICSExportPluginTest.php new file mode 100644 index 000000000..75412577e --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/CalDAV/ICSExportPluginTest.php @@ -0,0 +1,386 @@ +icsExportPlugin = new ICSExportPlugin(); + $this->server->addPlugin( + $this->icsExportPlugin + ); + + $id = $this->caldavBackend->createCalendar( + 'principals/admin', + 'UUID-123467', + [ + '{DAV:}displayname' => 'Hello!', + '{http://apple.com/ns/ical/}calendar-color' => '#AA0000FF', + ] + ); + + $this->caldavBackend->createCalendarObject( + $id, + 'event-1', + <<caldavBackend->createCalendarObject( + $id, + 'todo-1', + <<assertEquals( + $this->icsExportPlugin, + $this->server->getPlugin('ics-export') + ); + $this->assertEquals($this->icsExportPlugin, $this->server->getPlugin('ics-export')); + $this->assertEquals('ics-export', $this->icsExportPlugin->getPluginInfo()['name']); + + } + + function testBeforeMethod() { + + $request = new HTTP\Request( + 'GET', + '/calendars/admin/UUID-123467?export' + ); + + $response = $this->request($request); + + $this->assertEquals(200, $response->getStatus()); + $this->assertEquals('text/calendar', $response->getHeader('Content-Type')); + + $obj = VObject\Reader::read($response->body); + + $this->assertEquals(8, count($obj->children())); + $this->assertEquals(1, count($obj->VERSION)); + $this->assertEquals(1, count($obj->CALSCALE)); + $this->assertEquals(1, count($obj->PRODID)); + $this->assertTrue(strpos((string)$obj->PRODID, DAV\Version::VERSION) !== false); + $this->assertEquals(1, count($obj->VTIMEZONE)); + $this->assertEquals(1, count($obj->VEVENT)); + $this->assertEquals("Hello!", $obj->{"X-WR-CALNAME"}); + $this->assertEquals("#AA0000FF", $obj->{"X-APPLE-CALENDAR-COLOR"}); + + } + function testBeforeMethodNoVersion() { + + $request = new HTTP\Request( + 'GET', + '/calendars/admin/UUID-123467?export' + ); + DAV\Server::$exposeVersion = false; + $response = $this->request($request); + DAV\Server::$exposeVersion = true; + + $this->assertEquals(200, $response->getStatus()); + $this->assertEquals('text/calendar', $response->getHeader('Content-Type')); + + $obj = VObject\Reader::read($response->body); + + $this->assertEquals(8, count($obj->children())); + $this->assertEquals(1, count($obj->VERSION)); + $this->assertEquals(1, count($obj->CALSCALE)); + $this->assertEquals(1, count($obj->PRODID)); + $this->assertFalse(strpos((string)$obj->PRODID, DAV\Version::VERSION) !== false); + $this->assertEquals(1, count($obj->VTIMEZONE)); + $this->assertEquals(1, count($obj->VEVENT)); + + } + + function testBeforeMethodNoExport() { + + $request = new HTTP\Request( + 'GET', + '/calendars/admin/UUID-123467' + ); + $response = new HTTP\Response(); + $this->assertNull($this->icsExportPlugin->httpGet($request, $response)); + + } + + function testACLIntegrationBlocked() { + + $aclPlugin = new DAVACL\Plugin(); + $aclPlugin->allowUnauthenticatedAccess = false; + $this->server->addPlugin( + $aclPlugin + ); + + $request = new HTTP\Request( + 'GET', + '/calendars/admin/UUID-123467?export' + ); + + $this->request($request, 403); + + } + + function testACLIntegrationNotBlocked() { + + $aclPlugin = new DAVACL\Plugin(); + $aclPlugin->allowUnauthenticatedAccess = false; + $this->server->addPlugin( + $aclPlugin + ); + $this->server->addPlugin( + new Plugin() + ); + + $this->autoLogin('admin'); + + $request = new HTTP\Request( + 'GET', + '/calendars/admin/UUID-123467?export' + ); + + $response = $this->request($request, 200); + $this->assertEquals('text/calendar', $response->getHeader('Content-Type')); + + $obj = VObject\Reader::read($response->body); + + $this->assertEquals(8, count($obj->children())); + $this->assertEquals(1, count($obj->VERSION)); + $this->assertEquals(1, count($obj->CALSCALE)); + $this->assertEquals(1, count($obj->PRODID)); + $this->assertTrue(strpos((string)$obj->PRODID, DAV\Version::VERSION) !== false); + $this->assertEquals(1, count($obj->VTIMEZONE)); + $this->assertEquals(1, count($obj->VEVENT)); + + } + + function testBadStartParam() { + + $request = new HTTP\Request( + 'GET', + '/calendars/admin/UUID-123467?export&start=foo' + ); + $this->request($request, 400); + + } + + function testBadEndParam() { + + $request = new HTTP\Request( + 'GET', + '/calendars/admin/UUID-123467?export&end=foo' + ); + $this->request($request, 400); + + } + + function testFilterStartEnd() { + + $request = new HTTP\Request( + 'GET', + '/calendars/admin/UUID-123467?export&start=1&end=2' + ); + $response = $this->request($request, 200); + + $obj = VObject\Reader::read($response->getBody()); + + $this->assertEquals(0, count($obj->VTIMEZONE)); + $this->assertEquals(0, count($obj->VEVENT)); + + } + + function testExpandNoStart() { + + $request = new HTTP\Request( + 'GET', + '/calendars/admin/UUID-123467?export&expand=1&end=2' + ); + $this->request($request, 400); + + } + + function testExpand() { + + $request = new HTTP\Request( + 'GET', + '/calendars/admin/UUID-123467?export&start=1&end=2000000000&expand=1' + ); + $response = $this->request($request, 200); + + $obj = VObject\Reader::read($response->getBody()); + + $this->assertEquals(0, count($obj->VTIMEZONE)); + $this->assertEquals(1, count($obj->VEVENT)); + + } + + function testJCal() { + + $request = new HTTP\Request( + 'GET', + '/calendars/admin/UUID-123467?export', + ['Accept' => 'application/calendar+json'] + ); + + $response = $this->request($request, 200); + $this->assertEquals('application/calendar+json', $response->getHeader('Content-Type')); + + } + + function testJCalInUrl() { + + $request = new HTTP\Request( + 'GET', + '/calendars/admin/UUID-123467?export&accept=jcal' + ); + + $response = $this->request($request, 200); + $this->assertEquals('application/calendar+json', $response->getHeader('Content-Type')); + + } + + function testNegotiateDefault() { + + $request = new HTTP\Request( + 'GET', + '/calendars/admin/UUID-123467?export', + ['Accept' => 'text/plain'] + ); + + $response = $this->request($request, 200); + $this->assertEquals('text/calendar', $response->getHeader('Content-Type')); + + } + + function testFilterComponentVEVENT() { + + $request = new HTTP\Request( + 'GET', + '/calendars/admin/UUID-123467?export&componentType=VEVENT' + ); + + $response = $this->request($request, 200); + + $obj = VObject\Reader::read($response->body); + $this->assertEquals(1, count($obj->VTIMEZONE)); + $this->assertEquals(1, count($obj->VEVENT)); + $this->assertEquals(0, count($obj->VTODO)); + + } + + function testFilterComponentVTODO() { + + $request = new HTTP\Request( + 'GET', + '/calendars/admin/UUID-123467?export&componentType=VTODO' + ); + + $response = $this->request($request, 200); + + $obj = VObject\Reader::read($response->body); + + $this->assertEquals(0, count($obj->VTIMEZONE)); + $this->assertEquals(0, count($obj->VEVENT)); + $this->assertEquals(1, count($obj->VTODO)); + + } + + function testFilterComponentBadComponent() { + + $request = new HTTP\Request( + 'GET', + '/calendars/admin/UUID-123467?export&componentType=VVOODOO' + ); + + $response = $this->request($request, 400); + + } + + function testContentDisposition() { + + $request = new HTTP\Request( + 'GET', + '/calendars/admin/UUID-123467?export' + ); + + $response = $this->request($request, 200); + $this->assertEquals('text/calendar', $response->getHeader('Content-Type')); + $this->assertEquals( + 'attachment; filename="UUID-123467-' . date('Y-m-d') . '.ics"', + $response->getHeader('Content-Disposition') + ); + + } + + function testContentDispositionJson() { + + $request = new HTTP\Request( + 'GET', + '/calendars/admin/UUID-123467?export', + ['Accept' => 'application/calendar+json'] + ); + + $response = $this->request($request, 200); + $this->assertEquals('application/calendar+json', $response->getHeader('Content-Type')); + $this->assertEquals( + 'attachment; filename="UUID-123467-' . date('Y-m-d') . '.json"', + $response->getHeader('Content-Disposition') + ); + + } + + function testContentDispositionBadChars() { + + $this->caldavBackend->createCalendar( + 'principals/admin', + 'UUID-b_ad"(ch)ars', + [ + '{DAV:}displayname' => 'Test bad characters', + '{http://apple.com/ns/ical/}calendar-color' => '#AA0000FF', + ] + ); + + $request = new HTTP\Request( + 'GET', + '/calendars/admin/UUID-b_ad"(ch)ars?export', + ['Accept' => 'application/calendar+json'] + ); + + $response = $this->request($request, 200); + $this->assertEquals('application/calendar+json', $response->getHeader('Content-Type')); + $this->assertEquals( + 'attachment; filename="UUID-b_adchars-' . date('Y-m-d') . '.json"', + $response->getHeader('Content-Disposition') + ); + + } + +} diff --git a/vendor/sabre/dav/tests/Sabre/CalDAV/Issue166Test.php b/vendor/sabre/dav/tests/Sabre/CalDAV/Issue166Test.php new file mode 100644 index 000000000..a1a9b7c04 --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/CalDAV/Issue166Test.php @@ -0,0 +1,63 @@ + 'VCALENDAR', + 'comp-filters' => [ + [ + 'name' => 'VEVENT', + 'comp-filters' => [], + 'prop-filters' => [], + 'is-not-defined' => false, + 'time-range' => [ + 'start' => new \DateTime('2011-12-01'), + 'end' => new \DateTime('2012-02-01'), + ], + ], + ], + 'prop-filters' => [], + 'is-not-defined' => false, + 'time-range' => null, + ]; + $input = VObject\Reader::read($input); + $this->assertTrue($validator->validate($input, $filters)); + + } + +} diff --git a/vendor/sabre/dav/tests/Sabre/CalDAV/Issue172Test.php b/vendor/sabre/dav/tests/Sabre/CalDAV/Issue172Test.php new file mode 100644 index 000000000..e2b85c2bc --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/CalDAV/Issue172Test.php @@ -0,0 +1,135 @@ + 'VCALENDAR', + 'comp-filters' => [ + [ + 'name' => 'VEVENT', + 'comp-filters' => [], + 'prop-filters' => [], + 'is-not-defined' => false, + 'time-range' => [ + 'start' => new \DateTime('2012-01-18 21:00:00 GMT-08:00'), + 'end' => new \DateTime('2012-01-18 21:00:00 GMT-08:00'), + ], + ], + ], + 'prop-filters' => [], + ]; + $input = VObject\Reader::read($input); + $this->assertTrue($validator->validate($input, $filters)); + } + + // Pacific Standard Time, translates to America/Los_Angeles (GMT-8 in January) + function testOutlookTimezoneName() { + $input = << 'VCALENDAR', + 'comp-filters' => [ + [ + 'name' => 'VEVENT', + 'comp-filters' => [], + 'prop-filters' => [], + 'is-not-defined' => false, + 'time-range' => [ + 'start' => new \DateTime('2012-01-13 10:30:00 GMT-08:00'), + 'end' => new \DateTime('2012-01-13 10:30:00 GMT-08:00'), + ], + ], + ], + 'prop-filters' => [], + ]; + $input = VObject\Reader::read($input); + $this->assertTrue($validator->validate($input, $filters)); + } + + // X-LIC-LOCATION, translates to America/Los_Angeles (GMT-8 in January) + function testLibICalLocationName() { + $input = << 'VCALENDAR', + 'comp-filters' => [ + [ + 'name' => 'VEVENT', + 'comp-filters' => [], + 'prop-filters' => [], + 'is-not-defined' => false, + 'time-range' => [ + 'start' => new \DateTime('2012-01-13 10:30:00 GMT-08:00'), + 'end' => new \DateTime('2012-01-13 10:30:00 GMT-08:00'), + ], + ], + ], + 'prop-filters' => [], + ]; + $input = VObject\Reader::read($input); + $this->assertTrue($validator->validate($input, $filters)); + } +} diff --git a/vendor/sabre/dav/tests/Sabre/CalDAV/Issue203Test.php b/vendor/sabre/dav/tests/Sabre/CalDAV/Issue203Test.php new file mode 100644 index 000000000..369e9a70c --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/CalDAV/Issue203Test.php @@ -0,0 +1,137 @@ + 1, + 'name' => 'Calendar', + 'principaluri' => 'principals/user1', + 'uri' => 'calendar1', + ] + ]; + + protected $caldavCalendarObjects = [ + 1 => [ + 'event.ics' => [ + 'calendardata' => 'BEGIN:VCALENDAR +VERSION:2.0 +BEGIN:VEVENT +UID:20120330T155305CEST-6585fBUVgV +DTSTAMP:20120330T135305Z +DTSTART;TZID=Europe/Berlin:20120326T155200 +DTEND;TZID=Europe/Berlin:20120326T165200 +RRULE:FREQ=DAILY;COUNT=2;INTERVAL=1 +SUMMARY:original summary +TRANSP:OPAQUE +END:VEVENT +BEGIN:VEVENT +UID:20120330T155305CEST-6585fBUVgV +DTSTAMP:20120330T135352Z +DESCRIPTION: +DTSTART;TZID=Europe/Berlin:20120328T155200 +DTEND;TZID=Europe/Berlin:20120328T165200 +RECURRENCE-ID;TZID=Europe/Berlin:20120327T155200 +SEQUENCE:1 +SUMMARY:overwritten summary +TRANSP:OPAQUE +END:VEVENT +END:VCALENDAR +', + ], + ], + ]; + + function testIssue203() { + + $request = HTTP\Sapi::createFromServerArray([ + 'REQUEST_METHOD' => 'REPORT', + 'HTTP_CONTENT_TYPE' => 'application/xml', + 'REQUEST_URI' => '/calendars/user1/calendar1', + 'HTTP_DEPTH' => '1', + ]); + + $request->setBody(' + + + + + + + + + + + + + + +'); + + $response = $this->request($request); + + // Everts super awesome xml parser. + $body = substr( + $response->body, + $start = strpos($response->body, 'BEGIN:VCALENDAR'), + strpos($response->body, 'END:VCALENDAR') - $start + 13 + ); + $body = str_replace(' ', '', $body); + + $vObject = VObject\Reader::read($body); + + $this->assertEquals(2, count($vObject->VEVENT)); + + + $expectedEvents = [ + [ + 'DTSTART' => '20120326T135200Z', + 'DTEND' => '20120326T145200Z', + 'SUMMARY' => 'original summary', + ], + [ + 'DTSTART' => '20120328T135200Z', + 'DTEND' => '20120328T145200Z', + 'SUMMARY' => 'overwritten summary', + 'RECURRENCE-ID' => '20120327T135200Z', + ] + ]; + + // try to match agains $expectedEvents array + foreach ($expectedEvents as $expectedEvent) { + + $matching = false; + + foreach ($vObject->VEVENT as $vevent) { + /** @var $vevent Sabre\VObject\Component\VEvent */ + foreach ($vevent->children() as $child) { + /** @var $child Sabre\VObject\Property */ + if (isset($expectedEvent[$child->name])) { + if ($expectedEvent[$child->name] != $child->getValue()) { + continue 2; + } + } + } + + $matching = true; + break; + } + + $this->assertTrue($matching, 'Did not find the following event in the response: ' . var_export($expectedEvent, true)); + } + } +} diff --git a/vendor/sabre/dav/tests/Sabre/CalDAV/Issue205Test.php b/vendor/sabre/dav/tests/Sabre/CalDAV/Issue205Test.php new file mode 100644 index 000000000..ce40a90b0 --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/CalDAV/Issue205Test.php @@ -0,0 +1,98 @@ + 1, + 'name' => 'Calendar', + 'principaluri' => 'principals/user1', + 'uri' => 'calendar1', + ] + ]; + + protected $caldavCalendarObjects = [ + 1 => [ + 'event.ics' => [ + 'calendardata' => 'BEGIN:VCALENDAR +VERSION:2.0 +BEGIN:VEVENT +UID:20120330T155305CEST-6585fBUVgV +DTSTAMP:20120330T135305Z +DTSTART;TZID=Europe/Berlin:20120326T155200 +DTEND;TZID=Europe/Berlin:20120326T165200 +SUMMARY:original summary +TRANSP:OPAQUE +BEGIN:VALARM +ACTION:AUDIO +ATTACH;VALUE=URI:Basso +TRIGGER:PT0S +END:VALARM +END:VEVENT +END:VCALENDAR +', + ], + ], + ]; + + function testIssue205() { + + $request = HTTP\Sapi::createFromServerArray([ + 'REQUEST_METHOD' => 'REPORT', + 'HTTP_CONTENT_TYPE' => 'application/xml', + 'REQUEST_URI' => '/calendars/user1/calendar1', + 'HTTP_DEPTH' => '1', + ]); + + $request->setBody(' + + + + + + + + + + + + + + + + +'); + + $response = $this->request($request); + + $this->assertFalse(strpos($response->body, 'Exception'), 'Exception occurred: ' . $response->body); + $this->assertFalse(strpos($response->body, 'Unknown or bad format'), 'DateTime unknown format Exception: ' . $response->body); + + // Everts super awesome xml parser. + $body = substr( + $response->body, + $start = strpos($response->body, 'BEGIN:VCALENDAR'), + strpos($response->body, 'END:VCALENDAR') - $start + 13 + ); + $body = str_replace(' ', '', $body); + + $vObject = VObject\Reader::read($body); + + $this->assertEquals(1, count($vObject->VEVENT)); + + } +} diff --git a/vendor/sabre/dav/tests/Sabre/CalDAV/Issue211Test.php b/vendor/sabre/dav/tests/Sabre/CalDAV/Issue211Test.php new file mode 100644 index 000000000..950629fd8 --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/CalDAV/Issue211Test.php @@ -0,0 +1,89 @@ + 1, + 'name' => 'Calendar', + 'principaluri' => 'principals/user1', + 'uri' => 'calendar1', + ] + ]; + + protected $caldavCalendarObjects = [ + 1 => [ + 'event.ics' => [ + 'calendardata' => 'BEGIN:VCALENDAR +VERSION:2.0 +BEGIN:VEVENT +UID:20120418T172519CEST-3510gh1hVw +DTSTAMP:20120418T152519Z +DTSTART;VALUE=DATE:20120330 +DTEND;VALUE=DATE:20120531 +EXDATE;TZID=Europe/Berlin:20120330T000000 +RRULE:FREQ=YEARLY;INTERVAL=1 +SEQUENCE:1 +SUMMARY:Birthday +TRANSP:TRANSPARENT +BEGIN:VALARM +ACTION:EMAIL +ATTENDEE:MAILTO:xxx@domain.de +DESCRIPTION:Dies ist eine Kalender Erinnerung +SUMMARY:Kalender Alarm Erinnerung +TRIGGER;VALUE=DATE-TIME:20120329T060000Z +END:VALARM +END:VEVENT +END:VCALENDAR +', + ], + ], + ]; + + function testIssue211() { + + $request = HTTP\Sapi::createFromServerArray([ + 'REQUEST_METHOD' => 'REPORT', + 'HTTP_CONTENT_TYPE' => 'application/xml', + 'REQUEST_URI' => '/calendars/user1/calendar1', + 'HTTP_DEPTH' => '1', + ]); + + $request->setBody(' + + + + + + + + + + + + + + +'); + + $response = $this->request($request); + + // if this assert is reached, the endless loop is gone + // There should be no matching events + $this->assertFalse(strpos('BEGIN:VEVENT', $response->body)); + + } +} diff --git a/vendor/sabre/dav/tests/Sabre/CalDAV/Issue220Test.php b/vendor/sabre/dav/tests/Sabre/CalDAV/Issue220Test.php new file mode 100644 index 000000000..c3c0b5b48 --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/CalDAV/Issue220Test.php @@ -0,0 +1,99 @@ + 1, + 'name' => 'Calendar', + 'principaluri' => 'principals/user1', + 'uri' => 'calendar1', + ] + ]; + + protected $caldavCalendarObjects = [ + 1 => [ + 'event.ics' => [ + 'calendardata' => 'BEGIN:VCALENDAR +VERSION:2.0 +BEGIN:VEVENT +DTSTART;TZID=Europe/Berlin:20120601T180000 +SUMMARY:Brot backen +RRULE:FREQ=DAILY;INTERVAL=1;WKST=MO +TRANSP:OPAQUE +DURATION:PT20M +LAST-MODIFIED:20120601T064634Z +CREATED:20120601T064634Z +DTSTAMP:20120601T064634Z +UID:b64f14c5-dccc-4eda-947f-bdb1f763fbcd +BEGIN:VALARM +TRIGGER;VALUE=DURATION:-PT5M +ACTION:DISPLAY +DESCRIPTION:Default Event Notification +X-WR-ALARMUID:cd952c1b-b3d6-41fb-b0a6-ec3a1a5bdd58 +END:VALARM +END:VEVENT +BEGIN:VEVENT +DTSTART;TZID=Europe/Berlin:20120606T180000 +SUMMARY:Brot backen +TRANSP:OPAQUE +STATUS:CANCELLED +DTEND;TZID=Europe/Berlin:20120606T182000 +LAST-MODIFIED:20120605T094310Z +SEQUENCE:1 +RECURRENCE-ID:20120606T160000Z +UID:b64f14c5-dccc-4eda-947f-bdb1f763fbcd +END:VEVENT +END:VCALENDAR +', + ], + ], + ]; + + function testIssue220() { + + $request = HTTP\Sapi::createFromServerArray([ + 'REQUEST_METHOD' => 'REPORT', + 'HTTP_CONTENT_TYPE' => 'application/xml', + 'REQUEST_URI' => '/calendars/user1/calendar1', + 'HTTP_DEPTH' => '1', + ]); + + $request->setBody(' + + + + + + + + + + + + + + +'); + + $response = $this->request($request); + + $this->assertFalse(strpos($response->body, 'PHPUnit_Framework_Error_Warning'), 'Error Warning occurred: ' . $response->body); + $this->assertFalse(strpos($response->body, 'Invalid argument supplied for foreach()'), 'Invalid argument supplied for foreach(): ' . $response->body); + + $this->assertEquals(207, $response->status); + } +} diff --git a/vendor/sabre/dav/tests/Sabre/CalDAV/Issue228Test.php b/vendor/sabre/dav/tests/Sabre/CalDAV/Issue228Test.php new file mode 100644 index 000000000..d0783701d --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/CalDAV/Issue228Test.php @@ -0,0 +1,79 @@ + 1, + 'name' => 'Calendar', + 'principaluri' => 'principals/user1', + 'uri' => 'calendar1', + ] + ]; + + protected $caldavCalendarObjects = [ + 1 => [ + 'event.ics' => [ + 'calendardata' => 'BEGIN:VCALENDAR +VERSION:2.0 +BEGIN:VEVENT +UID:20120730T113415CEST-6804EGphkd@xxxxxx.de +DTSTAMP:20120730T093415Z +DTSTART;VALUE=DATE:20120729 +DTEND;VALUE=DATE:20120730 +SUMMARY:sunday event +TRANSP:TRANSPARENT +END:VEVENT +END:VCALENDAR +', + ], + ], + ]; + + function testIssue228() { + + $request = HTTP\Sapi::createFromServerArray([ + 'REQUEST_METHOD' => 'REPORT', + 'HTTP_CONTENT_TYPE' => 'application/xml', + 'REQUEST_URI' => '/calendars/user1/calendar1', + 'HTTP_DEPTH' => '1', + ]); + + $request->setBody(' + + + + + + + + + + + + + + +'); + + $response = $this->request($request); + + // We must check if absolutely nothing was returned from this query. + $this->assertFalse(strpos($response->body, 'BEGIN:VCALENDAR')); + + } +} diff --git a/vendor/sabre/dav/tests/Sabre/CalDAV/JCalTransformTest.php b/vendor/sabre/dav/tests/Sabre/CalDAV/JCalTransformTest.php new file mode 100644 index 000000000..f1eed1775 --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/CalDAV/JCalTransformTest.php @@ -0,0 +1,262 @@ + 1, + 'principaluri' => 'principals/user1', + 'uri' => 'foo', + ] + ]; + protected $caldavCalendarObjects = [ + 1 => [ + 'bar.ics' => [ + 'uri' => 'bar.ics', + 'calendarid' => 1, + 'calendardata' => "BEGIN:VCALENDAR\r\nBEGIN:VEVENT\r\nEND:VEVENT\r\nEND:VCALENDAR\r\n", + 'lastmodified' => null + ] + ], + ]; + + function testGet() { + + $headers = [ + 'Accept' => 'application/calendar+json', + ]; + $request = new Request('GET', '/calendars/user1/foo/bar.ics', $headers); + + $response = $this->request($request); + + $body = $response->getBodyAsString(); + $this->assertEquals(200, $response->getStatus(), "Incorrect status code: " . $body); + + $response = json_decode($body, true); + if (json_last_error() !== JSON_ERROR_NONE) { + $this->fail('Json decoding error: ' . json_last_error_msg()); + } + $this->assertEquals( + [ + 'vcalendar', + [], + [ + [ + 'vevent', + [], + [], + ], + ], + ], + $response + ); + + } + + function testMultiGet() { + + $xml = << + + + + + /calendars/user1/foo/bar.ics + +XML; + + $headers = []; + $request = new Request('REPORT', '/calendars/user1/foo', $headers, $xml); + + $response = $this->request($request); + + $this->assertEquals(207, $response->getStatus(), 'Full rsponse: ' . $response->getBodyAsString()); + + $multiStatus = $this->server->xml->parse( + $response->getBodyAsString() + ); + + $responses = $multiStatus->getResponses(); + $this->assertEquals(1, count($responses)); + + $response = $responses[0]->getResponseProperties()[200]["{urn:ietf:params:xml:ns:caldav}calendar-data"]; + + $jresponse = json_decode($response, true); + if (json_last_error()) { + $this->fail('Json decoding error: ' . json_last_error_msg() . '. Full response: ' . $response); + } + $this->assertEquals( + [ + 'vcalendar', + [], + [ + [ + 'vevent', + [], + [], + ], + ], + ], + $jresponse + ); + + } + + function testCalendarQueryDepth1() { + + $xml = << + + + + + + + + +XML; + + $headers = [ + 'Depth' => '1', + ]; + $request = new Request('REPORT', '/calendars/user1/foo', $headers, $xml); + + $response = $this->request($request); + + $this->assertEquals(207, $response->getStatus(), "Invalid response code. Full body: " . $response->getBodyAsString()); + + $multiStatus = $this->server->xml->parse( + $response->getBodyAsString() + ); + + $responses = $multiStatus->getResponses(); + + $this->assertEquals(1, count($responses)); + + $response = $responses[0]->getResponseProperties()[200]["{urn:ietf:params:xml:ns:caldav}calendar-data"]; + $response = json_decode($response, true); + if (json_last_error()) { + $this->fail('Json decoding error: ' . json_last_error_msg()); + } + $this->assertEquals( + [ + 'vcalendar', + [], + [ + [ + 'vevent', + [], + [], + ], + ], + ], + $response + ); + + } + + function testCalendarQueryDepth0() { + + $xml = << + + + + + + + + +XML; + + $headers = [ + 'Depth' => '0', + ]; + $request = new Request('REPORT', '/calendars/user1/foo/bar.ics', $headers, $xml); + + $response = $this->request($request); + + $this->assertEquals(207, $response->getStatus(), "Invalid response code. Full body: " . $response->getBodyAsString()); + + $multiStatus = $this->server->xml->parse( + $response->getBodyAsString() + ); + + $responses = $multiStatus->getResponses(); + + $this->assertEquals(1, count($responses)); + + $response = $responses[0]->getResponseProperties()[200]["{urn:ietf:params:xml:ns:caldav}calendar-data"]; + $response = json_decode($response, true); + if (json_last_error()) { + $this->fail('Json decoding error: ' . json_last_error_msg()); + } + $this->assertEquals( + [ + 'vcalendar', + [], + [ + [ + 'vevent', + [], + [], + ], + ], + ], + $response + ); + + } + + function testValidateICalendar() { + + $input = [ + 'vcalendar', + [], + [ + [ + 'vevent', + [ + ['uid', (object)[], 'text', 'foo'], + ['dtstart', (object)[], 'date', '2016-04-06'], + ], + [], + ], + ], + ]; + $input = json_encode($input); + $this->caldavPlugin->beforeWriteContent( + 'calendars/user1/foo/bar.ics', + $this->server->tree->getNodeForPath('calendars/user1/foo/bar.ics'), + $input, + $modified + ); + + + $expected = <<assertVObjectEqualsVObject( + $expected, + $input + ); + + } + +} diff --git a/vendor/sabre/dav/tests/Sabre/CalDAV/Notifications/CollectionTest.php b/vendor/sabre/dav/tests/Sabre/CalDAV/Notifications/CollectionTest.php new file mode 100644 index 000000000..6585f85c3 --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/CalDAV/Notifications/CollectionTest.php @@ -0,0 +1,85 @@ +principalUri = 'principals/user1'; + + $this->notification = new CalDAV\Xml\Notification\SystemStatus(1, '"1"'); + + $this->caldavBackend = new CalDAV\Backend\MockSharing([], [], [ + 'principals/user1' => [ + $this->notification + ] + ]); + + return new Collection($this->caldavBackend, $this->principalUri); + + } + + function testGetChildren() { + + $col = $this->getInstance(); + $this->assertEquals('notifications', $col->getName()); + + $this->assertEquals([ + new Node($this->caldavBackend, $this->principalUri, $this->notification) + ], $col->getChildren()); + + } + + function testGetOwner() { + + $col = $this->getInstance(); + $this->assertEquals('principals/user1', $col->getOwner()); + + } + + function testGetGroup() { + + $col = $this->getInstance(); + $this->assertNull($col->getGroup()); + + } + + function testGetACL() { + + $col = $this->getInstance(); + $expected = [ + [ + 'privilege' => '{DAV:}all', + 'principal' => '{DAV:}owner', + 'protected' => true, + ], + ]; + + $this->assertEquals($expected, $col->getACL()); + + } + + /** + * @expectedException \Sabre\DAV\Exception\Forbidden + */ + function testSetACL() { + + $col = $this->getInstance(); + $col->setACL([]); + + } + + function testGetSupportedPrivilegeSet() { + + $col = $this->getInstance(); + $this->assertNull($col->getSupportedPrivilegeSet()); + + } +} diff --git a/vendor/sabre/dav/tests/Sabre/CalDAV/Notifications/NodeTest.php b/vendor/sabre/dav/tests/Sabre/CalDAV/Notifications/NodeTest.php new file mode 100644 index 000000000..6c6e02da8 --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/CalDAV/Notifications/NodeTest.php @@ -0,0 +1,96 @@ +systemStatus = new CalDAV\Xml\Notification\SystemStatus(1, '"1"'); + + $this->caldavBackend = new CalDAV\Backend\MockSharing([], [], [ + 'principals/user1' => [ + $this->systemStatus + ] + ]); + + $node = new Node($this->caldavBackend, 'principals/user1', $this->systemStatus); + return $node; + + } + + function testGetId() { + + $node = $this->getInstance(); + $this->assertEquals($this->systemStatus->getId() . '.xml', $node->getName()); + + } + + function testGetEtag() { + + $node = $this->getInstance(); + $this->assertEquals('"1"', $node->getETag()); + + } + + function testGetNotificationType() { + + $node = $this->getInstance(); + $this->assertEquals($this->systemStatus, $node->getNotificationType()); + + } + + function testDelete() { + + $node = $this->getInstance(); + $node->delete(); + $this->assertEquals([], $this->caldavBackend->getNotificationsForPrincipal('principals/user1')); + + } + + function testGetGroup() { + + $node = $this->getInstance(); + $this->assertNull($node->getGroup()); + + } + + function testGetACL() { + + $node = $this->getInstance(); + $expected = [ + [ + 'privilege' => '{DAV:}all', + 'principal' => '{DAV:}owner', + 'protected' => true, + ], + ]; + + $this->assertEquals($expected, $node->getACL()); + + } + + /** + * @expectedException \Sabre\DAV\Exception\Forbidden + */ + function testSetACL() { + + $node = $this->getInstance(); + $node->setACL([]); + + } + + function testGetSupportedPrivilegeSet() { + + $node = $this->getInstance(); + $this->assertNull($node->getSupportedPrivilegeSet()); + + } +} diff --git a/vendor/sabre/dav/tests/Sabre/CalDAV/Notifications/PluginTest.php b/vendor/sabre/dav/tests/Sabre/CalDAV/Notifications/PluginTest.php new file mode 100644 index 000000000..73f256c98 --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/CalDAV/Notifications/PluginTest.php @@ -0,0 +1,168 @@ +caldavBackend = new CalDAV\Backend\MockSharing(); + $principalBackend = new DAVACL\PrincipalBackend\Mock(); + $calendars = new CalDAV\CalendarRoot($principalBackend, $this->caldavBackend); + $principals = new CalDAV\Principal\Collection($principalBackend); + + $root = new DAV\SimpleCollection('root'); + $root->addChild($calendars); + $root->addChild($principals); + + $this->server = new DAV\Server($root); + $this->server->sapi = new HTTP\SapiMock(); + $this->server->debugExceptions = true; + $this->server->setBaseUri('/'); + $this->plugin = new Plugin(); + $this->server->addPlugin($this->plugin); + + + // Adding ACL plugin + $aclPlugin = new DAVACL\Plugin(); + $aclPlugin->allowUnauthenticatedAccess = false; + $this->server->addPlugin($aclPlugin); + + // CalDAV is also required. + $this->server->addPlugin(new CalDAV\Plugin()); + // Adding Auth plugin, and ensuring that we are logged in. + $authBackend = new DAV\Auth\Backend\Mock(); + $authPlugin = new DAV\Auth\Plugin($authBackend); + $this->server->addPlugin($authPlugin); + + // This forces a login + $authPlugin->beforeMethod(new HTTP\Request(), new HTTP\Response()); + + $this->response = new HTTP\ResponseMock(); + $this->server->httpResponse = $this->response; + + } + + function testSimple() { + + $this->assertEquals([], $this->plugin->getFeatures()); + $this->assertEquals('notifications', $this->plugin->getPluginName()); + $this->assertEquals( + 'notifications', + $this->plugin->getPluginInfo()['name'] + ); + + } + + function testPrincipalProperties() { + + $httpRequest = new Request('GET', '/', ['Host' => 'sabredav.org']); + $this->server->httpRequest = $httpRequest; + + $props = $this->server->getPropertiesForPath('principals/admin', [ + '{' . Plugin::NS_CALENDARSERVER . '}notification-URL', + ]); + + $this->assertArrayHasKey(0, $props); + $this->assertArrayHasKey(200, $props[0]); + + $this->assertArrayHasKey('{' . Plugin::NS_CALENDARSERVER . '}notification-URL', $props[0][200]); + $prop = $props[0][200]['{' . Plugin::NS_CALENDARSERVER . '}notification-URL']; + $this->assertTrue($prop instanceof DAV\Xml\Property\Href); + $this->assertEquals('calendars/admin/notifications/', $prop->getHref()); + + } + + function testNotificationProperties() { + + $notification = new Node( + $this->caldavBackend, + 'principals/user1', + new SystemStatus('foo', '"1"') + ); + $propFind = new DAV\PropFind('calendars/user1/notifications', [ + '{' . Plugin::NS_CALENDARSERVER . '}notificationtype', + ]); + + $this->plugin->propFind($propFind, $notification); + + $this->assertEquals( + $notification->getNotificationType(), + $propFind->get('{' . Plugin::NS_CALENDARSERVER . '}notificationtype') + ); + + } + + function testNotificationGet() { + + $notification = new Node( + $this->caldavBackend, + 'principals/user1', + new SystemStatus('foo', '"1"') + ); + + $server = new DAV\Server([$notification]); + $caldav = new Plugin(); + + $server->httpRequest = new Request('GET', '/foo.xml'); + $httpResponse = new HTTP\ResponseMock(); + $server->httpResponse = $httpResponse; + + $server->addPlugin($caldav); + + $caldav->httpGet($server->httpRequest, $server->httpResponse); + + $this->assertEquals(200, $httpResponse->status); + $this->assertEquals([ + 'Content-Type' => ['application/xml'], + 'ETag' => ['"1"'], + ], $httpResponse->getHeaders()); + + $expected = +' + + + +'; + + $this->assertXmlStringEqualsXmlString($expected, $httpResponse->getBodyAsString()); + + } + + function testGETPassthrough() { + + $server = new DAV\Server(); + $caldav = new Plugin(); + + $httpResponse = new HTTP\ResponseMock(); + $server->httpResponse = $httpResponse; + + $server->addPlugin($caldav); + + $this->assertNull($caldav->httpGet(new HTTP\Request('GET', '/foozz'), $server->httpResponse)); + + } + + +} diff --git a/vendor/sabre/dav/tests/Sabre/CalDAV/PluginTest.php b/vendor/sabre/dav/tests/Sabre/CalDAV/PluginTest.php new file mode 100644 index 000000000..859f6aa0c --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/CalDAV/PluginTest.php @@ -0,0 +1,1086 @@ +caldavBackend = new Backend\Mock([ + [ + 'id' => 1, + 'uri' => 'UUID-123467', + 'principaluri' => 'principals/user1', + '{DAV:}displayname' => 'user1 calendar', + $caldavNS . 'calendar-description' => 'Calendar description', + '{http://apple.com/ns/ical/}calendar-order' => '1', + '{http://apple.com/ns/ical/}calendar-color' => '#FF0000', + $caldavNS . 'supported-calendar-component-set' => new Xml\Property\SupportedCalendarComponentSet(['VEVENT', 'VTODO']), + ], + [ + 'id' => 2, + 'uri' => 'UUID-123468', + 'principaluri' => 'principals/user1', + '{DAV:}displayname' => 'user1 calendar2', + $caldavNS . 'calendar-description' => 'Calendar description', + '{http://apple.com/ns/ical/}calendar-order' => '1', + '{http://apple.com/ns/ical/}calendar-color' => '#FF0000', + $caldavNS . 'supported-calendar-component-set' => new Xml\Property\SupportedCalendarComponentSet(['VEVENT', 'VTODO']), + ] + ], [ + 1 => [ + 'UUID-2345' => [ + 'calendardata' => TestUtil::getTestCalendarData(), + ] + ] + ]); + $principalBackend = new DAVACL\PrincipalBackend\Mock(); + $principalBackend->setGroupMemberSet('principals/admin/calendar-proxy-read', ['principals/user1']); + $principalBackend->setGroupMemberSet('principals/admin/calendar-proxy-write', ['principals/user1']); + $principalBackend->addPrincipal([ + 'uri' => 'principals/admin/calendar-proxy-read', + ]); + $principalBackend->addPrincipal([ + 'uri' => 'principals/admin/calendar-proxy-write', + ]); + + $calendars = new CalendarRoot($principalBackend, $this->caldavBackend); + $principals = new Principal\Collection($principalBackend); + + $root = new DAV\SimpleCollection('root'); + $root->addChild($calendars); + $root->addChild($principals); + + $this->server = new DAV\Server($root); + $this->server->sapi = new HTTP\SapiMock(); + $this->server->debugExceptions = true; + $this->server->setBaseUri('/'); + $this->plugin = new Plugin(); + $this->server->addPlugin($this->plugin); + + // Adding ACL plugin + $aclPlugin = new DAVACL\Plugin(); + $aclPlugin->allowUnauthenticatedAccess = false; + $this->server->addPlugin($aclPlugin); + + // Adding Auth plugin, and ensuring that we are logged in. + $authBackend = new DAV\Auth\Backend\Mock(); + $authBackend->setPrincipal('principals/user1'); + $authPlugin = new DAV\Auth\Plugin($authBackend); + $authPlugin->beforeMethod(new \Sabre\HTTP\Request(), new \Sabre\HTTP\Response()); + $this->server->addPlugin($authPlugin); + + // This forces a login + $authPlugin->beforeMethod(new HTTP\Request(), new HTTP\Response()); + + $this->response = new HTTP\ResponseMock(); + $this->server->httpResponse = $this->response; + + } + + function testSimple() { + + $this->assertEquals(['MKCALENDAR'], $this->plugin->getHTTPMethods('calendars/user1/randomnewcalendar')); + $this->assertEquals(['calendar-access', 'calendar-proxy'], $this->plugin->getFeatures()); + $this->assertEquals( + 'caldav', + $this->plugin->getPluginInfo()['name'] + ); + + } + + function testUnknownMethodPassThrough() { + + $request = new HTTP\Request('MKBREAKFAST', '/'); + + $this->server->httpRequest = $request; + $this->server->exec(); + + $this->assertEquals(501, $this->response->status, 'Incorrect status returned. Full response body:' . $this->response->body); + + } + + function testReportPassThrough() { + + $request = new HTTP\Request('REPORT', '/', ['Content-Type' => 'application/xml']); + $request->setBody(''); + + $this->server->httpRequest = $request; + $this->server->exec(); + + $this->assertEquals(415, $this->response->status); + + } + + function testMkCalendarBadLocation() { + + $request = new HTTP\Request('MKCALENDAR', '/blabla'); + + $body = ' + + + + Lisa\'s Events + Calendar restricted to events. + + + + + + + '; + + $request->setBody($body); + $this->server->httpRequest = $request; + $this->server->exec(); + + $this->assertEquals(403, $this->response->status); + + } + + function testMkCalendarNoParentNode() { + + $request = new HTTP\Request('MKCALENDAR', '/doesntexist/calendar'); + + $body = ' + + + + Lisa\'s Events + Calendar restricted to events. + + + + + + + '; + + $request->setBody($body); + $this->server->httpRequest = $request; + $this->server->exec(); + + $this->assertEquals(409, $this->response->status); + + } + + function testMkCalendarExistingCalendar() { + + $request = HTTP\Sapi::createFromServerArray([ + 'REQUEST_METHOD' => 'MKCALENDAR', + 'REQUEST_URI' => '/calendars/user1/UUID-123467', + ]); + + $body = ' + + + + Lisa\'s Events + Calendar restricted to events. + + + + + + + '; + + $request->setBody($body); + $this->server->httpRequest = $request; + $this->server->exec(); + + $this->assertEquals(405, $this->response->status); + + } + + function testMkCalendarSucceed() { + + $request = new HTTP\Request('MKCALENDAR', '/calendars/user1/NEWCALENDAR'); + + $timezone = 'BEGIN:VCALENDAR +PRODID:-//Example Corp.//CalDAV Client//EN +VERSION:2.0 +BEGIN:VTIMEZONE +TZID:US-Eastern +LAST-MODIFIED:19870101T000000Z +BEGIN:STANDARD +DTSTART:19671029T020000 +RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +TZNAME:Eastern Standard Time (US & Canada) +END:STANDARD +BEGIN:DAYLIGHT +DTSTART:19870405T020000 +RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=4 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +TZNAME:Eastern Daylight Time (US & Canada) +END:DAYLIGHT +END:VTIMEZONE +END:VCALENDAR'; + + $body = ' + + + + Lisa\'s Events + Calendar restricted to events. + + + + + + + '; + + $request->setBody($body); + $this->server->httpRequest = $request; + $this->server->exec(); + + $this->assertEquals(201, $this->response->status, 'Invalid response code received. Full response body: ' . $this->response->body); + + $calendars = $this->caldavBackend->getCalendarsForUser('principals/user1'); + $this->assertEquals(3, count($calendars)); + + $newCalendar = null; + foreach ($calendars as $calendar) { + if ($calendar['uri'] === 'NEWCALENDAR') { + $newCalendar = $calendar; + break; + } + } + + $this->assertInternalType('array', $newCalendar); + + $keys = [ + 'uri' => 'NEWCALENDAR', + 'id' => null, + '{urn:ietf:params:xml:ns:caldav}calendar-description' => 'Calendar restricted to events.', + '{urn:ietf:params:xml:ns:caldav}calendar-timezone' => $timezone, + '{DAV:}displayname' => 'Lisa\'s Events', + '{urn:ietf:params:xml:ns:caldav}supported-calendar-component-set' => null, + ]; + + foreach ($keys as $key => $value) { + + $this->assertArrayHasKey($key, $newCalendar); + + if (is_null($value)) continue; + $this->assertEquals($value, $newCalendar[$key]); + + } + $sccs = '{urn:ietf:params:xml:ns:caldav}supported-calendar-component-set'; + $this->assertTrue($newCalendar[$sccs] instanceof Xml\Property\SupportedCalendarComponentSet); + $this->assertEquals(['VEVENT'], $newCalendar[$sccs]->getValue()); + + } + + function testMkCalendarEmptyBodySucceed() { + + $request = new HTTP\Request('MKCALENDAR', '/calendars/user1/NEWCALENDAR'); + + $request->setBody(''); + $this->server->httpRequest = $request; + $this->server->exec(); + + $this->assertEquals(201, $this->response->status, 'Invalid response code received. Full response body: ' . $this->response->body); + + $calendars = $this->caldavBackend->getCalendarsForUser('principals/user1'); + $this->assertEquals(3, count($calendars)); + + $newCalendar = null; + foreach ($calendars as $calendar) { + if ($calendar['uri'] === 'NEWCALENDAR') { + $newCalendar = $calendar; + break; + } + } + + $this->assertInternalType('array', $newCalendar); + + $keys = [ + 'uri' => 'NEWCALENDAR', + 'id' => null, + '{urn:ietf:params:xml:ns:caldav}supported-calendar-component-set' => null, + ]; + + foreach ($keys as $key => $value) { + + $this->assertArrayHasKey($key, $newCalendar); + + if (is_null($value)) continue; + $this->assertEquals($value, $newCalendar[$key]); + + } + $sccs = '{urn:ietf:params:xml:ns:caldav}supported-calendar-component-set'; + $this->assertTrue($newCalendar[$sccs] instanceof Xml\Property\SupportedCalendarComponentSet); + $this->assertEquals(['VEVENT', 'VTODO'], $newCalendar[$sccs]->getValue()); + + } + + function testMkCalendarBadXml() { + + $request = new HTTP\Request('MKCALENDAR', '/blabla'); + $body = 'This is not xml'; + + $request->setBody($body); + $this->server->httpRequest = $request; + $this->server->exec(); + + $this->assertEquals(400, $this->response->status); + + } + + function testPrincipalProperties() { + + $httpRequest = new HTTP\Request('FOO', '/blabla', ['Host' => 'sabredav.org']); + $this->server->httpRequest = $httpRequest; + + $props = $this->server->getPropertiesForPath('/principals/user1', [ + '{' . Plugin::NS_CALDAV . '}calendar-home-set', + '{' . Plugin::NS_CALENDARSERVER . '}calendar-proxy-read-for', + '{' . Plugin::NS_CALENDARSERVER . '}calendar-proxy-write-for', + '{' . Plugin::NS_CALENDARSERVER . '}notification-URL', + '{' . Plugin::NS_CALENDARSERVER . '}email-address-set', + ]); + + $this->assertArrayHasKey(0, $props); + $this->assertArrayHasKey(200, $props[0]); + + + $this->assertArrayHasKey('{urn:ietf:params:xml:ns:caldav}calendar-home-set', $props[0][200]); + $prop = $props[0][200]['{urn:ietf:params:xml:ns:caldav}calendar-home-set']; + $this->assertInstanceOf('Sabre\\DAV\\Xml\\Property\\Href', $prop); + $this->assertEquals('calendars/user1/', $prop->getHref()); + + $this->assertArrayHasKey('{http://calendarserver.org/ns/}calendar-proxy-read-for', $props[0][200]); + $prop = $props[0][200]['{http://calendarserver.org/ns/}calendar-proxy-read-for']; + $this->assertInstanceOf('Sabre\\DAV\\Xml\\Property\\Href', $prop); + $this->assertEquals(['principals/admin/'], $prop->getHrefs()); + + $this->assertArrayHasKey('{http://calendarserver.org/ns/}calendar-proxy-write-for', $props[0][200]); + $prop = $props[0][200]['{http://calendarserver.org/ns/}calendar-proxy-write-for']; + $this->assertInstanceOf('Sabre\\DAV\\Xml\\Property\\Href', $prop); + $this->assertEquals(['principals/admin/'], $prop->getHrefs()); + + $this->assertArrayHasKey('{' . Plugin::NS_CALENDARSERVER . '}email-address-set', $props[0][200]); + $prop = $props[0][200]['{' . Plugin::NS_CALENDARSERVER . '}email-address-set']; + $this->assertInstanceOf('Sabre\\CalDAV\\Xml\\Property\\EmailAddressSet', $prop); + $this->assertEquals(['user1.sabredav@sabredav.org'], $prop->getValue()); + + } + + function testSupportedReportSetPropertyNonCalendar() { + + $props = $this->server->getPropertiesForPath('/calendars/user1', [ + '{DAV:}supported-report-set', + ]); + + $this->assertArrayHasKey(0, $props); + $this->assertArrayHasKey(200, $props[0]); + $this->assertArrayHasKey('{DAV:}supported-report-set', $props[0][200]); + + $prop = $props[0][200]['{DAV:}supported-report-set']; + + $this->assertInstanceOf('\\Sabre\\DAV\\Xml\\Property\\SupportedReportSet', $prop); + $value = [ + '{DAV:}expand-property', + '{DAV:}principal-match', + '{DAV:}principal-property-search', + '{DAV:}principal-search-property-set', + ]; + $this->assertEquals($value, $prop->getValue()); + + } + + /** + * @depends testSupportedReportSetPropertyNonCalendar + */ + function testSupportedReportSetProperty() { + + $props = $this->server->getPropertiesForPath('/calendars/user1/UUID-123467', [ + '{DAV:}supported-report-set', + ]); + + $this->assertArrayHasKey(0, $props); + $this->assertArrayHasKey(200, $props[0]); + $this->assertArrayHasKey('{DAV:}supported-report-set', $props[0][200]); + + $prop = $props[0][200]['{DAV:}supported-report-set']; + + $this->assertInstanceOf('\\Sabre\\DAV\\Xml\\Property\\SupportedReportSet', $prop); + $value = [ + '{urn:ietf:params:xml:ns:caldav}calendar-multiget', + '{urn:ietf:params:xml:ns:caldav}calendar-query', + '{urn:ietf:params:xml:ns:caldav}free-busy-query', + '{DAV:}expand-property', + '{DAV:}principal-match', + '{DAV:}principal-property-search', + '{DAV:}principal-search-property-set' + ]; + $this->assertEquals($value, $prop->getValue()); + + } + + function testSupportedReportSetUserCalendars() { + + $this->server->addPlugin(new \Sabre\DAV\Sync\Plugin()); + + $props = $this->server->getPropertiesForPath('/calendars/user1', [ + '{DAV:}supported-report-set', + ]); + + $this->assertArrayHasKey(0, $props); + $this->assertArrayHasKey(200, $props[0]); + $this->assertArrayHasKey('{DAV:}supported-report-set', $props[0][200]); + + $prop = $props[0][200]['{DAV:}supported-report-set']; + + $this->assertInstanceOf('\\Sabre\\DAV\\Xml\\Property\\SupportedReportSet', $prop); + $value = [ + '{DAV:}sync-collection', + '{DAV:}expand-property', + '{DAV:}principal-match', + '{DAV:}principal-property-search', + '{DAV:}principal-search-property-set', + ]; + $this->assertEquals($value, $prop->getValue()); + + } + + /** + * @depends testSupportedReportSetProperty + */ + function testCalendarMultiGetReport() { + + $body = + '' . + '' . + '' . + ' ' . + ' ' . + '' . + '/calendars/user1/UUID-123467/UUID-2345' . + ''; + + $request = new HTTP\Request('REPORT', '/calendars/user1', ['Depth' => '1']); + $request->setBody($body); + + $this->server->httpRequest = $request; + $this->server->exec(); + + $this->assertEquals(207, $this->response->status, 'Invalid HTTP status received. Full response body'); + + $expectedIcal = TestUtil::getTestCalendarData(); + + $expected = << + + + /calendars/user1/UUID-123467/UUID-2345 + + + $expectedIcal + "e207e33c10e5fb9c12cfb35b5d9116e1" + + HTTP/1.1 200 OK + + + +XML; + + $this->assertXmlStringEqualsXmlString($expected, $this->response->getBodyAsString()); + + } + + /** + * @depends testCalendarMultiGetReport + */ + function testCalendarMultiGetReportExpand() { + + $body = + '' . + '' . + '' . + ' ' . + ' ' . + ' ' . + ' ' . + '' . + '/calendars/user1/UUID-123467/UUID-2345' . + ''; + + $request = new HTTP\Request('REPORT', '/calendars/user1', ['Depth' => '1']); + $request->setBody($body); + + $this->server->httpRequest = $request; + $this->server->exec(); + + $this->assertEquals(207, $this->response->status, 'Invalid HTTP status received. Full response body: ' . $this->response->body); + + $expectedIcal = TestUtil::getTestCalendarData(); + $expectedIcal = \Sabre\VObject\Reader::read($expectedIcal); + $expectedIcal = $expectedIcal->expand( + new DateTime('2011-01-01 00:00:00', new DateTimeZone('UTC')), + new DateTime('2011-12-31 23:59:59', new DateTimeZone('UTC')) + ); + $expectedIcal = str_replace("\r\n", " \n", $expectedIcal->serialize()); + + $expected = << + + + /calendars/user1/UUID-123467/UUID-2345 + + + $expectedIcal + "e207e33c10e5fb9c12cfb35b5d9116e1" + + HTTP/1.1 200 OK + + + +XML; + + $this->assertXmlStringEqualsXmlString($expected, $this->response->getBodyAsString()); + + } + + /** + * @depends testSupportedReportSetProperty + * @depends testCalendarMultiGetReport + */ + function testCalendarQueryReport() { + + $body = + '' . + '' . + '' . + ' ' . + ' ' . + ' ' . + ' ' . + '' . + '' . + ' ' . + ' ' . + ' ' . + '' . + ''; + + $request = new HTTP\Request('REPORT', '/calendars/user1/UUID-123467', ['Depth' => '1']); + $request->setBody($body); + + $this->server->httpRequest = $request; + $this->server->exec(); + + $this->assertEquals(207, $this->response->status, 'Received an unexpected status. Full response body: ' . $this->response->body); + + $expectedIcal = TestUtil::getTestCalendarData(); + $expectedIcal = \Sabre\VObject\Reader::read($expectedIcal); + $expectedIcal = $expectedIcal->expand( + new DateTime('2000-01-01 00:00:00', new DateTimeZone('UTC')), + new DateTime('2010-12-31 23:59:59', new DateTimeZone('UTC')) + ); + $expectedIcal = str_replace("\r\n", " \n", $expectedIcal->serialize()); + + $expected = << + + + /calendars/user1/UUID-123467/UUID-2345 + + + $expectedIcal + "e207e33c10e5fb9c12cfb35b5d9116e1" + + HTTP/1.1 200 OK + + + +XML; + + $this->assertXmlStringEqualsXmlString($expected, $this->response->getBodyAsString()); + + } + + /** + * @depends testSupportedReportSetProperty + * @depends testCalendarMultiGetReport + */ + function testCalendarQueryReportWindowsPhone() { + + $body = + '' . + '' . + '' . + ' ' . + ' ' . + ' ' . + ' ' . + '' . + '' . + ' ' . + ' ' . + ' ' . + '' . + ''; + + $request = new HTTP\Request('REPORT', '/calendars/user1/UUID-123467', [ + 'Depth' => '0', + 'User-Agent' => 'MSFT-WP/8.10.14219 (gzip)', + ]); + + $request->setBody($body); + + $this->server->httpRequest = $request; + $this->server->exec(); + + $this->assertEquals(207, $this->response->status, 'Received an unexpected status. Full response body: ' . $this->response->body); + + $expectedIcal = TestUtil::getTestCalendarData(); + $expectedIcal = \Sabre\VObject\Reader::read($expectedIcal); + $expectedIcal = $expectedIcal->expand( + new DateTime('2000-01-01 00:00:00', new DateTimeZone('UTC')), + new DateTime('2010-12-31 23:59:59', new DateTimeZone('UTC')) + ); + $expectedIcal = str_replace("\r\n", " \n", $expectedIcal->serialize()); + + $expected = << + + + /calendars/user1/UUID-123467/UUID-2345 + + + $expectedIcal + "e207e33c10e5fb9c12cfb35b5d9116e1" + + HTTP/1.1 200 OK + + + +XML; + + $this->assertXmlStringEqualsXmlString($expected, $this->response->getBodyAsString()); + + } + + /** + * @depends testSupportedReportSetProperty + * @depends testCalendarMultiGetReport + */ + function testCalendarQueryReportBadDepth() { + + $body = + '' . + '' . + '' . + ' ' . + ' ' . + ' ' . + ' ' . + '' . + '' . + ' ' . + ' ' . + ' ' . + '' . + ''; + + $request = new HTTP\Request('REPORT', '/calendars/user1/UUID-123467', [ + 'Depth' => '0', + ]); + $request->setBody($body); + + $this->server->httpRequest = $request; + $this->server->exec(); + + $this->assertEquals(400, $this->response->status, 'Received an unexpected status. Full response body: ' . $this->response->body); + + } + + /** + * @depends testCalendarQueryReport + */ + function testCalendarQueryReportNoCalData() { + + $body = + '' . + '' . + '' . + ' ' . + '' . + '' . + ' ' . + ' ' . + ' ' . + '' . + ''; + + $request = new HTTP\Request('REPORT', '/calendars/user1/UUID-123467', [ + 'Depth' => '1', + ]); + $request->setBody($body); + + $this->server->httpRequest = $request; + $this->server->exec(); + + $this->assertEquals(207, $this->response->status, 'Received an unexpected status. Full response body: ' . $this->response->body); + + $expected = << + + + /calendars/user1/UUID-123467/UUID-2345 + + + "e207e33c10e5fb9c12cfb35b5d9116e1" + + HTTP/1.1 200 OK + + + +XML; + + $this->assertXmlStringEqualsXmlString($expected, $this->response->getBodyAsString()); + + } + + /** + * @depends testCalendarQueryReport + */ + function testCalendarQueryReportNoFilters() { + + $body = + '' . + '' . + '' . + ' ' . + ' ' . + '' . + ''; + + $request = new HTTP\Request('REPORT', '/calendars/user1/UUID-123467'); + $request->setBody($body); + + $this->server->httpRequest = $request; + $this->server->exec(); + + $this->assertEquals(400, $this->response->status, 'Received an unexpected status. Full response body: ' . $this->response->body); + + } + + /** + * @depends testSupportedReportSetProperty + * @depends testCalendarMultiGetReport + */ + function testCalendarQueryReport1Object() { + + $body = + '' . + '' . + '' . + ' ' . + ' ' . + ' ' . + ' ' . + '' . + '' . + ' ' . + ' ' . + ' ' . + '' . + ''; + + $request = new HTTP\Request('REPORT', '/calendars/user1/UUID-123467/UUID-2345', ['Depth' => '0']); + $request->setBody($body); + + $this->server->httpRequest = $request; + $this->server->exec(); + + $this->assertEquals(207, $this->response->status, 'Received an unexpected status. Full response body: ' . $this->response->body); + + $expectedIcal = TestUtil::getTestCalendarData(); + $expectedIcal = \Sabre\VObject\Reader::read($expectedIcal); + $expectedIcal = $expectedIcal->expand( + new DateTime('2000-01-01 00:00:00', new DateTimeZone('UTC')), + new DateTime('2010-12-31 23:59:59', new DateTimeZone('UTC')) + ); + $expectedIcal = str_replace("\r\n", " \n", $expectedIcal->serialize()); + + $expected = << + + + /calendars/user1/UUID-123467/UUID-2345 + + + $expectedIcal + "e207e33c10e5fb9c12cfb35b5d9116e1" + + HTTP/1.1 200 OK + + + +XML; + + $this->assertXmlStringEqualsXmlString($expected, $this->response->getBodyAsString()); + + } + + /** + * @depends testSupportedReportSetProperty + * @depends testCalendarMultiGetReport + */ + function testCalendarQueryReport1ObjectNoCalData() { + + $body = + '' . + '' . + '' . + ' ' . + '' . + '' . + ' ' . + ' ' . + ' ' . + '' . + ''; + + $request = new HTTP\Request('REPORT', '/calendars/user1/UUID-123467/UUID-2345', ['Depth' => '0']); + $request->setBody($body); + + $this->server->httpRequest = $request; + $this->server->exec(); + + $this->assertEquals(207, $this->response->status, 'Received an unexpected status. Full response body: ' . $this->response->body); + + $expected = << + + + /calendars/user1/UUID-123467/UUID-2345 + + + "e207e33c10e5fb9c12cfb35b5d9116e1" + + HTTP/1.1 200 OK + + + +XML; + + $this->assertXmlStringEqualsXmlString($expected, $this->response->getBodyAsString()); + + } + + function testHTMLActionsPanel() { + + $output = ''; + $r = $this->server->emit('onHTMLActionsPanel', [$this->server->tree->getNodeForPath('calendars/user1'), &$output]); + $this->assertFalse($r); + + $this->assertTrue(!!strpos($output, 'Display name')); + + } + + /** + * @depends testCalendarMultiGetReport + */ + function testCalendarMultiGetReportNoEnd() { + + $body = + '' . + '' . + '' . + ' ' . + ' ' . + ' ' . + ' ' . + '' . + '/calendars/user1/UUID-123467/UUID-2345' . + ''; + + $request = new HTTP\Request('REPORT', '/calendars/user1', ['Depth' => '1']); + $request->setBody($body); + + $this->server->httpRequest = $request; + $this->server->exec(); + + $this->assertEquals(400, $this->response->status, 'Invalid HTTP status received. Full response body: ' . $this->response->body); + + } + + /** + * @depends testCalendarMultiGetReport + */ + function testCalendarMultiGetReportNoStart() { + + $body = + '' . + '' . + '' . + ' ' . + ' ' . + ' ' . + ' ' . + '' . + '/calendars/user1/UUID-123467/UUID-2345' . + ''; + + $request = new HTTP\Request('REPORT', '/calendars/user1', ['Depth' => '1']); + $request->setBody($body); + + $this->server->httpRequest = $request; + $this->server->exec(); + + $this->assertEquals(400, $this->response->status, 'Invalid HTTP status received. Full response body: ' . $this->response->body); + + } + + /** + * @depends testCalendarMultiGetReport + */ + function testCalendarMultiGetReportEndBeforeStart() { + + $body = + '' . + '' . + '' . + ' ' . + ' ' . + ' ' . + ' ' . + '' . + '/calendars/user1/UUID-123467/UUID-2345' . + ''; + + $request = new HTTP\Request('REPORT', '/calendars/user1', ['Depth' => '1']); + $request->setBody($body); + + $this->server->httpRequest = $request; + $this->server->exec(); + + $this->assertEquals(400, $this->response->status, 'Invalid HTTP status received. Full response body: ' . $this->response->body); + + } + + /** + * @depends testSupportedReportSetPropertyNonCalendar + */ + function testCalendarProperties() { + + $ns = '{urn:ietf:params:xml:ns:caldav}'; + $props = $this->server->getProperties('calendars/user1/UUID-123467', [ + $ns . 'max-resource-size', + $ns . 'supported-calendar-data', + $ns . 'supported-collation-set', + ]); + + $this->assertEquals([ + $ns . 'max-resource-size' => 10000000, + $ns . 'supported-calendar-data' => new Xml\Property\SupportedCalendarData(), + $ns . 'supported-collation-set' => new Xml\Property\SupportedCollationSet(), + ], $props); + + } + +} diff --git a/vendor/sabre/dav/tests/Sabre/CalDAV/Principal/CollectionTest.php b/vendor/sabre/dav/tests/Sabre/CalDAV/Principal/CollectionTest.php new file mode 100644 index 000000000..23c248825 --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/CalDAV/Principal/CollectionTest.php @@ -0,0 +1,20 @@ +getChildForPrincipal([ + 'uri' => 'principals/admin', + ]); + $this->assertInstanceOf('Sabre\\CalDAV\\Principal\\User', $r); + + } + +} diff --git a/vendor/sabre/dav/tests/Sabre/CalDAV/Principal/ProxyReadTest.php b/vendor/sabre/dav/tests/Sabre/CalDAV/Principal/ProxyReadTest.php new file mode 100644 index 000000000..fe07f0131 --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/CalDAV/Principal/ProxyReadTest.php @@ -0,0 +1,102 @@ + 'principal/user', + ]); + $this->backend = $backend; + return $principal; + + } + + function testGetName() { + + $i = $this->getInstance(); + $this->assertEquals('calendar-proxy-read', $i->getName()); + + } + function testGetDisplayName() { + + $i = $this->getInstance(); + $this->assertEquals('calendar-proxy-read', $i->getDisplayName()); + + } + + function testGetLastModified() { + + $i = $this->getInstance(); + $this->assertNull($i->getLastModified()); + + } + + /** + * @expectedException Sabre\DAV\Exception\Forbidden + */ + function testDelete() { + + $i = $this->getInstance(); + $i->delete(); + + } + + /** + * @expectedException Sabre\DAV\Exception\Forbidden + */ + function testSetName() { + + $i = $this->getInstance(); + $i->setName('foo'); + + } + + function testGetAlternateUriSet() { + + $i = $this->getInstance(); + $this->assertEquals([], $i->getAlternateUriSet()); + + } + + function testGetPrincipalUri() { + + $i = $this->getInstance(); + $this->assertEquals('principal/user/calendar-proxy-read', $i->getPrincipalUrl()); + + } + + function testGetGroupMemberSet() { + + $i = $this->getInstance(); + $this->assertEquals([], $i->getGroupMemberSet()); + + } + + function testGetGroupMembership() { + + $i = $this->getInstance(); + $this->assertEquals([], $i->getGroupMembership()); + + } + + function testSetGroupMemberSet() { + + $i = $this->getInstance(); + $i->setGroupMemberSet(['principals/foo']); + + $expected = [ + $i->getPrincipalUrl() => ['principals/foo'] + ]; + + $this->assertEquals($expected, $this->backend->groupMembers); + + } +} diff --git a/vendor/sabre/dav/tests/Sabre/CalDAV/Principal/ProxyWriteTest.php b/vendor/sabre/dav/tests/Sabre/CalDAV/Principal/ProxyWriteTest.php new file mode 100644 index 000000000..6cdb9b30e --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/CalDAV/Principal/ProxyWriteTest.php @@ -0,0 +1,40 @@ + 'principal/user', + ]); + $this->backend = $backend; + return $principal; + + } + + function testGetName() { + + $i = $this->getInstance(); + $this->assertEquals('calendar-proxy-write', $i->getName()); + + } + function testGetDisplayName() { + + $i = $this->getInstance(); + $this->assertEquals('calendar-proxy-write', $i->getDisplayName()); + + } + + function testGetPrincipalUri() { + + $i = $this->getInstance(); + $this->assertEquals('principal/user/calendar-proxy-write', $i->getPrincipalUrl()); + + } + +} diff --git a/vendor/sabre/dav/tests/Sabre/CalDAV/Principal/UserTest.php b/vendor/sabre/dav/tests/Sabre/CalDAV/Principal/UserTest.php new file mode 100644 index 000000000..420bb3b1a --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/CalDAV/Principal/UserTest.php @@ -0,0 +1,127 @@ +addPrincipal([ + 'uri' => 'principals/user/calendar-proxy-read', + ]); + $backend->addPrincipal([ + 'uri' => 'principals/user/calendar-proxy-write', + ]); + $backend->addPrincipal([ + 'uri' => 'principals/user/random', + ]); + return new User($backend, [ + 'uri' => 'principals/user', + ]); + + } + + /** + * @expectedException Sabre\DAV\Exception\Forbidden + */ + function testCreateFile() { + + $u = $this->getInstance(); + $u->createFile('test'); + + } + + /** + * @expectedException Sabre\DAV\Exception\Forbidden + */ + function testCreateDirectory() { + + $u = $this->getInstance(); + $u->createDirectory('test'); + + } + + function testGetChildProxyRead() { + + $u = $this->getInstance(); + $child = $u->getChild('calendar-proxy-read'); + $this->assertInstanceOf('Sabre\\CalDAV\\Principal\\ProxyRead', $child); + + } + + function testGetChildProxyWrite() { + + $u = $this->getInstance(); + $child = $u->getChild('calendar-proxy-write'); + $this->assertInstanceOf('Sabre\\CalDAV\\Principal\\ProxyWrite', $child); + + } + + /** + * @expectedException Sabre\DAV\Exception\NotFound + */ + function testGetChildNotFound() { + + $u = $this->getInstance(); + $child = $u->getChild('foo'); + + } + + /** + * @expectedException Sabre\DAV\Exception\NotFound + */ + function testGetChildNotFound2() { + + $u = $this->getInstance(); + $child = $u->getChild('random'); + + } + + function testGetChildren() { + + $u = $this->getInstance(); + $children = $u->getChildren(); + $this->assertEquals(2, count($children)); + $this->assertInstanceOf('Sabre\\CalDAV\\Principal\\ProxyRead', $children[0]); + $this->assertInstanceOf('Sabre\\CalDAV\\Principal\\ProxyWrite', $children[1]); + + } + + function testChildExist() { + + $u = $this->getInstance(); + $this->assertTrue($u->childExists('calendar-proxy-read')); + $this->assertTrue($u->childExists('calendar-proxy-write')); + $this->assertFalse($u->childExists('foo')); + + } + + function testGetACL() { + + $expected = [ + [ + 'privilege' => '{DAV:}all', + 'principal' => '{DAV:}owner', + 'protected' => true, + ], + [ + 'privilege' => '{DAV:}read', + 'principal' => 'principals/user/calendar-proxy-read', + 'protected' => true, + ], + [ + 'privilege' => '{DAV:}read', + 'principal' => 'principals/user/calendar-proxy-write', + 'protected' => true, + ], + ]; + + $u = $this->getInstance(); + $this->assertEquals($expected, $u->getACL()); + + } + +} diff --git a/vendor/sabre/dav/tests/Sabre/CalDAV/Schedule/DeliverNewEventTest.php b/vendor/sabre/dav/tests/Sabre/CalDAV/Schedule/DeliverNewEventTest.php new file mode 100644 index 000000000..79e323f5c --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/CalDAV/Schedule/DeliverNewEventTest.php @@ -0,0 +1,92 @@ +caldavBackend->createCalendar( + 'principals/user1', + 'default', + [ + + ] + ); + $this->caldavBackend->createCalendar( + 'principals/user2', + 'default', + [ + + ] + ); + + } + + function testDelivery() { + + $request = new Request('PUT', '/calendars/user1/default/foo.ics'); + $request->setBody(<<server->on('schedule', function($message) use (&$messages) { + $messages[] = $message; + }); + + $response = $this->request($request); + + $this->assertEquals(201, $response->getStatus(), 'Incorrect status code received. Response body:' . $response->getBodyAsString()); + + $result = $this->request(new Request('GET', '/calendars/user1/default/foo.ics'))->getBody(); + $resultVObj = VObject\Reader::read($result); + + $this->assertEquals( + '1.2', + $resultVObj->VEVENT->ATTENDEE[1]['SCHEDULE-STATUS']->getValue() + ); + + $this->assertEquals(1, count($messages)); + $message = $messages[0]; + + $this->assertInstanceOf('\Sabre\VObject\ITip\Message', $message); + $this->assertEquals('mailto:user2.sabredav@sabredav.org', $message->recipient); + $this->assertEquals('Roxy Kesh', $message->recipientName); + $this->assertEquals('mailto:user1.sabredav@sabredav.org', $message->sender); + $this->assertEquals('Administrator', $message->senderName); + $this->assertEquals('REQUEST', $message->method); + + $this->assertEquals('REQUEST', $message->message->METHOD->getValue()); + + } + +} diff --git a/vendor/sabre/dav/tests/Sabre/CalDAV/Schedule/FreeBusyRequestTest.php b/vendor/sabre/dav/tests/Sabre/CalDAV/Schedule/FreeBusyRequestTest.php new file mode 100644 index 000000000..0e0b609a1 --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/CalDAV/Schedule/FreeBusyRequestTest.php @@ -0,0 +1,611 @@ + 'principals/user2', + 'id' => 1, + 'uri' => 'calendar1', + $caldavNS . 'calendar-timezone' => "BEGIN:VCALENDAR\r\nBEGIN:VTIMEZONE\r\nTZID:Europe/Berlin\r\nEND:VTIMEZONE\r\nEND:VCALENDAR", + ], + [ + 'principaluri' => 'principals/user2', + 'id' => 2, + 'uri' => 'calendar2', + $caldavNS . 'schedule-calendar-transp' => new ScheduleCalendarTransp(ScheduleCalendarTransp::TRANSPARENT), + ], + ]; + $calendarobjects = [ + 1 => ['1.ics' => [ + 'uri' => '1.ics', + 'calendardata' => 'BEGIN:VCALENDAR +BEGIN:VEVENT +DTSTART:20110101T130000 +DURATION:PT1H +END:VEVENT +END:VCALENDAR', + 'calendarid' => 1, + ]], + 2 => ['2.ics' => [ + 'uri' => '2.ics', + 'calendardata' => 'BEGIN:VCALENDAR +BEGIN:VEVENT +DTSTART:20110101T080000 +DURATION:PT1H +END:VEVENT +END:VCALENDAR', + 'calendarid' => 2, + ]] + + ]; + + $principalBackend = new DAVACL\PrincipalBackend\Mock(); + $this->caldavBackend = new CalDAV\Backend\MockScheduling($calendars, $calendarobjects); + + $tree = [ + new DAVACL\PrincipalCollection($principalBackend), + new CalDAV\CalendarRoot($principalBackend, $this->caldavBackend), + ]; + + $this->request = HTTP\Sapi::createFromServerArray([ + 'CONTENT_TYPE' => 'text/calendar', + ]); + $this->response = new HTTP\ResponseMock(); + + $this->server = new DAV\Server($tree); + $this->server->httpRequest = $this->request; + $this->server->httpResponse = $this->response; + + $this->aclPlugin = new DAVACL\Plugin(); + $this->aclPlugin->allowUnauthenticatedAccess = false; + $this->server->addPlugin($this->aclPlugin); + + $authBackend = new DAV\Auth\Backend\Mock(); + $authBackend->setPrincipal('principals/user1'); + $this->authPlugin = new DAV\Auth\Plugin($authBackend); + // Forcing authentication to work. + $this->authPlugin->beforeMethod($this->request, $this->response); + $this->server->addPlugin($this->authPlugin); + + // CalDAV plugin + $this->plugin = new CalDAV\Plugin(); + $this->server->addPlugin($this->plugin); + + // Scheduling plugin + $this->plugin = new Plugin(); + $this->server->addPlugin($this->plugin); + + } + + function testWrongContentType() { + + $this->server->httpRequest = new HTTP\Request( + 'POST', + '/calendars/user1/outbox', + ['Content-Type' => 'text/plain'] + ); + + $this->assertNull( + $this->plugin->httpPost($this->server->httpRequest, $this->server->httpResponse) + ); + + } + + function testNotFound() { + + $this->server->httpRequest = new HTTP\Request( + 'POST', + '/calendars/user1/blabla', + ['Content-Type' => 'text/calendar'] + ); + + $this->assertNull( + $this->plugin->httpPost($this->server->httpRequest, $this->server->httpResponse) + ); + + } + + function testNotOutbox() { + + $this->server->httpRequest = new HTTP\Request( + 'POST', + '/calendars/user1/inbox', + ['Content-Type' => 'text/calendar'] + ); + + $this->assertNull( + $this->plugin->httpPost($this->server->httpRequest, $this->server->httpResponse) + ); + + } + + /** + * @expectedException Sabre\DAV\Exception\BadRequest + */ + function testNoItipMethod() { + + $this->server->httpRequest = new HTTP\Request( + 'POST', + '/calendars/user1/outbox', + ['Content-Type' => 'text/calendar'] + ); + + $body = <<server->httpRequest->setBody($body); + $this->plugin->httpPost($this->server->httpRequest, $this->server->httpResponse); + + } + + /** + * @expectedException \Sabre\DAV\Exception\NotImplemented + */ + function testNoVFreeBusy() { + + $this->server->httpRequest = new HTTP\Request( + 'POST', + '/calendars/user1/outbox', + ['Content-Type' => 'text/calendar'] + ); + + $body = <<server->httpRequest->setBody($body); + $this->plugin->httpPost($this->server->httpRequest, $this->server->httpResponse); + + } + + /** + * @expectedException Sabre\DAV\Exception\Forbidden + */ + function testIncorrectOrganizer() { + + $this->server->httpRequest = new HTTP\Request( + 'POST', + '/calendars/user1/outbox', + ['Content-Type' => 'text/calendar'] + ); + + + $body = <<server->httpRequest->setBody($body); + $this->plugin->httpPost($this->server->httpRequest, $this->server->httpResponse); + + } + + /** + * @expectedException Sabre\DAV\Exception\BadRequest + */ + function testNoAttendees() { + + $this->server->httpRequest = new HTTP\Request( + 'POST', + '/calendars/user1/outbox', + ['Content-Type' => 'text/calendar'] + ); + + $body = <<server->httpRequest->setBody($body); + $this->plugin->httpPost($this->server->httpRequest, $this->server->httpResponse); + + } + + /** + * @expectedException Sabre\DAV\Exception\BadRequest + */ + function testNoDTStart() { + + $this->server->httpRequest = new HTTP\Request( + 'POST', + '/calendars/user1/outbox', + ['Content-Type' => 'text/calendar'] + ); + + $body = <<server->httpRequest->setBody($body); + $this->plugin->httpPost($this->server->httpRequest, $this->server->httpResponse); + + } + + function testSucceed() { + + $this->server->httpRequest = new HTTP\Request( + 'POST', + '/calendars/user1/outbox', + ['Content-Type' => 'text/calendar'] + ); + + $body = <<server->httpRequest->setBody($body); + + // Lazily making the current principal an admin. + $this->aclPlugin->adminPrincipals[] = 'principals/user1'; + + $this->assertFalse( + $this->plugin->httpPost($this->server->httpRequest, $this->response) + ); + + $this->assertEquals(200, $this->response->status); + $this->assertEquals([ + 'Content-Type' => ['application/xml'], + ], $this->response->getHeaders()); + + $strings = [ + 'mailto:user2.sabredav@sabredav.org', + 'mailto:user3.sabredav@sabredav.org', + '2.0;Success', + '3.7;Could not find principal', + 'FREEBUSY:20110101T120000Z/20110101T130000Z', + ]; + + foreach ($strings as $string) { + $this->assertTrue( + strpos($this->response->body, $string) !== false, + 'The response body did not contain: ' . $string . 'Full response: ' . $this->response->body + ); + } + + $this->assertTrue( + strpos($this->response->body, 'FREEBUSY;FBTYPE=BUSY:20110101T080000Z/20110101T090000Z') == false, + 'The response body did contain free busy info from a transparent calendar.' + ); + + } + + /** + * Testing if the freebusy request still works, even if there are no + * calendars in the target users' account. + */ + function testSucceedNoCalendars() { + + // Deleting calendars + $this->caldavBackend->deleteCalendar(1); + $this->caldavBackend->deleteCalendar(2); + + $this->server->httpRequest = new HTTP\Request( + 'POST', + '/calendars/user1/outbox', + ['Content-Type' => 'text/calendar'] + ); + + $body = <<server->httpRequest->setBody($body); + + // Lazily making the current principal an admin. + $this->aclPlugin->adminPrincipals[] = 'principals/user1'; + + $this->assertFalse( + $this->plugin->httpPost($this->server->httpRequest, $this->response) + ); + + $this->assertEquals(200, $this->response->status); + $this->assertEquals([ + 'Content-Type' => ['application/xml'], + ], $this->response->getHeaders()); + + $strings = [ + 'mailto:user2.sabredav@sabredav.org', + '2.0;Success', + ]; + + foreach ($strings as $string) { + $this->assertTrue( + strpos($this->response->body, $string) !== false, + 'The response body did not contain: ' . $string . 'Full response: ' . $this->response->body + ); + } + + } + + function testNoCalendarHomeFound() { + + $this->server->httpRequest = new HTTP\Request( + 'POST', + '/calendars/user1/outbox', + ['Content-Type' => 'text/calendar'] + ); + + $body = <<server->httpRequest->setBody($body); + + // Lazily making the current principal an admin. + $this->aclPlugin->adminPrincipals[] = 'principals/user1'; + + // Removing the calendar home + $this->server->on('propFind', function(DAV\PropFind $propFind) { + + $propFind->set('{' . Plugin::NS_CALDAV . '}calendar-home-set', null, 403); + + }); + + $this->assertFalse( + $this->plugin->httpPost($this->server->httpRequest, $this->response) + ); + + $this->assertEquals(200, $this->response->status); + $this->assertEquals([ + 'Content-Type' => ['application/xml'], + ], $this->response->getHeaders()); + + $strings = [ + 'mailto:user2.sabredav@sabredav.org', + '3.7;No calendar-home-set property found', + ]; + + foreach ($strings as $string) { + $this->assertTrue( + strpos($this->response->body, $string) !== false, + 'The response body did not contain: ' . $string . 'Full response: ' . $this->response->body + ); + } + + } + + function testNoInboxFound() { + + $this->server->httpRequest = new HTTP\Request( + 'POST', + '/calendars/user1/outbox', + ['Content-Type' => 'text/calendar'] + ); + + $body = <<server->httpRequest->setBody($body); + + // Lazily making the current principal an admin. + $this->aclPlugin->adminPrincipals[] = 'principals/user1'; + + // Removing the inbox + $this->server->on('propFind', function(DAV\PropFind $propFind) { + + $propFind->set('{' . Plugin::NS_CALDAV . '}schedule-inbox-URL', null, 403); + + }); + + $this->assertFalse( + $this->plugin->httpPost($this->server->httpRequest, $this->response) + ); + + $this->assertEquals(200, $this->response->status); + $this->assertEquals([ + 'Content-Type' => ['application/xml'], + ], $this->response->getHeaders()); + + $strings = [ + 'mailto:user2.sabredav@sabredav.org', + '3.7;No schedule-inbox-URL property found', + ]; + + foreach ($strings as $string) { + $this->assertTrue( + strpos($this->response->body, $string) !== false, + 'The response body did not contain: ' . $string . 'Full response: ' . $this->response->body + ); + } + + } + + function testSucceedUseVAVAILABILITY() { + + $this->server->httpRequest = new HTTP\Request( + 'POST', + '/calendars/user1/outbox', + ['Content-Type' => 'text/calendar'] + ); + + $body = <<server->httpRequest->setBody($body); + + // Lazily making the current principal an admin. + $this->aclPlugin->adminPrincipals[] = 'principals/user1'; + + // Adding VAVAILABILITY manually + $this->server->on('propFind', function(DAV\PropFind $propFind) { + + $propFind->handle('{' . Plugin::NS_CALDAV . '}calendar-availability', function() { + + $avail = <<assertFalse( + $this->plugin->httpPost($this->server->httpRequest, $this->response) + ); + + $this->assertEquals(200, $this->response->status); + $this->assertEquals([ + 'Content-Type' => ['application/xml'], + ], $this->response->getHeaders()); + + $strings = [ + 'mailto:user2.sabredav@sabredav.org', + '2.0;Success', + 'FREEBUSY;FBTYPE=BUSY-UNAVAILABLE:20110101T080000Z/20110101T090000Z', + 'FREEBUSY:20110101T120000Z/20110101T130000Z', + 'FREEBUSY;FBTYPE=BUSY-UNAVAILABLE:20110101T170000Z/20110101T180000Z', + ]; + + foreach ($strings as $string) { + $this->assertTrue( + strpos($this->response->body, $string) !== false, + 'The response body did not contain: ' . $string . 'Full response: ' . $this->response->body + ); + } + + } + + /* + function testNoPrivilege() { + + $this->markTestIncomplete('Currently there\'s no "no privilege" situation'); + + $this->server->httpRequest = HTTP\Sapi::createFromServerArray(array( + 'CONTENT_TYPE' => 'text/calendar', + 'REQUEST_METHOD' => 'POST', + 'REQUEST_URI' => '/calendars/user1/outbox', + )); + + $body = <<server->httpRequest->setBody($body); + + $this->assertFalse( + $this->plugin->httpPost($this->server->httpRequest, $this->response) + ); + + $this->assertEquals(200, $this->response->status); + $this->assertEquals([ + 'Content-Type' => 'application/xml', + ], $this->response->getHeaders()); + + $strings = [ + 'mailto:user2.sabredav@sabredav.org', + '3.7;No calendar-home-set property found', + ]; + + foreach($strings as $string) { + $this->assertTrue( + strpos($this->response->body, $string)!==false, + 'The response body did not contain: ' . $string .'Full response: ' . $this->response->body + ); + } + + + }*/ + +} diff --git a/vendor/sabre/dav/tests/Sabre/CalDAV/Schedule/IMip/MockPlugin.php b/vendor/sabre/dav/tests/Sabre/CalDAV/Schedule/IMip/MockPlugin.php new file mode 100644 index 000000000..028466093 --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/CalDAV/Schedule/IMip/MockPlugin.php @@ -0,0 +1,50 @@ +emails[] = [ + 'to' => $to, + 'subject' => $subject, + 'body' => $body, + 'headers' => $headers, + ]; + + } + + function getSentEmails() { + + return $this->emails; + + } + + +} diff --git a/vendor/sabre/dav/tests/Sabre/CalDAV/Schedule/IMipPluginTest.php b/vendor/sabre/dav/tests/Sabre/CalDAV/Schedule/IMipPluginTest.php new file mode 100644 index 000000000..7311999f5 --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/CalDAV/Schedule/IMipPluginTest.php @@ -0,0 +1,221 @@ +assertEquals( + 'imip', + $plugin->getPluginInfo()['name'] + ); + + } + + function testDeliverReply() { + + $message = new Message(); + $message->sender = 'mailto:sender@example.org'; + $message->senderName = 'Sender'; + $message->recipient = 'mailto:recipient@example.org'; + $message->recipientName = 'Recipient'; + $message->method = 'REPLY'; + + $ics = <<message = Reader::read($ics); + + $result = $this->schedule($message); + + $expected = [ + [ + 'to' => 'Recipient ', + 'subject' => 'Re: Birthday party', + 'body' => $ics, + 'headers' => [ + 'Reply-To: Sender ', + 'From: system@example.org', + 'Content-Type: text/calendar; charset=UTF-8; method=REPLY', + 'X-Sabre-Version: ' . \Sabre\DAV\Version::VERSION, + ], + ] + ]; + + $this->assertEquals($expected, $result); + + } + + function testDeliverReplyNoMailto() { + + $message = new Message(); + $message->sender = 'mailto:sender@example.org'; + $message->senderName = 'Sender'; + $message->recipient = 'http://example.org/recipient'; + $message->recipientName = 'Recipient'; + $message->method = 'REPLY'; + + $ics = <<message = Reader::read($ics); + + $result = $this->schedule($message); + + $expected = []; + + $this->assertEquals($expected, $result); + + } + + function testDeliverRequest() { + + $message = new Message(); + $message->sender = 'mailto:sender@example.org'; + $message->senderName = 'Sender'; + $message->recipient = 'mailto:recipient@example.org'; + $message->recipientName = 'Recipient'; + $message->method = 'REQUEST'; + + $ics = <<message = Reader::read($ics); + + $result = $this->schedule($message); + + $expected = [ + [ + 'to' => 'Recipient ', + 'subject' => 'Birthday party', + 'body' => $ics, + 'headers' => [ + 'Reply-To: Sender ', + 'From: system@example.org', + 'Content-Type: text/calendar; charset=UTF-8; method=REQUEST', + 'X-Sabre-Version: ' . \Sabre\DAV\Version::VERSION, + ], + ] + ]; + + $this->assertEquals($expected, $result); + + } + + function testDeliverCancel() { + + $message = new Message(); + $message->sender = 'mailto:sender@example.org'; + $message->senderName = 'Sender'; + $message->recipient = 'mailto:recipient@example.org'; + $message->recipientName = 'Recipient'; + $message->method = 'CANCEL'; + + $ics = <<message = Reader::read($ics); + + $result = $this->schedule($message); + + $expected = [ + [ + 'to' => 'Recipient ', + 'subject' => 'Cancelled: Birthday party', + 'body' => $ics, + 'headers' => [ + 'Reply-To: Sender ', + 'From: system@example.org', + 'Content-Type: text/calendar; charset=UTF-8; method=CANCEL', + 'X-Sabre-Version: ' . \Sabre\DAV\Version::VERSION, + ], + ] + ]; + + $this->assertEquals($expected, $result); + $this->assertEquals('1.1', substr($message->scheduleStatus, 0, 3)); + + } + + function schedule(Message $message) { + + $plugin = new IMip\MockPlugin('system@example.org'); + + $server = new Server(); + $server->addPlugin($plugin); + $server->emit('schedule', [$message]); + + return $plugin->getSentEmails(); + + } + + function testDeliverInsignificantRequest() { + + $message = new Message(); + $message->sender = 'mailto:sender@example.org'; + $message->senderName = 'Sender'; + $message->recipient = 'mailto:recipient@example.org'; + $message->recipientName = 'Recipient'; + $message->method = 'REQUEST'; + $message->significantChange = false; + + $ics = <<message = Reader::read($ics); + + $result = $this->schedule($message); + + $expected = []; + $this->assertEquals($expected, $result); + $this->assertEquals('1.0', $message->getScheduleStatus()[0]); + + } + +} diff --git a/vendor/sabre/dav/tests/Sabre/CalDAV/Schedule/InboxTest.php b/vendor/sabre/dav/tests/Sabre/CalDAV/Schedule/InboxTest.php new file mode 100644 index 000000000..01c3488af --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/CalDAV/Schedule/InboxTest.php @@ -0,0 +1,136 @@ +assertEquals('inbox', $inbox->getName()); + $this->assertEquals([], $inbox->getChildren()); + $this->assertEquals('principals/user1', $inbox->getOwner()); + $this->assertEquals(null, $inbox->getGroup()); + + $this->assertEquals([ + [ + 'privilege' => '{DAV:}read', + 'principal' => '{DAV:}authenticated', + 'protected' => true, + ], + [ + 'privilege' => '{DAV:}write-properties', + 'principal' => 'principals/user1', + 'protected' => true, + ], + [ + 'privilege' => '{DAV:}unbind', + 'principal' => 'principals/user1', + 'protected' => true, + ], + [ + 'privilege' => '{DAV:}unbind', + 'principal' => 'principals/user1/calendar-proxy-write', + 'protected' => true, + ], + [ + 'privilege' => '{urn:ietf:params:xml:ns:caldav}schedule-deliver', + 'principal' => '{DAV:}authenticated', + 'protected' => true, + ], + ], $inbox->getACL()); + + $ok = false; + + } + + /** + * @depends testSetup + */ + function testGetChildren() { + + $backend = new CalDAV\Backend\MockScheduling(); + $inbox = new Inbox( + $backend, + 'principals/user1' + ); + + $this->assertEquals( + 0, + count($inbox->getChildren()) + ); + $backend->createSchedulingObject('principals/user1', 'schedule1.ics', "BEGIN:VCALENDAR\r\nEND:VCALENDAR"); + $this->assertEquals( + 1, + count($inbox->getChildren()) + ); + $this->assertInstanceOf('Sabre\CalDAV\Schedule\SchedulingObject', $inbox->getChildren()[0]); + $this->assertEquals( + 'schedule1.ics', + $inbox->getChildren()[0]->getName() + ); + + } + + /** + * @depends testGetChildren + */ + function testCreateFile() { + + $backend = new CalDAV\Backend\MockScheduling(); + $inbox = new Inbox( + $backend, + 'principals/user1' + ); + + $this->assertEquals( + 0, + count($inbox->getChildren()) + ); + $inbox->createFile('schedule1.ics', "BEGIN:VCALENDAR\r\nEND:VCALENDAR"); + $this->assertEquals( + 1, + count($inbox->getChildren()) + ); + $this->assertInstanceOf('Sabre\CalDAV\Schedule\SchedulingObject', $inbox->getChildren()[0]); + $this->assertEquals( + 'schedule1.ics', + $inbox->getChildren()[0]->getName() + ); + + } + + /** + * @depends testSetup + */ + function testCalendarQuery() { + + $backend = new CalDAV\Backend\MockScheduling(); + $inbox = new Inbox( + $backend, + 'principals/user1' + ); + + $this->assertEquals( + 0, + count($inbox->getChildren()) + ); + $backend->createSchedulingObject('principals/user1', 'schedule1.ics', "BEGIN:VCALENDAR\r\nEND:VCALENDAR"); + $this->assertEquals( + ['schedule1.ics'], + $inbox->calendarQuery([ + 'name' => 'VCALENDAR', + 'comp-filters' => [], + 'prop-filters' => [], + 'is-not-defined' => false + ]) + ); + + } +} diff --git a/vendor/sabre/dav/tests/Sabre/CalDAV/Schedule/OutboxPostTest.php b/vendor/sabre/dav/tests/Sabre/CalDAV/Schedule/OutboxPostTest.php new file mode 100644 index 000000000..3ab2c2288 --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/CalDAV/Schedule/OutboxPostTest.php @@ -0,0 +1,134 @@ + 'POST', + 'REQUEST_URI' => '/notfound', + 'HTTP_CONTENT_TYPE' => 'text/calendar', + ]); + + $this->assertHTTPStatus(501, $req); + + } + + function testPostPassThruNotTextCalendar() { + + $req = HTTP\Sapi::createFromServerArray([ + 'REQUEST_METHOD' => 'POST', + 'REQUEST_URI' => '/calendars/user1/outbox', + ]); + + $this->assertHTTPStatus(501, $req); + + } + + function testPostPassThruNoOutBox() { + + $req = HTTP\Sapi::createFromServerArray([ + 'REQUEST_METHOD' => 'POST', + 'REQUEST_URI' => '/calendars', + 'HTTP_CONTENT_TYPE' => 'text/calendar', + ]); + + $this->assertHTTPStatus(501, $req); + + } + + function testInvalidIcalBody() { + + $req = HTTP\Sapi::createFromServerArray([ + 'REQUEST_METHOD' => 'POST', + 'REQUEST_URI' => '/calendars/user1/outbox', + 'HTTP_ORIGINATOR' => 'mailto:user1.sabredav@sabredav.org', + 'HTTP_RECIPIENT' => 'mailto:user2@example.org', + 'HTTP_CONTENT_TYPE' => 'text/calendar', + ]); + $req->setBody('foo'); + + $this->assertHTTPStatus(400, $req); + + } + + function testNoVEVENT() { + + $req = HTTP\Sapi::createFromServerArray([ + 'REQUEST_METHOD' => 'POST', + 'REQUEST_URI' => '/calendars/user1/outbox', + 'HTTP_ORIGINATOR' => 'mailto:user1.sabredav@sabredav.org', + 'HTTP_RECIPIENT' => 'mailto:user2@example.org', + 'HTTP_CONTENT_TYPE' => 'text/calendar', + ]); + + $body = [ + 'BEGIN:VCALENDAR', + 'BEGIN:VTIMEZONE', + 'END:VTIMEZONE', + 'END:VCALENDAR', + ]; + + $req->setBody(implode("\r\n", $body)); + + $this->assertHTTPStatus(400, $req); + + } + + function testNoMETHOD() { + + $req = HTTP\Sapi::createFromServerArray([ + 'REQUEST_METHOD' => 'POST', + 'REQUEST_URI' => '/calendars/user1/outbox', + 'HTTP_ORIGINATOR' => 'mailto:user1.sabredav@sabredav.org', + 'HTTP_RECIPIENT' => 'mailto:user2@example.org', + 'HTTP_CONTENT_TYPE' => 'text/calendar', + ]); + + $body = [ + 'BEGIN:VCALENDAR', + 'BEGIN:VEVENT', + 'END:VEVENT', + 'END:VCALENDAR', + ]; + + $req->setBody(implode("\r\n", $body)); + + $this->assertHTTPStatus(400, $req); + + } + + function testUnsupportedMethod() { + + $req = HTTP\Sapi::createFromServerArray([ + 'REQUEST_METHOD' => 'POST', + 'REQUEST_URI' => '/calendars/user1/outbox', + 'HTTP_ORIGINATOR' => 'mailto:user1.sabredav@sabredav.org', + 'HTTP_RECIPIENT' => 'mailto:user2@example.org', + 'HTTP_CONTENT_TYPE' => 'text/calendar', + ]); + + $body = [ + 'BEGIN:VCALENDAR', + 'METHOD:PUBLISH', + 'BEGIN:VEVENT', + 'END:VEVENT', + 'END:VCALENDAR', + ]; + + $req->setBody(implode("\r\n", $body)); + + $this->assertHTTPStatus(501, $req); + + } + +} diff --git a/vendor/sabre/dav/tests/Sabre/CalDAV/Schedule/OutboxTest.php b/vendor/sabre/dav/tests/Sabre/CalDAV/Schedule/OutboxTest.php new file mode 100644 index 000000000..04d4b1237 --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/CalDAV/Schedule/OutboxTest.php @@ -0,0 +1,48 @@ +assertEquals('outbox', $outbox->getName()); + $this->assertEquals([], $outbox->getChildren()); + $this->assertEquals('principals/user1', $outbox->getOwner()); + $this->assertEquals(null, $outbox->getGroup()); + + $this->assertEquals([ + [ + 'privilege' => '{' . CalDAV\Plugin::NS_CALDAV . '}schedule-send', + 'principal' => 'principals/user1', + 'protected' => true, + ], + [ + 'privilege' => '{DAV:}read', + 'principal' => 'principals/user1', + 'protected' => true, + ], + [ + 'privilege' => '{' . CalDAV\Plugin::NS_CALDAV . '}schedule-send', + 'principal' => 'principals/user1/calendar-proxy-write', + 'protected' => true, + ], + [ + 'privilege' => '{DAV:}read', + 'principal' => 'principals/user1/calendar-proxy-read', + 'protected' => true, + ], + [ + 'privilege' => '{DAV:}read', + 'principal' => 'principals/user1/calendar-proxy-write', + 'protected' => true, + ], + ], $outbox->getACL()); + + } + +} diff --git a/vendor/sabre/dav/tests/Sabre/CalDAV/Schedule/PluginBasicTest.php b/vendor/sabre/dav/tests/Sabre/CalDAV/Schedule/PluginBasicTest.php new file mode 100644 index 000000000..cee911b6e --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/CalDAV/Schedule/PluginBasicTest.php @@ -0,0 +1,39 @@ +assertEquals( + 'caldav-schedule', + $plugin->getPluginInfo()['name'] + ); + + } + + function testOptions() { + + $plugin = new Plugin(); + $expected = [ + 'calendar-auto-schedule', + 'calendar-availability', + ]; + $this->assertEquals($expected, $plugin->getFeatures()); + + } + + function testGetHTTPMethods() { + + $this->assertEquals([], $this->caldavSchedulePlugin->getHTTPMethods('notfound')); + $this->assertEquals([], $this->caldavSchedulePlugin->getHTTPMethods('calendars/user1')); + $this->assertEquals(['POST'], $this->caldavSchedulePlugin->getHTTPMethods('calendars/user1/outbox')); + + } + +} diff --git a/vendor/sabre/dav/tests/Sabre/CalDAV/Schedule/PluginPropertiesTest.php b/vendor/sabre/dav/tests/Sabre/CalDAV/Schedule/PluginPropertiesTest.php new file mode 100644 index 000000000..2d0391893 --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/CalDAV/Schedule/PluginPropertiesTest.php @@ -0,0 +1,146 @@ +caldavBackend->createCalendar( + 'principals/user1', + 'default', + [ + + ] + ); + $this->principalBackend->addPrincipal([ + 'uri' => 'principals/user1/calendar-proxy-read' + ]); + + } + + function testPrincipalProperties() { + + $props = $this->server->getPropertiesForPath('/principals/user1', [ + '{urn:ietf:params:xml:ns:caldav}schedule-inbox-URL', + '{urn:ietf:params:xml:ns:caldav}schedule-outbox-URL', + '{urn:ietf:params:xml:ns:caldav}calendar-user-address-set', + '{urn:ietf:params:xml:ns:caldav}calendar-user-type', + '{urn:ietf:params:xml:ns:caldav}schedule-default-calendar-URL', + ]); + + $this->assertArrayHasKey(0, $props); + $this->assertArrayHasKey(200, $props[0]); + + $this->assertArrayHasKey('{urn:ietf:params:xml:ns:caldav}schedule-outbox-URL', $props[0][200]); + $prop = $props[0][200]['{urn:ietf:params:xml:ns:caldav}schedule-outbox-URL']; + $this->assertTrue($prop instanceof DAV\Xml\Property\Href); + $this->assertEquals('calendars/user1/outbox/', $prop->getHref()); + + $this->assertArrayHasKey('{urn:ietf:params:xml:ns:caldav}schedule-inbox-URL', $props[0][200]); + $prop = $props[0][200]['{urn:ietf:params:xml:ns:caldav}schedule-inbox-URL']; + $this->assertTrue($prop instanceof DAV\Xml\Property\Href); + $this->assertEquals('calendars/user1/inbox/', $prop->getHref()); + + $this->assertArrayHasKey('{urn:ietf:params:xml:ns:caldav}calendar-user-address-set', $props[0][200]); + $prop = $props[0][200]['{urn:ietf:params:xml:ns:caldav}calendar-user-address-set']; + $this->assertTrue($prop instanceof DAV\Xml\Property\Href); + $this->assertEquals(['mailto:user1.sabredav@sabredav.org', '/principals/user1/'], $prop->getHrefs()); + + $this->assertArrayHasKey('{urn:ietf:params:xml:ns:caldav}calendar-user-type', $props[0][200]); + $prop = $props[0][200]['{urn:ietf:params:xml:ns:caldav}calendar-user-type']; + $this->assertEquals('INDIVIDUAL', $prop); + + $this->assertArrayHasKey('{urn:ietf:params:xml:ns:caldav}schedule-default-calendar-URL', $props[0][200]); + $prop = $props[0][200]['{urn:ietf:params:xml:ns:caldav}schedule-default-calendar-URL']; + $this->assertEquals('calendars/user1/default/', $prop->getHref()); + + } + function testPrincipalPropertiesBadPrincipal() { + + $props = $this->server->getPropertiesForPath('principals/user1/calendar-proxy-read', [ + '{urn:ietf:params:xml:ns:caldav}schedule-inbox-URL', + '{urn:ietf:params:xml:ns:caldav}schedule-outbox-URL', + '{urn:ietf:params:xml:ns:caldav}calendar-user-address-set', + '{urn:ietf:params:xml:ns:caldav}calendar-user-type', + '{urn:ietf:params:xml:ns:caldav}schedule-default-calendar-URL', + ]); + + $this->assertArrayHasKey(0, $props); + $this->assertArrayHasKey(200, $props[0]); + $this->assertArrayHasKey(404, $props[0]); + + $this->assertArrayHasKey('{urn:ietf:params:xml:ns:caldav}schedule-outbox-URL', $props[0][404]); + $this->assertArrayHasKey('{urn:ietf:params:xml:ns:caldav}schedule-inbox-URL', $props[0][404]); + + $prop = $props[0][200]['{urn:ietf:params:xml:ns:caldav}calendar-user-address-set']; + $this->assertTrue($prop instanceof DAV\Xml\Property\Href); + $this->assertEquals(['/principals/user1/calendar-proxy-read/'], $prop->getHrefs()); + + $this->assertArrayHasKey('{urn:ietf:params:xml:ns:caldav}calendar-user-type', $props[0][200]); + $prop = $props[0][200]['{urn:ietf:params:xml:ns:caldav}calendar-user-type']; + $this->assertEquals('INDIVIDUAL', $prop); + + $this->assertArrayHasKey('{urn:ietf:params:xml:ns:caldav}schedule-default-calendar-URL', $props[0][404]); + + } + function testNoDefaultCalendar() { + + foreach ($this->caldavBackend->getCalendarsForUser('principals/user1') as $calendar) { + $this->caldavBackend->deleteCalendar($calendar['id']); + } + $props = $this->server->getPropertiesForPath('/principals/user1', [ + '{urn:ietf:params:xml:ns:caldav}schedule-default-calendar-URL', + ]); + + $this->assertArrayHasKey(0, $props); + $this->assertArrayHasKey(404, $props[0]); + + $this->assertArrayHasKey('{urn:ietf:params:xml:ns:caldav}schedule-default-calendar-URL', $props[0][404]); + + } + + /** + * There are two properties for availability. The server should + * automatically map the old property to the standard property. + */ + function testAvailabilityMapping() { + + $path = 'calendars/user1/inbox'; + $oldProp = '{http://calendarserver.org/ns/}calendar-availability'; + $newProp = '{urn:ietf:params:xml:ns:caldav}calendar-availability'; + $value1 = 'first value'; + $value2 = 'second value'; + + // Storing with the old name + $this->server->updateProperties($path, [ + $oldProp => $value1 + ]); + + // Retrieving with the new name + $this->assertEquals( + [$newProp => $value1], + $this->server->getProperties($path, [$newProp]) + ); + + // Storing with the new name + $this->server->updateProperties($path, [ + $newProp => $value2 + ]); + + // Retrieving with the old name + $this->assertEquals( + [$oldProp => $value2], + $this->server->getProperties($path, [$oldProp]) + ); + + } + +} diff --git a/vendor/sabre/dav/tests/Sabre/CalDAV/Schedule/PluginPropertiesWithSharedCalendarTest.php b/vendor/sabre/dav/tests/Sabre/CalDAV/Schedule/PluginPropertiesWithSharedCalendarTest.php new file mode 100644 index 000000000..870f14c14 --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/CalDAV/Schedule/PluginPropertiesWithSharedCalendarTest.php @@ -0,0 +1,71 @@ +caldavBackend->createCalendar( + 'principals/user1', + 'shared', + [ + 'share-access' => DAV\Sharing\Plugin::ACCESS_READWRITE + ] + ); + $this->caldavBackend->createCalendar( + 'principals/user1', + 'default', + [ + + ] + ); + + } + + function testPrincipalProperties() { + + $props = $this->server->getPropertiesForPath('/principals/user1', [ + '{urn:ietf:params:xml:ns:caldav}schedule-inbox-URL', + '{urn:ietf:params:xml:ns:caldav}schedule-outbox-URL', + '{urn:ietf:params:xml:ns:caldav}calendar-user-address-set', + '{urn:ietf:params:xml:ns:caldav}calendar-user-type', + '{urn:ietf:params:xml:ns:caldav}schedule-default-calendar-URL', + ]); + + $this->assertArrayHasKey(0, $props); + $this->assertArrayHasKey(200, $props[0]); + + $this->assertArrayHasKey('{urn:ietf:params:xml:ns:caldav}schedule-outbox-URL', $props[0][200]); + $prop = $props[0][200]['{urn:ietf:params:xml:ns:caldav}schedule-outbox-URL']; + $this->assertTrue($prop instanceof DAV\Xml\Property\Href); + $this->assertEquals('calendars/user1/outbox/', $prop->getHref()); + + $this->assertArrayHasKey('{urn:ietf:params:xml:ns:caldav}schedule-inbox-URL', $props[0][200]); + $prop = $props[0][200]['{urn:ietf:params:xml:ns:caldav}schedule-inbox-URL']; + $this->assertTrue($prop instanceof DAV\Xml\Property\Href); + $this->assertEquals('calendars/user1/inbox/', $prop->getHref()); + + $this->assertArrayHasKey('{urn:ietf:params:xml:ns:caldav}calendar-user-address-set', $props[0][200]); + $prop = $props[0][200]['{urn:ietf:params:xml:ns:caldav}calendar-user-address-set']; + $this->assertTrue($prop instanceof DAV\Xml\Property\Href); + $this->assertEquals(['mailto:user1.sabredav@sabredav.org', '/principals/user1/'], $prop->getHrefs()); + + $this->assertArrayHasKey('{urn:ietf:params:xml:ns:caldav}calendar-user-type', $props[0][200]); + $prop = $props[0][200]['{urn:ietf:params:xml:ns:caldav}calendar-user-type']; + $this->assertEquals('INDIVIDUAL', $prop); + + $this->assertArrayHasKey('{urn:ietf:params:xml:ns:caldav}schedule-default-calendar-URL', $props[0][200]); + $prop = $props[0][200]['{urn:ietf:params:xml:ns:caldav}schedule-default-calendar-URL']; + $this->assertEquals('calendars/user1/default/', $prop->getHref()); + + } + +} diff --git a/vendor/sabre/dav/tests/Sabre/CalDAV/Schedule/ScheduleDeliverTest.php b/vendor/sabre/dav/tests/Sabre/CalDAV/Schedule/ScheduleDeliverTest.php new file mode 100644 index 000000000..8123c685c --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/CalDAV/Schedule/ScheduleDeliverTest.php @@ -0,0 +1,666 @@ + 'principals/user1', + 'uri' => 'cal', + ], + [ + 'principaluri' => 'principals/user2', + 'uri' => 'cal', + ], + ]; + + function setUp() { + + $this->calendarObjectUri = '/calendars/user1/cal/object.ics'; + + parent::setUp(); + + } + + function testNewInvite() { + + $newObject = <<deliver(null, $newObject); + $this->assertItemsInInbox('user2', 1); + + $expected = <<assertVObjectEqualsVObject( + $expected, + $newObject + ); + + } + + function testNewOnWrongCollection() { + + $newObject = <<calendarObjectUri = '/calendars/user1/object.ics'; + $this->deliver(null, $newObject); + $this->assertItemsInInbox('user2', 0); + + + } + function testNewInviteSchedulingDisabled() { + + $newObject = <<deliver(null, $newObject, true); + $this->assertItemsInInbox('user2', 0); + + } + function testUpdatedInvite() { + + $newObject = <<deliver($oldObject, $newObject); + $this->assertItemsInInbox('user2', 1); + + $expected = <<assertVObjectEqualsVObject( + $expected, + $newObject + ); + + + } + function testUpdatedInviteSchedulingDisabled() { + + $newObject = <<deliver($oldObject, $newObject, true); + $this->assertItemsInInbox('user2', 0); + + } + + function testUpdatedInviteWrongPath() { + + $newObject = <<calendarObjectUri = '/calendars/user1/inbox/foo.ics'; + $this->deliver($oldObject, $newObject); + $this->assertItemsInInbox('user2', 0); + + } + + function testDeletedInvite() { + + $newObject = null; + + $oldObject = <<deliver($oldObject, $newObject); + $this->assertItemsInInbox('user2', 1); + + } + + function testDeletedInviteSchedulingDisabled() { + + $newObject = null; + + $oldObject = <<deliver($oldObject, $newObject, true); + $this->assertItemsInInbox('user2', 0); + + } + + /** + * A MOVE request will trigger an unbind on a scheduling resource. + * + * However, we must not treat it as a cancellation, it just got moved to a + * different calendar. + */ + function testUnbindIgnoredOnMove() { + + $newObject = null; + + $oldObject = <<server->httpRequest->setMethod('MOVE'); + $this->deliver($oldObject, $newObject); + $this->assertItemsInInbox('user2', 0); + + } + + function testDeletedInviteWrongUrl() { + + $newObject = null; + + $oldObject = <<calendarObjectUri = '/calendars/user1/inbox/foo.ics'; + $this->deliver($oldObject, $newObject); + $this->assertItemsInInbox('user2', 0); + + } + + function testReply() { + + $oldObject = <<putPath('calendars/user2/cal/foo.ics', $oldObject); + + $this->deliver($oldObject, $newObject); + $this->assertItemsInInbox('user2', 1); + $this->assertItemsInInbox('user1', 0); + + $expected = <<assertVObjectEqualsVObject( + $expected, + $newObject + ); + + } + + + + function testInviteUnknownUser() { + + $newObject = <<deliver(null, $newObject); + + $expected = <<assertVObjectEqualsVObject( + $expected, + $newObject + ); + + } + + function testInviteNoInboxUrl() { + + $newObject = <<server->on('propFind', function($propFind) { + $propFind->set('{' . Plugin::NS_CALDAV . '}schedule-inbox-URL', null, 403); + }); + $this->deliver(null, $newObject); + + $expected = <<assertVObjectEqualsVObject( + $expected, + $newObject + ); + + } + + function testInviteNoCalendarHomeSet() { + + $newObject = <<server->on('propFind', function($propFind) { + $propFind->set('{' . Plugin::NS_CALDAV . '}calendar-home-set', null, 403); + }); + $this->deliver(null, $newObject); + + $expected = <<assertVObjectEqualsVObject( + $expected, + $newObject + ); + + } + function testInviteNoDefaultCalendar() { + + $newObject = <<server->on('propFind', function($propFind) { + $propFind->set('{' . Plugin::NS_CALDAV . '}schedule-default-calendar-URL', null, 403); + }); + $this->deliver(null, $newObject); + + $expected = <<assertVObjectEqualsVObject( + $expected, + $newObject + ); + + } + function testInviteNoScheduler() { + + $newObject = <<server->removeAllListeners('schedule'); + $this->deliver(null, $newObject); + + $expected = <<assertVObjectEqualsVObject( + $expected, + $newObject + ); + + } + function testInviteNoACLPlugin() { + + $this->setupACL = false; + parent::setUp(); + + $newObject = <<deliver(null, $newObject); + + $expected = <<assertVObjectEqualsVObject( + $expected, + $newObject + ); + + } + + protected $calendarObjectUri; + + function deliver($oldObject, &$newObject, $disableScheduling = false) { + + $this->server->httpRequest->setUrl($this->calendarObjectUri); + if ($disableScheduling) { + $this->server->httpRequest->setHeader('Schedule-Reply', 'F'); + } + + if ($oldObject && $newObject) { + // update + $this->putPath($this->calendarObjectUri, $oldObject); + + $stream = fopen('php://memory', 'r+'); + fwrite($stream, $newObject); + rewind($stream); + $modified = false; + + $this->server->emit('beforeWriteContent', [ + $this->calendarObjectUri, + $this->server->tree->getNodeForPath($this->calendarObjectUri), + &$stream, + &$modified + ]); + if ($modified) { + $newObject = $stream; + } + + } elseif ($oldObject && !$newObject) { + // delete + $this->putPath($this->calendarObjectUri, $oldObject); + + $this->caldavSchedulePlugin->beforeUnbind( + $this->calendarObjectUri + ); + } else { + + // create + $stream = fopen('php://memory', 'r+'); + fwrite($stream, $newObject); + rewind($stream); + $modified = false; + $this->server->emit('beforeCreateFile', [ + $this->calendarObjectUri, + &$stream, + $this->server->tree->getNodeForPath(dirname($this->calendarObjectUri)), + &$modified + ]); + + if ($modified) { + $newObject = $stream; + } + } + + } + + + /** + * Creates or updates a node at the specified path. + * + * This circumvents sabredav's internal server apis, so all events and + * access control is skipped. + * + * @param string $path + * @param string $data + * @return void + */ + function putPath($path, $data) { + + list($parent, $base) = \Sabre\HTTP\UrlUtil::splitPath($path); + $parentNode = $this->server->tree->getNodeForPath($parent); + + /* + if ($parentNode->childExists($base)) { + $childNode = $parentNode->getChild($base); + $childNode->put($data); + } else {*/ + $parentNode->createFile($base, $data); + //} + + } + + function assertItemsInInbox($user, $count) { + + $inboxNode = $this->server->tree->getNodeForPath('calendars/' . $user . '/inbox'); + $this->assertEquals($count, count($inboxNode->getChildren())); + + } + +} diff --git a/vendor/sabre/dav/tests/Sabre/CalDAV/Schedule/SchedulingObjectTest.php b/vendor/sabre/dav/tests/Sabre/CalDAV/Schedule/SchedulingObjectTest.php new file mode 100644 index 000000000..be83cd081 --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/CalDAV/Schedule/SchedulingObjectTest.php @@ -0,0 +1,378 @@ +markTestSkipped('SQLite driver is not available'); + $this->backend = new Backend\MockScheduling(); + + $this->data = <<data = <<inbox = new Inbox($this->backend, 'principals/user1'); + $this->inbox->createFile('item1.ics', $this->data); + + } + + function teardown() { + + unset($this->inbox); + unset($this->backend); + + } + + function testSetup() { + + $children = $this->inbox->getChildren(); + $this->assertTrue($children[0] instanceof SchedulingObject); + + $this->assertInternalType('string', $children[0]->getName()); + $this->assertInternalType('string', $children[0]->get()); + $this->assertInternalType('string', $children[0]->getETag()); + $this->assertEquals('text/calendar; charset=utf-8', $children[0]->getContentType()); + + } + + /** + * @expectedException InvalidArgumentException + */ + function testInvalidArg1() { + + $obj = new SchedulingObject( + new Backend\MockScheduling([], []), + [], + [] + ); + + } + + /** + * @expectedException InvalidArgumentException + */ + function testInvalidArg2() { + + $obj = new SchedulingObject( + new Backend\MockScheduling([], []), + [], + ['calendarid' => '1'] + ); + + } + + /** + * @depends testSetup + * @expectedException \Sabre\DAV\Exception\MethodNotAllowed + */ + function testPut() { + + $children = $this->inbox->getChildren(); + $this->assertTrue($children[0] instanceof SchedulingObject); + + $children[0]->put(''); + + } + + /** + * @depends testSetup + */ + function testDelete() { + + $children = $this->inbox->getChildren(); + $this->assertTrue($children[0] instanceof SchedulingObject); + + $obj = $children[0]; + $obj->delete(); + + $children2 = $this->inbox->getChildren(); + $this->assertEquals(count($children) - 1, count($children2)); + + } + + /** + * @depends testSetup + */ + function testGetLastModified() { + + $children = $this->inbox->getChildren(); + $this->assertTrue($children[0] instanceof SchedulingObject); + + $obj = $children[0]; + + $lastMod = $obj->getLastModified(); + $this->assertTrue(is_int($lastMod) || ctype_digit($lastMod) || is_null($lastMod)); + + } + + /** + * @depends testSetup + */ + function testGetSize() { + + $children = $this->inbox->getChildren(); + $this->assertTrue($children[0] instanceof SchedulingObject); + + $obj = $children[0]; + + $size = $obj->getSize(); + $this->assertInternalType('int', $size); + + } + + function testGetOwner() { + + $children = $this->inbox->getChildren(); + $this->assertTrue($children[0] instanceof SchedulingObject); + + $obj = $children[0]; + $this->assertEquals('principals/user1', $obj->getOwner()); + + } + + function testGetGroup() { + + $children = $this->inbox->getChildren(); + $this->assertTrue($children[0] instanceof SchedulingObject); + + $obj = $children[0]; + $this->assertNull($obj->getGroup()); + + } + + function testGetACL() { + + $expected = [ + [ + 'privilege' => '{DAV:}all', + 'principal' => '{DAV:}owner', + 'protected' => true, + ], + [ + 'privilege' => '{DAV:}all', + 'principal' => 'principals/user1/calendar-proxy-write', + 'protected' => true, + ], + [ + 'privilege' => '{DAV:}read', + 'principal' => 'principals/user1/calendar-proxy-read', + 'protected' => true, + ], + ]; + + $children = $this->inbox->getChildren(); + $this->assertTrue($children[0] instanceof SchedulingObject); + + $obj = $children[0]; + $this->assertEquals($expected, $obj->getACL()); + + } + + function testDefaultACL() { + + $backend = new Backend\MockScheduling([], []); + $calendarObject = new SchedulingObject($backend, ['calendarid' => 1, 'uri' => 'foo', 'principaluri' => 'principals/user1']); + $expected = [ + [ + 'privilege' => '{DAV:}all', + 'principal' => '{DAV:}owner', + 'protected' => true, + ], + [ + 'privilege' => '{DAV:}all', + 'principal' => 'principals/user1/calendar-proxy-write', + 'protected' => true, + ], + [ + 'privilege' => '{DAV:}read', + 'principal' => 'principals/user1/calendar-proxy-read', + 'protected' => true, + ], + ]; + $this->assertEquals($expected, $calendarObject->getACL()); + + + } + + /** + * @expectedException \Sabre\DAV\Exception\Forbidden + */ + function testSetACL() { + + $children = $this->inbox->getChildren(); + $this->assertTrue($children[0] instanceof SchedulingObject); + + $obj = $children[0]; + $obj->setACL([]); + + } + + function testGet() { + + $children = $this->inbox->getChildren(); + $this->assertTrue($children[0] instanceof SchedulingObject); + + $obj = $children[0]; + + $this->assertEquals($this->data, $obj->get()); + + } + + function testGetRefetch() { + + $backend = new Backend\MockScheduling(); + $backend->createSchedulingObject('principals/user1', 'foo', 'foo'); + + $obj = new SchedulingObject($backend, [ + 'calendarid' => 1, + 'uri' => 'foo', + 'principaluri' => 'principals/user1', + ]); + + $this->assertEquals('foo', $obj->get()); + + } + + function testGetEtag1() { + + $objectInfo = [ + 'calendardata' => 'foo', + 'uri' => 'foo', + 'etag' => 'bar', + 'calendarid' => 1 + ]; + + $backend = new Backend\MockScheduling([], []); + $obj = new SchedulingObject($backend, $objectInfo); + + $this->assertEquals('bar', $obj->getETag()); + + } + + function testGetEtag2() { + + $objectInfo = [ + 'calendardata' => 'foo', + 'uri' => 'foo', + 'calendarid' => 1 + ]; + + $backend = new Backend\MockScheduling([], []); + $obj = new SchedulingObject($backend, $objectInfo); + + $this->assertEquals('"' . md5('foo') . '"', $obj->getETag()); + + } + + function testGetSupportedPrivilegesSet() { + + $objectInfo = [ + 'calendardata' => 'foo', + 'uri' => 'foo', + 'calendarid' => 1 + ]; + + $backend = new Backend\MockScheduling([], []); + $obj = new SchedulingObject($backend, $objectInfo); + $this->assertNull($obj->getSupportedPrivilegeSet()); + + } + + function testGetSize1() { + + $objectInfo = [ + 'calendardata' => 'foo', + 'uri' => 'foo', + 'calendarid' => 1 + ]; + + $backend = new Backend\MockScheduling([], []); + $obj = new SchedulingObject($backend, $objectInfo); + $this->assertEquals(3, $obj->getSize()); + + } + + function testGetSize2() { + + $objectInfo = [ + 'uri' => 'foo', + 'calendarid' => 1, + 'size' => 4, + ]; + + $backend = new Backend\MockScheduling([], []); + $obj = new SchedulingObject($backend, $objectInfo); + $this->assertEquals(4, $obj->getSize()); + + } + + function testGetContentType() { + + $objectInfo = [ + 'uri' => 'foo', + 'calendarid' => 1, + ]; + + $backend = new Backend\MockScheduling([], []); + $obj = new SchedulingObject($backend, $objectInfo); + $this->assertEquals('text/calendar; charset=utf-8', $obj->getContentType()); + + } + + function testGetContentType2() { + + $objectInfo = [ + 'uri' => 'foo', + 'calendarid' => 1, + 'component' => 'VEVENT', + ]; + + $backend = new Backend\MockScheduling([], []); + $obj = new SchedulingObject($backend, $objectInfo); + $this->assertEquals('text/calendar; charset=utf-8; component=VEVENT', $obj->getContentType()); + + } + function testGetACL2() { + + $objectInfo = [ + 'uri' => 'foo', + 'calendarid' => 1, + 'acl' => [], + ]; + + $backend = new Backend\MockScheduling([], []); + $obj = new SchedulingObject($backend, $objectInfo); + $this->assertEquals([], $obj->getACL()); + + } +} diff --git a/vendor/sabre/dav/tests/Sabre/CalDAV/SharedCalendarTest.php b/vendor/sabre/dav/tests/Sabre/CalDAV/SharedCalendarTest.php new file mode 100644 index 000000000..f71c19523 --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/CalDAV/SharedCalendarTest.php @@ -0,0 +1,176 @@ + 1, + '{http://calendarserver.org/ns/}shared-url' => 'calendars/owner/original', + '{http://sabredav.org/ns}owner-principal' => 'principals/owner', + '{http://sabredav.org/ns}read-only' => false, + 'share-access' => Sharing\Plugin::ACCESS_READWRITE, + 'principaluri' => 'principals/sharee', + ]; + } + + $this->backend = new Backend\MockSharing( + [$props], + [], + [] + ); + + $sharee = new Sharee(); + $sharee->href = 'mailto:removeme@example.org'; + $sharee->properties['{DAV:}displayname'] = 'To be removed'; + $sharee->access = Sharing\Plugin::ACCESS_READ; + $this->backend->updateInvites(1, [$sharee]); + + return new SharedCalendar($this->backend, $props); + + } + + function testGetInvites() { + + $sharee = new Sharee(); + $sharee->href = 'mailto:removeme@example.org'; + $sharee->properties['{DAV:}displayname'] = 'To be removed'; + $sharee->access = Sharing\Plugin::ACCESS_READ; + $sharee->inviteStatus = Sharing\Plugin::INVITE_NORESPONSE; + + $this->assertEquals( + [$sharee], + $this->getInstance()->getInvites() + ); + + } + + function testGetOwner() { + $this->assertEquals('principals/sharee', $this->getInstance()->getOwner()); + } + + function testGetACL() { + + $expected = [ + [ + 'privilege' => '{DAV:}write', + 'principal' => 'principals/sharee', + 'protected' => true, + ], + [ + 'privilege' => '{DAV:}write', + 'principal' => 'principals/sharee/calendar-proxy-write', + 'protected' => true, + ], + [ + 'privilege' => '{DAV:}write-properties', + 'principal' => 'principals/sharee', + 'protected' => true, + ], + [ + 'privilege' => '{DAV:}write-properties', + 'principal' => 'principals/sharee/calendar-proxy-write', + 'protected' => true, + ], + [ + 'privilege' => '{DAV:}read', + 'principal' => 'principals/sharee', + 'protected' => true, + ], + [ + 'privilege' => '{DAV:}read', + 'principal' => 'principals/sharee/calendar-proxy-read', + 'protected' => true, + ], + [ + 'privilege' => '{DAV:}read', + 'principal' => 'principals/sharee/calendar-proxy-write', + 'protected' => true, + ], + [ + 'privilege' => '{' . Plugin::NS_CALDAV . '}read-free-busy', + 'principal' => '{DAV:}authenticated', + 'protected' => true, + ], + ]; + + $this->assertEquals($expected, $this->getInstance()->getACL()); + + } + + function testGetChildACL() { + + $expected = [ + [ + 'privilege' => '{DAV:}write', + 'principal' => 'principals/sharee', + 'protected' => true, + ], + [ + 'privilege' => '{DAV:}write', + 'principal' => 'principals/sharee/calendar-proxy-write', + 'protected' => true, + ], + [ + 'privilege' => '{DAV:}read', + 'principal' => 'principals/sharee', + 'protected' => true, + ], + [ + 'privilege' => '{DAV:}read', + 'principal' => 'principals/sharee/calendar-proxy-write', + 'protected' => true, + ], + [ + 'privilege' => '{DAV:}read', + 'principal' => 'principals/sharee/calendar-proxy-read', + 'protected' => true, + ], + + ]; + + $this->assertEquals($expected, $this->getInstance()->getChildACL()); + + } + + function testUpdateInvites() { + + $instance = $this->getInstance(); + $newSharees = [ + new Sharee(), + new Sharee() + ]; + $newSharees[0]->href = 'mailto:test@example.org'; + $newSharees[0]->properties['{DAV:}displayname'] = 'Foo Bar'; + $newSharees[0]->comment = 'Booh'; + $newSharees[0]->access = Sharing\Plugin::ACCESS_READWRITE; + + $newSharees[1]->href = 'mailto:removeme@example.org'; + $newSharees[1]->access = Sharing\Plugin::ACCESS_NOACCESS; + + $instance->updateInvites($newSharees); + + $expected = [ + clone $newSharees[0] + ]; + $expected[0]->inviteStatus = Sharing\Plugin::INVITE_NORESPONSE; + $this->assertEquals($expected, $instance->getInvites()); + + } + + function testPublish() { + + $instance = $this->getInstance(); + $this->assertNull($instance->setPublishStatus(true)); + $this->assertNull($instance->setPublishStatus(false)); + + } +} diff --git a/vendor/sabre/dav/tests/Sabre/CalDAV/SharingPluginTest.php b/vendor/sabre/dav/tests/Sabre/CalDAV/SharingPluginTest.php new file mode 100644 index 000000000..9589176a3 --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/CalDAV/SharingPluginTest.php @@ -0,0 +1,396 @@ +caldavCalendars = [ + [ + 'principaluri' => 'principals/user1', + 'id' => 1, + 'uri' => 'cal1', + ], + [ + 'principaluri' => 'principals/user1', + 'id' => 2, + 'uri' => 'cal2', + 'share-access' => \Sabre\DAV\Sharing\Plugin::ACCESS_READWRITE, + ], + [ + 'principaluri' => 'principals/user1', + 'id' => 3, + 'uri' => 'cal3', + ], + ]; + + parent::setUp(); + + // Making the logged in user an admin, for full access: + $this->aclPlugin->adminPrincipals[] = 'principals/user2'; + + } + + function testSimple() { + + $this->assertInstanceOf('Sabre\\CalDAV\\SharingPlugin', $this->server->getPlugin('caldav-sharing')); + $this->assertEquals( + 'caldav-sharing', + $this->caldavSharingPlugin->getPluginInfo()['name'] + ); + + } + + /** + * @expectedException \LogicException + */ + function testSetupWithoutCoreSharingPlugin() { + + $server = new DAV\Server(); + $server->addPlugin( + new SharingPlugin() + ); + + } + + function testGetFeatures() { + + $this->assertEquals(['calendarserver-sharing'], $this->caldavSharingPlugin->getFeatures()); + + } + + function testBeforeGetShareableCalendar() { + + // Forcing the server to authenticate: + $this->authPlugin->beforeMethod(new HTTP\Request(), new HTTP\Response()); + $props = $this->server->getProperties('calendars/user1/cal1', [ + '{' . Plugin::NS_CALENDARSERVER . '}invite', + '{' . Plugin::NS_CALENDARSERVER . '}allowed-sharing-modes', + ]); + + $this->assertInstanceOf('Sabre\\CalDAV\\Xml\\Property\\Invite', $props['{' . Plugin::NS_CALENDARSERVER . '}invite']); + $this->assertInstanceOf('Sabre\\CalDAV\\Xml\\Property\\AllowedSharingModes', $props['{' . Plugin::NS_CALENDARSERVER . '}allowed-sharing-modes']); + + } + + function testBeforeGetSharedCalendar() { + + $props = $this->server->getProperties('calendars/user1/cal2', [ + '{' . Plugin::NS_CALENDARSERVER . '}shared-url', + '{' . Plugin::NS_CALENDARSERVER . '}invite', + ]); + + $this->assertInstanceOf('Sabre\\CalDAV\\Xml\\Property\\Invite', $props['{' . Plugin::NS_CALENDARSERVER . '}invite']); + //$this->assertInstanceOf('Sabre\\DAV\\Xml\\Property\\Href', $props['{' . Plugin::NS_CALENDARSERVER . '}shared-url']); + + } + + function testUpdateResourceType() { + + $this->caldavBackend->updateInvites(1, + [ + new Sharee([ + 'href' => 'mailto:joe@example.org', + ]) + ] + ); + $result = $this->server->updateProperties('calendars/user1/cal1', [ + '{DAV:}resourcetype' => new DAV\Xml\Property\ResourceType(['{DAV:}collection']) + ]); + + $this->assertEquals([ + '{DAV:}resourcetype' => 200 + ], $result); + + $this->assertEquals(0, count($this->caldavBackend->getInvites(1))); + + } + + function testUpdatePropertiesPassThru() { + + $result = $this->server->updateProperties('calendars/user1/cal3', [ + '{DAV:}foo' => 'bar', + ]); + + $this->assertEquals([ + '{DAV:}foo' => 200, + ], $result); + + } + + function testUnknownMethodNoPOST() { + + $request = HTTP\Sapi::createFromServerArray([ + 'REQUEST_METHOD' => 'PATCH', + 'REQUEST_URI' => '/', + ]); + + $response = $this->request($request); + + $this->assertEquals(501, $response->status, $response->body); + + } + + function testUnknownMethodNoXML() { + + $request = HTTP\Sapi::createFromServerArray([ + 'REQUEST_METHOD' => 'POST', + 'REQUEST_URI' => '/', + 'CONTENT_TYPE' => 'text/plain', + ]); + + $response = $this->request($request); + + $this->assertEquals(501, $response->status, $response->body); + + } + + function testUnknownMethodNoNode() { + + $request = HTTP\Sapi::createFromServerArray([ + 'REQUEST_METHOD' => 'POST', + 'REQUEST_URI' => '/foo', + 'CONTENT_TYPE' => 'text/xml', + ]); + + $response = $this->request($request); + + $this->assertEquals(501, $response->status, $response->body); + + } + + function testShareRequest() { + + $request = new HTTP\Request('POST', '/calendars/user1/cal1', ['Content-Type' => 'text/xml']); + + $xml = << + + + mailto:joe@example.org + Joe Shmoe + + + + mailto:nancy@example.org + + +RRR; + + $request->setBody($xml); + + $response = $this->request($request, 200); + + $this->assertEquals( + [ + new Sharee([ + 'href' => 'mailto:joe@example.org', + 'properties' => [ + '{DAV:}displayname' => 'Joe Shmoe', + ], + 'access' => \Sabre\DAV\Sharing\Plugin::ACCESS_READWRITE, + 'inviteStatus' => \Sabre\DAV\Sharing\Plugin::INVITE_NORESPONSE, + 'comment' => '', + ]), + ], + $this->caldavBackend->getInvites(1) + ); + + // Wiping out tree cache + $this->server->tree->markDirty(''); + + // Verifying that the calendar is now marked shared. + $props = $this->server->getProperties('calendars/user1/cal1', ['{DAV:}resourcetype']); + $this->assertTrue( + $props['{DAV:}resourcetype']->is('{http://calendarserver.org/ns/}shared-owner') + ); + + } + + function testShareRequestNoShareableCalendar() { + + $request = new HTTP\Request( + 'POST', + '/calendars/user1/cal2', + ['Content-Type' => 'text/xml'] + ); + + $xml = ' + + + mailto:joe@example.org + Joe Shmoe + + + + mailto:nancy@example.org + + +'; + + $request->setBody($xml); + + $response = $this->request($request, 403); + + } + + function testInviteReply() { + + $request = HTTP\Sapi::createFromServerArray([ + 'REQUEST_METHOD' => 'POST', + 'REQUEST_URI' => '/calendars/user1', + 'CONTENT_TYPE' => 'text/xml', + ]); + + $xml = ' + + /principals/owner + + +'; + + $request->setBody($xml); + $response = $this->request($request); + $this->assertEquals(200, $response->status, $response->body); + + } + + function testInviteBadXML() { + + $request = HTTP\Sapi::createFromServerArray([ + 'REQUEST_METHOD' => 'POST', + 'REQUEST_URI' => '/calendars/user1', + 'CONTENT_TYPE' => 'text/xml', + ]); + + $xml = ' + + +'; + $request->setBody($xml); + $response = $this->request($request); + $this->assertEquals(400, $response->status, $response->body); + + } + + function testInviteWrongUrl() { + + $request = HTTP\Sapi::createFromServerArray([ + 'REQUEST_METHOD' => 'POST', + 'REQUEST_URI' => '/calendars/user1/cal1', + 'CONTENT_TYPE' => 'text/xml', + ]); + + $xml = ' + + /principals/owner + +'; + $request->setBody($xml); + $response = $this->request($request); + $this->assertEquals(501, $response->status, $response->body); + + // If the plugin did not handle this request, it must ensure that the + // body is still accessible by other plugins. + $this->assertEquals($xml, $request->getBody(true)); + + } + + function testPublish() { + + $request = new HTTP\Request('POST', '/calendars/user1/cal1', ['Content-Type' => 'text/xml']); + + $xml = ' + +'; + + $request->setBody($xml); + + $response = $this->request($request); + $this->assertEquals(202, $response->status, $response->body); + + } + + + function testUnpublish() { + + $request = new HTTP\Request( + 'POST', + '/calendars/user1/cal1', + ['Content-Type' => 'text/xml'] + ); + + $xml = ' + +'; + + $request->setBody($xml); + + $response = $this->request($request); + $this->assertEquals(200, $response->status, $response->body); + + } + + function testPublishWrongUrl() { + + $request = new HTTP\Request( + 'POST', + '/calendars/user1', + ['Content-Type' => 'text/xml'] + ); + + $xml = ' + +'; + + $request->setBody($xml); + $this->request($request, 501); + + } + + function testUnpublishWrongUrl() { + + $request = new HTTP\Request( + 'POST', + '/calendars/user1', + ['Content-Type' => 'text/xml'] + ); + $xml = ' + +'; + + $request->setBody($xml); + + $this->request($request, 501); + + } + + function testUnknownXmlDoc() { + + + $request = new HTTP\Request( + 'POST', + '/calendars/user1/cal2', + ['Content-Type' => 'text/xml'] + ); + + $xml = ' +'; + + $request->setBody($xml); + + $response = $this->request($request); + $this->assertEquals(501, $response->status, $response->body); + + } +} diff --git a/vendor/sabre/dav/tests/Sabre/CalDAV/Subscriptions/CreateSubscriptionTest.php b/vendor/sabre/dav/tests/Sabre/CalDAV/Subscriptions/CreateSubscriptionTest.php new file mode 100644 index 000000000..8ad0f8ac5 --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/CalDAV/Subscriptions/CreateSubscriptionTest.php @@ -0,0 +1,123 @@ + + + + + + + + + + #1C4587FF + Jewish holidays + Foo + 19 + + webcal://www.example.org/ + + P1W + + + + +XML; + + $headers = [ + 'Content-Type' => 'application/xml', + ]; + $request = new Request('MKCOL', '/calendars/user1/subscription1', $headers, $body); + + $response = $this->request($request); + $this->assertEquals(201, $response->getStatus()); + $subscriptions = $this->caldavBackend->getSubscriptionsForUser('principals/user1'); + $this->assertSubscription($subscriptions[0]); + + + } + /** + * OS X 10.9.2 and up + */ + function testMKCALENDAR() { + + $body = << + + + + + + + + + + + + P1W + + webcal://www.example.org/ + + #1C4587FF + 19 + Foo + + Jewish holidays + + + +XML; + + $headers = [ + 'Content-Type' => 'application/xml', + ]; + $request = new Request('MKCALENDAR', '/calendars/user1/subscription1', $headers, $body); + + $response = $this->request($request); + $this->assertEquals(201, $response->getStatus()); + $subscriptions = $this->caldavBackend->getSubscriptionsForUser('principals/user1'); + $this->assertSubscription($subscriptions[0]); + + // Also seeing if it works when calling this as a PROPFIND. + $this->assertEquals([ + '{http://calendarserver.org/ns/}subscribed-strip-alarms' => '', + ], + $this->server->getProperties('calendars/user1/subscription1', ['{http://calendarserver.org/ns/}subscribed-strip-alarms']) + ); + + + } + + function assertSubscription($subscription) { + + $this->assertEquals('', $subscription['{http://calendarserver.org/ns/}subscribed-strip-attachments']); + $this->assertEquals('', $subscription['{http://calendarserver.org/ns/}subscribed-strip-todos']); + $this->assertEquals('#1C4587FF', $subscription['{http://apple.com/ns/ical/}calendar-color']); + $this->assertEquals('Jewish holidays', $subscription['{DAV:}displayname']); + $this->assertEquals('Foo', $subscription['{urn:ietf:params:xml:ns:caldav}calendar-description']); + $this->assertEquals('19', $subscription['{http://apple.com/ns/ical/}calendar-order']); + $this->assertEquals('webcal://www.example.org/', $subscription['{http://calendarserver.org/ns/}source']->getHref()); + $this->assertEquals('P1W', $subscription['{http://apple.com/ns/ical/}refreshrate']); + $this->assertEquals('subscription1', $subscription['uri']); + $this->assertEquals('principals/user1', $subscription['principaluri']); + $this->assertEquals('webcal://www.example.org/', $subscription['source']); + $this->assertEquals(['principals/user1', 1], $subscription['id']); + + } + +} diff --git a/vendor/sabre/dav/tests/Sabre/CalDAV/Subscriptions/PluginTest.php b/vendor/sabre/dav/tests/Sabre/CalDAV/Subscriptions/PluginTest.php new file mode 100644 index 000000000..dc6d2d5f0 --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/CalDAV/Subscriptions/PluginTest.php @@ -0,0 +1,50 @@ +addPlugin($plugin); + + $this->assertEquals( + '{http://calendarserver.org/ns/}subscribed', + $server->resourceTypeMapping['Sabre\\CalDAV\\Subscriptions\\ISubscription'] + ); + $this->assertEquals( + 'Sabre\\DAV\\Xml\\Property\\Href', + $server->xml->elementMap['{http://calendarserver.org/ns/}source'] + ); + + $this->assertEquals( + ['calendarserver-subscribed'], + $plugin->getFeatures() + ); + + $this->assertEquals( + 'subscriptions', + $plugin->getPluginInfo()['name'] + ); + + } + + function testPropFind() { + + $propName = '{http://calendarserver.org/ns/}subscribed-strip-alarms'; + $propFind = new PropFind('foo', [$propName]); + $propFind->set($propName, null, 200); + + $plugin = new Plugin(); + $plugin->propFind($propFind, new \Sabre\DAV\SimpleCollection('hi')); + + $this->assertFalse(is_null($propFind->get($propName))); + + } + +} diff --git a/vendor/sabre/dav/tests/Sabre/CalDAV/Subscriptions/SubscriptionTest.php b/vendor/sabre/dav/tests/Sabre/CalDAV/Subscriptions/SubscriptionTest.php new file mode 100644 index 000000000..559d526cd --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/CalDAV/Subscriptions/SubscriptionTest.php @@ -0,0 +1,131 @@ + new Href('http://example.org/src', false), + 'lastmodified' => date('2013-04-06 11:40:00'), // tomorrow is my birthday! + '{DAV:}displayname' => 'displayname', + ]; + + + $id = $caldavBackend->createSubscription('principals/user1', 'uri', array_merge($info, $override)); + $subInfo = $caldavBackend->getSubscriptionsForUser('principals/user1'); + + $this->assertEquals(1, count($subInfo)); + $subscription = new Subscription($caldavBackend, $subInfo[0]); + + $this->backend = $caldavBackend; + return $subscription; + + } + + function testValues() { + + $sub = $this->getSub(); + + $this->assertEquals('uri', $sub->getName()); + $this->assertEquals(date('2013-04-06 11:40:00'), $sub->getLastModified()); + $this->assertEquals([], $sub->getChildren()); + + $this->assertEquals( + [ + '{DAV:}displayname' => 'displayname', + '{http://calendarserver.org/ns/}source' => new Href('http://example.org/src', false), + ], + $sub->getProperties(['{DAV:}displayname', '{http://calendarserver.org/ns/}source']) + ); + + $this->assertEquals('principals/user1', $sub->getOwner()); + $this->assertNull($sub->getGroup()); + + $acl = [ + [ + 'privilege' => '{DAV:}all', + 'principal' => 'principals/user1', + 'protected' => true, + ], + [ + 'privilege' => '{DAV:}all', + 'principal' => 'principals/user1/calendar-proxy-write', + 'protected' => true, + ], + [ + 'privilege' => '{DAV:}read', + 'principal' => 'principals/user1/calendar-proxy-read', + 'protected' => true, + ] + ]; + $this->assertEquals($acl, $sub->getACL()); + + $this->assertNull($sub->getSupportedPrivilegeSet()); + + } + + function testValues2() { + + $sub = $this->getSub([ + 'lastmodified' => null, + ]); + + $this->assertEquals(null, $sub->getLastModified()); + + } + + /** + * @expectedException \Sabre\DAV\Exception\Forbidden + */ + function testSetACL() { + + $sub = $this->getSub(); + $sub->setACL([]); + + } + + function testDelete() { + + $sub = $this->getSub(); + $sub->delete(); + + $this->assertEquals([], $this->backend->getSubscriptionsForUser('principals1/user1')); + + } + + function testUpdateProperties() { + + $sub = $this->getSub(); + $propPatch = new PropPatch([ + '{DAV:}displayname' => 'foo', + ]); + $sub->propPatch($propPatch); + $this->assertTrue($propPatch->commit()); + + $this->assertEquals( + 'foo', + $this->backend->getSubscriptionsForUser('principals/user1')[0]['{DAV:}displayname'] + ); + + } + + /** + * @expectedException \InvalidArgumentException + */ + function testBadConstruct() { + + $caldavBackend = new \Sabre\CalDAV\Backend\MockSubscriptionSupport([], []); + new Subscription($caldavBackend, []); + + } + +} diff --git a/vendor/sabre/dav/tests/Sabre/CalDAV/TestUtil.php b/vendor/sabre/dav/tests/Sabre/CalDAV/TestUtil.php new file mode 100644 index 000000000..673d39c0a --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/CalDAV/TestUtil.php @@ -0,0 +1,189 @@ +createCalendar( + 'principals/user1', + 'UUID-123467', + [ + '{DAV:}displayname' => 'user1 calendar', + '{urn:ietf:params:xml:ns:caldav}calendar-description' => 'Calendar description', + '{http://apple.com/ns/ical/}calendar-order' => '1', + '{http://apple.com/ns/ical/}calendar-color' => '#FF0000', + ] + ); + $backend->createCalendar( + 'principals/user1', + 'UUID-123468', + [ + '{DAV:}displayname' => 'user1 calendar2', + '{urn:ietf:params:xml:ns:caldav}calendar-description' => 'Calendar description', + '{http://apple.com/ns/ical/}calendar-order' => '1', + '{http://apple.com/ns/ical/}calendar-color' => '#FF0000', + ] + ); + $backend->createCalendarObject($calendarId, 'UUID-2345', self::getTestCalendarData()); + return $backend; + + } + + static function getTestCalendarData($type = 1) { + + $calendarData = 'BEGIN:VCALENDAR +VERSION:2.0 +PRODID:-//Apple Inc.//iCal 4.0.1//EN +CALSCALE:GREGORIAN +BEGIN:VTIMEZONE +TZID:Asia/Seoul +BEGIN:DAYLIGHT +TZOFFSETFROM:+0900 +RRULE:FREQ=YEARLY;UNTIL=19880507T150000Z;BYMONTH=5;BYDAY=2SU +DTSTART:19870510T000000 +TZNAME:GMT+09:00 +TZOFFSETTO:+1000 +END:DAYLIGHT +BEGIN:STANDARD +TZOFFSETFROM:+1000 +DTSTART:19881009T000000 +TZNAME:GMT+09:00 +TZOFFSETTO:+0900 +END:STANDARD +END:VTIMEZONE +BEGIN:VEVENT +CREATED:20100225T154229Z +UID:39A6B5ED-DD51-4AFE-A683-C35EE3749627 +TRANSP:TRANSPARENT +SUMMARY:Something here +DTSTAMP:20100228T130202Z'; + + switch ($type) { + case 1 : + $calendarData .= "\nDTSTART;TZID=Asia/Seoul:20100223T060000\nDTEND;TZID=Asia/Seoul:20100223T070000\n"; + break; + case 2 : + $calendarData .= "\nDTSTART:20100223T060000\nDTEND:20100223T070000\n"; + break; + case 3 : + $calendarData .= "\nDTSTART;VALUE=DATE:20100223\nDTEND;VALUE=DATE:20100223\n"; + break; + case 4 : + $calendarData .= "\nDTSTART;TZID=Asia/Seoul:20100223T060000\nDURATION:PT1H\n"; + break; + case 5 : + $calendarData .= "\nDTSTART;TZID=Asia/Seoul:20100223T060000\nDURATION:-P5D\n"; + break; + case 6 : + $calendarData .= "\nDTSTART;VALUE=DATE:20100223\n"; + break; + case 7 : + $calendarData .= "\nDTSTART;VALUE=DATETIME:20100223T060000\n"; + break; + + // No DTSTART, so intentionally broken + case 'X' : + $calendarData .= "\n"; + break; + } + + + $calendarData .= 'ATTENDEE;PARTSTAT=NEEDS-ACTION:mailto:lisa@example.com +SEQUENCE:2 +END:VEVENT +END:VCALENDAR'; + + return $calendarData; + + } + + static function getTestTODO($type = 'due') { + + switch ($type) { + + case 'due' : + $extra = "DUE:20100104T000000Z"; + break; + case 'due2' : + $extra = "DUE:20060104T000000Z"; + break; + case 'due_date' : + $extra = "DUE;VALUE=DATE:20060104"; + break; + case 'due_tz' : + $extra = "DUE;TZID=Asia/Seoul:20060104T000000Z"; + break; + case 'due_dtstart' : + $extra = "DTSTART:20050223T060000Z\nDUE:20060104T000000Z"; + break; + case 'due_dtstart2' : + $extra = "DTSTART:20090223T060000Z\nDUE:20100104T000000Z"; + break; + case 'dtstart' : + $extra = 'DTSTART:20100223T060000Z'; + break; + case 'dtstart2' : + $extra = 'DTSTART:20060223T060000Z'; + break; + case 'dtstart_date' : + $extra = 'DTSTART;VALUE=DATE:20100223'; + break; + case 'dtstart_tz' : + $extra = 'DTSTART;TZID=Asia/Seoul:20100223T060000Z'; + break; + case 'dtstart_duration' : + $extra = "DTSTART:20061023T060000Z\nDURATION:PT1H"; + break; + case 'dtstart_duration2' : + $extra = "DTSTART:20101023T060000Z\nDURATION:PT1H"; + break; + case 'completed' : + $extra = 'COMPLETED:20060601T000000Z'; + break; + case 'completed2' : + $extra = 'COMPLETED:20090601T000000Z'; + break; + case 'created' : + $extra = 'CREATED:20060601T000000Z'; + break; + case 'created2' : + $extra = 'CREATED:20090601T000000Z'; + break; + case 'completedcreated' : + $extra = "CREATED:20060601T000000Z\nCOMPLETED:20070101T000000Z"; + break; + case 'completedcreated2' : + $extra = "CREATED:20090601T000000Z\nCOMPLETED:20100101T000000Z"; + break; + case 'notime' : + $extra = 'X-FILLER:oh hello'; + break; + default : + throw new Exception('Unknown type: ' . $type); + + } + + $todo = 'BEGIN:VCALENDAR +VERSION:2.0 +PRODID:-//Example Corp.//CalDAV Client//EN +BEGIN:VTODO +DTSTAMP:20060205T235335Z +' . $extra . ' +STATUS:NEEDS-ACTION +SUMMARY:Task #1 +UID:DDDEEB7915FA61233B861457@example.com +BEGIN:VALARM +ACTION:AUDIO +TRIGGER;RELATED=START:-PT10M +END:VALARM +END:VTODO +END:VCALENDAR'; + + return $todo; + + } + +} diff --git a/vendor/sabre/dav/tests/Sabre/CalDAV/ValidateICalTest.php b/vendor/sabre/dav/tests/Sabre/CalDAV/ValidateICalTest.php new file mode 100644 index 000000000..629df90c1 --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/CalDAV/ValidateICalTest.php @@ -0,0 +1,406 @@ + 'calendar1', + 'principaluri' => 'principals/admin', + 'uri' => 'calendar1', + '{urn:ietf:params:xml:ns:caldav}supported-calendar-component-set' => new Xml\Property\SupportedCalendarComponentSet(['VEVENT', 'VTODO', 'VJOURNAL']), + ], + [ + 'id' => 'calendar2', + 'principaluri' => 'principals/admin', + 'uri' => 'calendar2', + '{urn:ietf:params:xml:ns:caldav}supported-calendar-component-set' => new Xml\Property\SupportedCalendarComponentSet(['VTODO', 'VJOURNAL']), + ] + ]; + + $this->calBackend = new Backend\Mock($calendars, []); + $principalBackend = new DAVACL\PrincipalBackend\Mock(); + + $tree = [ + new CalendarRoot($principalBackend, $this->calBackend), + ]; + + $this->server = new DAV\Server($tree); + $this->server->sapi = new HTTP\SapiMock(); + $this->server->debugExceptions = true; + + $plugin = new Plugin(); + $this->server->addPlugin($plugin); + + $response = new HTTP\ResponseMock(); + $this->server->httpResponse = $response; + + } + + function request(HTTP\Request $request) { + + $this->server->httpRequest = $request; + $this->server->exec(); + + return $this->server->httpResponse; + + } + + function testCreateFile() { + + $request = HTTP\Sapi::createFromServerArray([ + 'REQUEST_METHOD' => 'PUT', + 'REQUEST_URI' => '/calendars/admin/calendar1/blabla.ics', + ]); + + $response = $this->request($request); + + $this->assertEquals(415, $response->status); + + } + + function testCreateFileValid() { + + $request = new HTTP\Request( + 'PUT', + '/calendars/admin/calendar1/blabla.ics', + ['Prefer' => 'handling=strict'] + ); + + $ics = <<setBody($ics); + + $response = $this->request($request); + + $this->assertEquals(201, $response->status, 'Incorrect status returned! Full response body: ' . $response->body); + $this->assertEquals([ + 'X-Sabre-Version' => [DAV\Version::VERSION], + 'Content-Length' => ['0'], + 'ETag' => ['"' . md5($ics) . '"'], + ], $response->getHeaders()); + + $expected = [ + 'uri' => 'blabla.ics', + 'calendardata' => $ics, + 'calendarid' => 'calendar1', + 'lastmodified' => null, + ]; + + $this->assertEquals($expected, $this->calBackend->getCalendarObject('calendar1', 'blabla.ics')); + + } + + function testCreateFileNoVersion() { + + $request = new HTTP\Request( + 'PUT', + '/calendars/admin/calendar1/blabla.ics', + ['Prefer' => 'handling=strict'] + ); + + $ics = <<setBody($ics); + + $response = $this->request($request); + + $this->assertEquals(415, $response->status, 'Incorrect status returned! Full response body: ' . $response->body); + + } + + function testCreateFileNoVersionFixed() { + + $request = new HTTP\Request( + 'PUT', + '/calendars/admin/calendar1/blabla.ics', + ['Prefer' => 'handling=lenient'] + ); + + $ics = <<setBody($ics); + + $response = $this->request($request); + + $this->assertEquals(201, $response->status, 'Incorrect status returned! Full response body: ' . $response->body); + $this->assertEquals([ + 'X-Sabre-Version' => [DAV\Version::VERSION], + 'Content-Length' => ['0'], + 'X-Sabre-Ew-Gross' => ['iCalendar validation warning: VERSION MUST appear exactly once in a VCALENDAR component'], + ], $response->getHeaders()); + + $ics = << 'blabla.ics', + 'calendardata' => $ics, + 'calendarid' => 'calendar1', + 'lastmodified' => null, + ]; + + $this->assertEquals($expected, $this->calBackend->getCalendarObject('calendar1', 'blabla.ics')); + + } + + function testCreateFileNoComponents() { + + $request = new HTTP\Request( + 'PUT', + '/calendars/admin/calendar1/blabla.ics', + ['Prefer' => 'handling=strict'] + ); + $ics = <<setBody($ics); + + $response = $this->request($request); + $this->assertEquals(403, $response->status, 'Incorrect status returned! Full response body: ' . $response->body); + + } + + function testCreateFileNoUID() { + + $request = HTTP\Sapi::createFromServerArray([ + 'REQUEST_METHOD' => 'PUT', + 'REQUEST_URI' => '/calendars/admin/calendar1/blabla.ics', + ]); + $request->setBody("BEGIN:VCALENDAR\r\nBEGIN:VEVENT\r\nEND:VEVENT\r\nEND:VCALENDAR\r\n"); + + $response = $this->request($request); + + $this->assertEquals(415, $response->status, 'Incorrect status returned! Full response body: ' . $response->body); + + } + + function testCreateFileVCard() { + + $request = HTTP\Sapi::createFromServerArray([ + 'REQUEST_METHOD' => 'PUT', + 'REQUEST_URI' => '/calendars/admin/calendar1/blabla.ics', + ]); + $request->setBody("BEGIN:VCARD\r\nEND:VCARD\r\n"); + + $response = $this->request($request); + + $this->assertEquals(415, $response->status, 'Incorrect status returned! Full response body: ' . $response->body); + + } + + function testCreateFile2Components() { + + $request = HTTP\Sapi::createFromServerArray([ + 'REQUEST_METHOD' => 'PUT', + 'REQUEST_URI' => '/calendars/admin/calendar1/blabla.ics', + ]); + $request->setBody("BEGIN:VCALENDAR\r\nBEGIN:VEVENT\r\nUID:foo\r\nEND:VEVENT\r\nBEGIN:VJOURNAL\r\nUID:foo\r\nEND:VJOURNAL\r\nEND:VCALENDAR\r\n"); + + $response = $this->request($request); + + $this->assertEquals(415, $response->status, 'Incorrect status returned! Full response body: ' . $response->body); + + } + + function testCreateFile2UIDS() { + + $request = HTTP\Sapi::createFromServerArray([ + 'REQUEST_METHOD' => 'PUT', + 'REQUEST_URI' => '/calendars/admin/calendar1/blabla.ics', + ]); + $request->setBody("BEGIN:VCALENDAR\r\nBEGIN:VTIMEZONE\r\nEND:VTIMEZONE\r\nBEGIN:VEVENT\r\nUID:foo\r\nEND:VEVENT\r\nBEGIN:VEVENT\r\nUID:bar\r\nEND:VEVENT\r\nEND:VCALENDAR\r\n"); + + $response = $this->request($request); + + $this->assertEquals(415, $response->status, 'Incorrect status returned! Full response body: ' . $response->body); + + } + + function testCreateFileWrongComponent() { + + $request = HTTP\Sapi::createFromServerArray([ + 'REQUEST_METHOD' => 'PUT', + 'REQUEST_URI' => '/calendars/admin/calendar1/blabla.ics', + ]); + $request->setBody("BEGIN:VCALENDAR\r\nBEGIN:VTIMEZONE\r\nEND:VTIMEZONE\r\nBEGIN:VFREEBUSY\r\nUID:foo\r\nEND:VFREEBUSY\r\nEND:VCALENDAR\r\n"); + + $response = $this->request($request); + + $this->assertEquals(403, $response->status, 'Incorrect status returned! Full response body: ' . $response->body); + + } + + function testUpdateFile() { + + $this->calBackend->createCalendarObject('calendar1', 'blabla.ics', 'foo'); + $request = HTTP\Sapi::createFromServerArray([ + 'REQUEST_METHOD' => 'PUT', + 'REQUEST_URI' => '/calendars/admin/calendar1/blabla.ics', + ]); + + $response = $this->request($request); + + $this->assertEquals(415, $response->status); + + } + + function testUpdateFileParsableBody() { + + $this->calBackend->createCalendarObject('calendar1', 'blabla.ics', 'foo'); + $request = new HTTP\Request( + 'PUT', + '/calendars/admin/calendar1/blabla.ics' + ); + $ics = <<setBody($ics); + $response = $this->request($request); + + $this->assertEquals(204, $response->status); + + $expected = [ + 'uri' => 'blabla.ics', + 'calendardata' => $ics, + 'calendarid' => 'calendar1', + 'lastmodified' => null, + ]; + + $this->assertEquals($expected, $this->calBackend->getCalendarObject('calendar1', 'blabla.ics')); + + } + + function testCreateFileInvalidComponent() { + + $request = HTTP\Sapi::createFromServerArray([ + 'REQUEST_METHOD' => 'PUT', + 'REQUEST_URI' => '/calendars/admin/calendar2/blabla.ics', + ]); + $request->setBody("BEGIN:VCALENDAR\r\nBEGIN:VTIMEZONE\r\nEND:VTIMEZONE\r\nBEGIN:VEVENT\r\nUID:foo\r\nEND:VEVENT\r\nEND:VCALENDAR\r\n"); + + $response = $this->request($request); + + $this->assertEquals(403, $response->status, 'Incorrect status returned! Full response body: ' . $response->body); + + } + + function testUpdateFileInvalidComponent() { + + $this->calBackend->createCalendarObject('calendar2', 'blabla.ics', 'foo'); + $request = HTTP\Sapi::createFromServerArray([ + 'REQUEST_METHOD' => 'PUT', + 'REQUEST_URI' => '/calendars/admin/calendar2/blabla.ics', + ]); + $request->setBody("BEGIN:VCALENDAR\r\nBEGIN:VTIMEZONE\r\nEND:VTIMEZONE\r\nBEGIN:VEVENT\r\nUID:foo\r\nEND:VEVENT\r\nEND:VCALENDAR\r\n"); + + $response = $this->request($request); + + $this->assertEquals(403, $response->status, 'Incorrect status returned! Full response body: ' . $response->body); + + } + + /** + * What we are testing here, is if we send in a latin1 character, the + * server should automatically transform this into UTF-8. + * + * More importantly. If any transformation happens, the etag must no longer + * be returned by the server. + */ + function testCreateFileModified() { + + $request = new HTTP\Request( + 'PUT', + '/calendars/admin/calendar1/blabla.ics' + ); + $ics = <<setBody($ics); + + $response = $this->request($request); + + $this->assertEquals(201, $response->status, 'Incorrect status returned! Full response body: ' . $response->body); + $this->assertNull($response->getHeader('ETag')); + + } +} diff --git a/vendor/sabre/dav/tests/Sabre/CalDAV/Xml/Notification/InviteReplyTest.php b/vendor/sabre/dav/tests/Sabre/CalDAV/Xml/Notification/InviteReplyTest.php new file mode 100644 index 000000000..cd700893d --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/CalDAV/Xml/Notification/InviteReplyTest.php @@ -0,0 +1,146 @@ +assertEquals('foo', $notification->getId()); + $this->assertEquals('"1"', $notification->getETag()); + + $simpleExpected = '' . "\n" . ''; + + $writer = new Writer(); + $writer->namespaceMap = [ + 'http://calendarserver.org/ns/' => 'cs', + ]; + $writer->openMemory(); + $writer->startDocument('1.0', 'UTF-8'); + $writer->startElement('{http://calendarserver.org/ns/}root'); + $writer->write($notification); + $writer->endElement(); + + $this->assertEquals($simpleExpected, $writer->outputMemory()); + + $writer = new Writer(); + $writer->contextUri = '/'; + $writer->namespaceMap = [ + 'http://calendarserver.org/ns/' => 'cs', + 'DAV:' => 'd', + ]; + $writer->openMemory(); + $writer->startDocument('1.0', 'UTF-8'); + $writer->startElement('{http://calendarserver.org/ns/}root'); + $notification->xmlSerializeFull($writer); + $writer->endElement(); + + $this->assertXmlStringEqualsXmlString($expected, $writer->outputMemory()); + + + } + + function dataProvider() { + + $dtStamp = new \DateTime('2012-01-01 00:00:00 GMT'); + return [ + [ + [ + 'id' => 'foo', + 'dtStamp' => $dtStamp, + 'etag' => '"1"', + 'inReplyTo' => 'bar', + 'href' => 'mailto:foo@example.org', + 'type' => DAV\Sharing\Plugin::INVITE_ACCEPTED, + 'hostUrl' => 'calendar' + ], +<< + + 20120101T000000Z + + foo + bar + mailto:foo@example.org + + + /calendar + + + + +FOO + ], + [ + [ + 'id' => 'foo', + 'dtStamp' => $dtStamp, + 'etag' => '"1"', + 'inReplyTo' => 'bar', + 'href' => 'mailto:foo@example.org', + 'type' => DAV\Sharing\Plugin::INVITE_DECLINED, + 'hostUrl' => 'calendar', + 'summary' => 'Summary!' + ], +<< + + 20120101T000000Z + + foo + bar + mailto:foo@example.org + + + /calendar + + Summary! + + + +FOO + ], + + ]; + + } + + /** + * @expectedException InvalidArgumentException + */ + function testMissingArg() { + + new InviteReply([]); + + } + + /** + * @expectedException InvalidArgumentException + */ + function testUnknownArg() { + + new InviteReply([ + 'foo-i-will-break' => true, + + 'id' => 1, + 'etag' => '"bla"', + 'href' => 'abc', + 'dtStamp' => 'def', + 'inReplyTo' => 'qrs', + 'type' => 'ghi', + 'hostUrl' => 'jkl', + ]); + + } + +} diff --git a/vendor/sabre/dav/tests/Sabre/CalDAV/Xml/Notification/InviteTest.php b/vendor/sabre/dav/tests/Sabre/CalDAV/Xml/Notification/InviteTest.php new file mode 100644 index 000000000..f03093916 --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/CalDAV/Xml/Notification/InviteTest.php @@ -0,0 +1,165 @@ +assertEquals('foo', $notification->getId()); + $this->assertEquals('"1"', $notification->getETag()); + + $simpleExpected = '' . "\n"; + $this->namespaceMap['http://calendarserver.org/ns/'] = 'cs'; + + $xml = $this->write($notification); + + $this->assertXmlStringEqualsXmlString($simpleExpected, $xml); + + $this->namespaceMap['urn:ietf:params:xml:ns:caldav'] = 'cal'; + $xml = $this->writeFull($notification); + + $this->assertXmlStringEqualsXmlString($expected, $xml); + + + } + + function dataProvider() { + + $dtStamp = new \DateTime('2012-01-01 00:00:00', new \DateTimeZone('GMT')); + return [ + [ + [ + 'id' => 'foo', + 'dtStamp' => $dtStamp, + 'etag' => '"1"', + 'href' => 'mailto:foo@example.org', + 'type' => DAV\Sharing\Plugin::INVITE_ACCEPTED, + 'readOnly' => true, + 'hostUrl' => 'calendar', + 'organizer' => 'principal/user1', + 'commonName' => 'John Doe', + 'summary' => 'Awesome stuff!' + ], +<< + + 20120101T000000Z + + foo + mailto:foo@example.org + + + /calendar + + Awesome stuff! + + + + + /principal/user1 + John Doe + + John Doe + + + +FOO + ], + [ + [ + 'id' => 'foo', + 'dtStamp' => $dtStamp, + 'etag' => '"1"', + 'href' => 'mailto:foo@example.org', + 'type' => DAV\Sharing\Plugin::INVITE_NORESPONSE, + 'readOnly' => true, + 'hostUrl' => 'calendar', + 'organizer' => 'principal/user1', + 'firstName' => 'Foo', + 'lastName' => 'Bar', + ], +<< + + 20120101T000000Z + + foo + mailto:foo@example.org + + + /calendar + + + + + + /principal/user1 + Foo + Bar + + Foo + Bar + + + +FOO + ], + + ]; + + } + + /** + * @expectedException InvalidArgumentException + */ + function testMissingArg() { + + new Invite([]); + + } + + /** + * @expectedException InvalidArgumentException + */ + function testUnknownArg() { + + new Invite([ + 'foo-i-will-break' => true, + + 'id' => 1, + 'etag' => '"bla"', + 'href' => 'abc', + 'dtStamp' => 'def', + 'type' => 'ghi', + 'readOnly' => true, + 'hostUrl' => 'jkl', + 'organizer' => 'mno', + ]); + + } + + function writeFull($input) { + + $writer = new Writer(); + $writer->contextUri = '/'; + $writer->namespaceMap = $this->namespaceMap; + $writer->openMemory(); + $writer->startElement('{http://calendarserver.org/ns/}root'); + $input->xmlSerializeFull($writer); + $writer->endElement(); + return $writer->outputMemory(); + + } +} diff --git a/vendor/sabre/dav/tests/Sabre/CalDAV/Xml/Notification/SystemStatusTest.php b/vendor/sabre/dav/tests/Sabre/CalDAV/Xml/Notification/SystemStatusTest.php new file mode 100644 index 000000000..1f9034340 --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/CalDAV/Xml/Notification/SystemStatusTest.php @@ -0,0 +1,69 @@ +assertEquals('foo', $notification->getId()); + $this->assertEquals('"1"', $notification->getETag()); + + $writer = new Writer(); + $writer->namespaceMap = [ + 'http://calendarserver.org/ns/' => 'cs', + ]; + $writer->openMemory(); + $writer->startDocument('1.0', 'UTF-8'); + $writer->startElement('{http://calendarserver.org/ns/}root'); + $writer->write($notification); + $writer->endElement(); + $this->assertXmlStringEqualsXmlString($expected1, $writer->outputMemory()); + + $writer = new Writer(); + $writer->namespaceMap = [ + 'http://calendarserver.org/ns/' => 'cs', + 'DAV:' => 'd', + ]; + $writer->openMemory(); + $writer->startDocument('1.0', 'UTF-8'); + $writer->startElement('{http://calendarserver.org/ns/}root'); + $notification->xmlSerializeFull($writer); + $writer->endElement(); + $this->assertXmlStringEqualsXmlString($expected2, $writer->outputMemory()); + + } + + function dataProvider() { + + return [ + + [ + new SystemStatus('foo', '"1"'), + '' . "\n" . '' . "\n", + '' . "\n" . '' . "\n", + ], + [ + new SystemStatus('foo', '"1"', SystemStatus::TYPE_MEDIUM, 'bar'), + '' . "\n" . '' . "\n", + '' . "\n" . 'bar' . "\n", + ], + [ + new SystemStatus('foo', '"1"', SystemStatus::TYPE_LOW, null, 'http://example.org/'), + '' . "\n" . '' . "\n", + '' . "\n" . 'http://example.org/' . "\n", + ] + ]; + + } + +} diff --git a/vendor/sabre/dav/tests/Sabre/CalDAV/Xml/Property/AllowedSharingModesTest.php b/vendor/sabre/dav/tests/Sabre/CalDAV/Xml/Property/AllowedSharingModesTest.php new file mode 100644 index 000000000..0602d4f24 --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/CalDAV/Xml/Property/AllowedSharingModesTest.php @@ -0,0 +1,38 @@ +assertInstanceOf('Sabre\CalDAV\Xml\Property\AllowedSharingModes', $sccs); + + } + + /** + * @depends testSimple + */ + function testSerialize() { + + $property = new AllowedSharingModes(true, true); + + $this->namespaceMap[CalDAV\Plugin::NS_CALDAV] = 'cal'; + $this->namespaceMap[CalDAV\Plugin::NS_CALENDARSERVER] = 'cs'; + $xml = $this->write(['{DAV:}root' => $property]); + + $this->assertXmlStringEqualsXmlString( +' + + + + +', $xml); + + } + +} diff --git a/vendor/sabre/dav/tests/Sabre/CalDAV/Xml/Property/EmailAddressSetTest.php b/vendor/sabre/dav/tests/Sabre/CalDAV/Xml/Property/EmailAddressSetTest.php new file mode 100644 index 000000000..30651a080 --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/CalDAV/Xml/Property/EmailAddressSetTest.php @@ -0,0 +1,40 @@ + 'cs', + 'DAV:' => 'd', + ]; + + function testSimple() { + + $eas = new EmailAddressSet(['foo@example.org']); + $this->assertEquals(['foo@example.org'], $eas->getValue()); + + } + + /** + * @depends testSimple + */ + function testSerialize() { + + $property = new EmailAddressSet(['foo@example.org']); + + $xml = $this->write([ + '{DAV:}root' => $property + ]); + + $this->assertXmlStringEqualsXmlString( +' + +foo@example.org +', $xml); + + } + +} diff --git a/vendor/sabre/dav/tests/Sabre/CalDAV/Xml/Property/InviteTest.php b/vendor/sabre/dav/tests/Sabre/CalDAV/Xml/Property/InviteTest.php new file mode 100644 index 000000000..1397dcca2 --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/CalDAV/Xml/Property/InviteTest.php @@ -0,0 +1,112 @@ +namespaceMap[CalDAV\Plugin::NS_CALDAV] = 'cal'; + $this->namespaceMap[CalDAV\Plugin::NS_CALENDARSERVER] = 'cs'; + + + } + + function testSimple() { + + $invite = new Invite([]); + $this->assertInstanceOf('Sabre\CalDAV\Xml\Property\Invite', $invite); + $this->assertEquals([], $invite->getValue()); + + } + + /** + * @depends testSimple + */ + function testSerialize() { + + $property = new Invite([ + new Sharee([ + 'href' => 'mailto:thedoctor@example.org', + 'properties' => ['{DAV:}displayname' => 'The Doctor'], + 'inviteStatus' => SP::INVITE_ACCEPTED, + 'access' => SP::ACCESS_SHAREDOWNER, + ]), + new Sharee([ + 'href' => 'mailto:user1@example.org', + 'inviteStatus' => SP::INVITE_ACCEPTED, + 'access' => SP::ACCESS_READWRITE, + ]), + new Sharee([ + 'href' => 'mailto:user2@example.org', + 'properties' => ['{DAV:}displayname' => 'John Doe'], + 'inviteStatus' => SP::INVITE_DECLINED, + 'access' => SP::ACCESS_READ, + ]), + new Sharee([ + 'href' => 'mailto:user3@example.org', + 'properties' => ['{DAV:}displayname' => 'Joe Shmoe'], + 'inviteStatus' => SP::INVITE_NORESPONSE, + 'access' => SP::ACCESS_READ, + 'comment' => 'Something, something', + ]), + new Sharee([ + 'href' => 'mailto:user4@example.org', + 'properties' => ['{DAV:}displayname' => 'Hoe Boe'], + 'inviteStatus' => SP::INVITE_INVALID, + 'access' => SP::ACCESS_READ, + ]), + ]); + + $xml = $this->write(['{DAV:}root' => $property]); + + $this->assertXmlStringEqualsXmlString( +' + + + mailto:thedoctor@example.org + The Doctor + + + + + + + mailto:user1@example.org + + + + + + + mailto:user2@example.org + John Doe + + + + + + + mailto:user3@example.org + Joe Shmoe + Something, something + + + + + + + mailto:user4@example.org + Hoe Boe + + +', $xml); + + } + +} diff --git a/vendor/sabre/dav/tests/Sabre/CalDAV/Xml/Property/ScheduleCalendarTranspTest.php b/vendor/sabre/dav/tests/Sabre/CalDAV/Xml/Property/ScheduleCalendarTranspTest.php new file mode 100644 index 000000000..729db4569 --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/CalDAV/Xml/Property/ScheduleCalendarTranspTest.php @@ -0,0 +1,118 @@ +namespaceMap[CalDAV\Plugin::NS_CALDAV] = 'cal'; + $this->namespaceMap[CalDAV\Plugin::NS_CALENDARSERVER] = 'cs'; + + + } + + function testSimple() { + + $prop = new ScheduleCalendarTransp(ScheduleCalendarTransp::OPAQUE); + $this->assertEquals( + ScheduleCalendarTransp::OPAQUE, + $prop->getValue() + ); + + } + + /** + * @expectedException \InvalidArgumentException + */ + function testBadValue() { + + new ScheduleCalendarTransp('ahhh'); + + } + + /** + * @depends testSimple + */ + function testSerializeOpaque() { + + $property = new ScheduleCalendarTransp(ScheduleCalendarTransp::OPAQUE); + $xml = $this->write(['{DAV:}root' => $property]); + + $this->assertXmlStringEqualsXmlString( +' + + + +', $xml); + + } + + /** + * @depends testSimple + */ + function testSerializeTransparent() { + + $property = new ScheduleCalendarTransp(ScheduleCalendarTransp::TRANSPARENT); + $xml = $this->write(['{DAV:}root' => $property]); + + $this->assertXmlStringEqualsXmlString( +' + + + +', $xml); + + } + + function testUnserializeTransparent() { + + $cal = CalDAV\Plugin::NS_CALDAV; + $cs = CalDAV\Plugin::NS_CALENDARSERVER; + +$xml = << + + + +XML; + + $result = $this->parse( + $xml, + ['{DAV:}root' => 'Sabre\\CalDAV\\Xml\\Property\\ScheduleCalendarTransp'] + ); + + $this->assertEquals( + new ScheduleCalendarTransp(ScheduleCalendarTransp::TRANSPARENT), + $result['value'] + ); + + } + + function testUnserializeOpaque() { + + $cal = CalDAV\Plugin::NS_CALDAV; + $cs = CalDAV\Plugin::NS_CALENDARSERVER; + +$xml = << + + + +XML; + + $result = $this->parse( + $xml, + ['{DAV:}root' => 'Sabre\\CalDAV\\Xml\\Property\\ScheduleCalendarTransp'] + ); + + $this->assertEquals( + new ScheduleCalendarTransp(ScheduleCalendarTransp::OPAQUE), + $result['value'] + ); + + } +} diff --git a/vendor/sabre/dav/tests/Sabre/CalDAV/Xml/Property/SupportedCalendarComponentSetTest.php b/vendor/sabre/dav/tests/Sabre/CalDAV/Xml/Property/SupportedCalendarComponentSetTest.php new file mode 100644 index 000000000..1acc402d3 --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/CalDAV/Xml/Property/SupportedCalendarComponentSetTest.php @@ -0,0 +1,102 @@ +namespaceMap[CalDAV\Plugin::NS_CALDAV] = 'cal'; + $this->namespaceMap[CalDAV\Plugin::NS_CALENDARSERVER] = 'cs'; + + } + + function testSimple() { + + $prop = new SupportedCalendarComponentSet(['VEVENT']); + $this->assertEquals( + ['VEVENT'], + $prop->getValue() + ); + + } + + function testMultiple() { + + $prop = new SupportedCalendarComponentSet(['VEVENT', 'VTODO']); + $this->assertEquals( + ['VEVENT', 'VTODO'], + $prop->getValue() + ); + + } + + /** + * @depends testSimple + * @depends testMultiple + */ + function testSerialize() { + + $property = new SupportedCalendarComponentSet(['VEVENT', 'VTODO']); + $xml = $this->write(['{DAV:}root' => $property]); + + $this->assertXmlStringEqualsXmlString( +' + + + + +', $xml); + + } + + function testUnserialize() { + + $cal = CalDAV\Plugin::NS_CALDAV; + $cs = CalDAV\Plugin::NS_CALENDARSERVER; + +$xml = << + + + + +XML; + + $result = $this->parse( + $xml, + ['{DAV:}root' => 'Sabre\\CalDAV\\Xml\\Property\\SupportedCalendarComponentSet'] + ); + + $this->assertEquals( + new SupportedCalendarComponentSet(['VEVENT', 'VTODO']), + $result['value'] + ); + + } + + /** + * @expectedException \Sabre\Xml\ParseException + */ + function testUnserializeEmpty() { + + $cal = CalDAV\Plugin::NS_CALDAV; + $cs = CalDAV\Plugin::NS_CALENDARSERVER; + +$xml = << + + +XML; + + $result = $this->parse( + $xml, + ['{DAV:}root' => 'Sabre\\CalDAV\\Xml\\Property\\SupportedCalendarComponentSet'] + ); + + } + +} diff --git a/vendor/sabre/dav/tests/Sabre/CalDAV/Xml/Property/SupportedCalendarDataTest.php b/vendor/sabre/dav/tests/Sabre/CalDAV/Xml/Property/SupportedCalendarDataTest.php new file mode 100644 index 000000000..442b6a059 --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/CalDAV/Xml/Property/SupportedCalendarDataTest.php @@ -0,0 +1,36 @@ +assertInstanceOf('Sabre\CalDAV\Xml\Property\SupportedCalendarData', $sccs); + + } + + /** + * @depends testSimple + */ + function testSerialize() { + + $this->namespaceMap[CalDAV\Plugin::NS_CALDAV] = 'cal'; + $property = new SupportedCalendarData(); + + $xml = $this->write(['{DAV:}root' => $property]); + + $this->assertXmlStringEqualsXmlString( +' + + + +', $xml); + + } + +} diff --git a/vendor/sabre/dav/tests/Sabre/CalDAV/Xml/Property/SupportedCollationSetTest.php b/vendor/sabre/dav/tests/Sabre/CalDAV/Xml/Property/SupportedCollationSetTest.php new file mode 100644 index 000000000..e009fb6cd --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/CalDAV/Xml/Property/SupportedCollationSetTest.php @@ -0,0 +1,37 @@ +assertInstanceOf('Sabre\CalDAV\Xml\Property\SupportedCollationSet', $scs); + + } + + /** + * @depends testSimple + */ + function testSerialize() { + + $property = new SupportedCollationSet(); + + $this->namespaceMap[CalDAV\Plugin::NS_CALDAV] = 'cal'; + $xml = $this->write(['{DAV:}root' => $property]); + + $this->assertXmlStringEqualsXmlString( +' + +i;ascii-casemap +i;octet +i;unicode-casemap +', $xml); + + } + +} diff --git a/vendor/sabre/dav/tests/Sabre/CalDAV/Xml/Request/CalendarQueryReportTest.php b/vendor/sabre/dav/tests/Sabre/CalDAV/Xml/Request/CalendarQueryReportTest.php new file mode 100644 index 000000000..d5e87db85 --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/CalDAV/Xml/Request/CalendarQueryReportTest.php @@ -0,0 +1,369 @@ + 'Sabre\\CalDAV\\Xml\\Request\CalendarQueryReport', + ]; + + function testDeserialize() { + + $xml = << + + + + + + + + +XML; + + $result = $this->parse($xml); + $calendarQueryReport = new CalendarQueryReport(); + $calendarQueryReport->properties = [ + '{DAV:}getetag', + ]; + $calendarQueryReport->filters = [ + 'name' => 'VCALENDAR', + 'is-not-defined' => false, + 'comp-filters' => [], + 'prop-filters' => [], + 'time-range' => false, + ]; + + $this->assertEquals( + $calendarQueryReport, + $result['value'] + ); + + } + + /** + * @expectedException Sabre\DAV\Exception\BadRequest + */ + function testDeserializeNoFilter() { + + $xml = << + + + + + +XML; + + $this->parse($xml); + + } + + function testDeserializeComplex() { + + $xml = << + + + + + + + + + + + + + + + + + + + + + + hi + + + + + + + + + + Hello + + + + + +XML; + + $result = $this->parse($xml); + $calendarQueryReport = new CalendarQueryReport(); + $calendarQueryReport->version = '2.0'; + $calendarQueryReport->contentType = 'application/json+calendar'; + $calendarQueryReport->properties = [ + '{DAV:}getetag', + '{urn:ietf:params:xml:ns:caldav}calendar-data', + ]; + $calendarQueryReport->expand = [ + 'start' => new DateTimeImmutable('2015-01-01 00:00:00', new DateTimeZone('UTC')), + 'end' => new DateTimeImmutable('2016-01-01 00:00:00', new DateTimeZone('UTC')), + ]; + $calendarQueryReport->filters = [ + 'name' => 'VCALENDAR', + 'is-not-defined' => false, + 'comp-filters' => [ + [ + 'name' => 'VEVENT', + 'is-not-defined' => false, + 'comp-filters' => [ + [ + 'name' => 'VALARM', + 'is-not-defined' => true, + 'comp-filters' => [], + 'prop-filters' => [], + 'time-range' => false, + ], + ], + 'prop-filters' => [ + [ + 'name' => 'UID', + 'is-not-defined' => false, + 'time-range' => false, + 'text-match' => null, + 'param-filters' => [], + ], + [ + 'name' => 'X-PROP', + 'is-not-defined' => false, + 'time-range' => false, + 'text-match' => null, + 'param-filters' => [ + [ + 'name' => 'X-PARAM', + 'is-not-defined' => false, + 'text-match' => null, + ], + [ + 'name' => 'X-PARAM2', + 'is-not-defined' => true, + 'text-match' => null, + ], + [ + 'name' => 'X-PARAM3', + 'is-not-defined' => false, + 'text-match' => [ + 'negate-condition' => true, + 'collation' => 'i;ascii-casemap', + 'value' => 'hi', + ], + ], + ], + ], + [ + 'name' => 'X-PROP2', + 'is-not-defined' => true, + 'time-range' => false, + 'text-match' => null, + 'param-filters' => [], + ], + [ + 'name' => 'X-PROP3', + 'is-not-defined' => false, + 'time-range' => [ + 'start' => new DateTimeImmutable('2015-01-01 00:00:00', new DateTimeZone('UTC')), + 'end' => new DateTimeImmutable('2016-01-01 00:00:00', new DateTimeZone('UTC')), + ], + 'text-match' => null, + 'param-filters' => [], + ], + [ + 'name' => 'X-PROP4', + 'is-not-defined' => false, + 'time-range' => false, + 'text-match' => [ + 'negate-condition' => false, + 'collation' => 'i;ascii-casemap', + 'value' => 'Hello', + ], + 'param-filters' => [], + ], + ], + 'time-range' => [ + 'start' => new DateTimeImmutable('2015-01-01 00:00:00', new DateTimeZone('UTC')), + 'end' => new DateTimeImmutable('2016-01-01 00:00:00', new DateTimeZone('UTC')), + ] + ], + ], + 'prop-filters' => [], + 'time-range' => false, + ]; + + $this->assertEquals( + $calendarQueryReport, + $result['value'] + ); + + } + + /** + * @expectedException \Sabre\DAV\Exception\BadRequest + */ + function testDeserializeDoubleTopCompFilter() { + + $xml = << + + + + + + + + + + + + +XML; + + $this->parse($xml); + + } + + /** + * @expectedException \Sabre\DAV\Exception\BadRequest + */ + function testDeserializeMissingExpandEnd() { + + $xml = << + + + + + + + + + + + +XML; + + $this->parse($xml); + + } + + /** + * @expectedException \Sabre\DAV\Exception\BadRequest + */ + function testDeserializeExpandEndBeforeStart() { + + $xml = << + + + + + + + + + + + +XML; + + $this->parse($xml); + + } + + /** + * @expectedException \Sabre\DAV\Exception\BadRequest + */ + function testDeserializeTimeRangeOnVCALENDAR() { + + $xml = << + + + + + + + + + + + +XML; + + $this->parse($xml); + + } + + /** + * @expectedException \Sabre\DAV\Exception\BadRequest + */ + function testDeserializeTimeRangeEndBeforeStart() { + + $xml = << + + + + + + + + + + + + + +XML; + + $this->parse($xml); + + } + + /** + * @expectedException \Sabre\DAV\Exception\BadRequest + */ + function testDeserializeTimeRangePropEndBeforeStart() { + + $xml = << + + + + + + + + + + + + + + + +XML; + + $this->parse($xml); + + } +} diff --git a/vendor/sabre/dav/tests/Sabre/CalDAV/Xml/Request/InviteReplyTest.php b/vendor/sabre/dav/tests/Sabre/CalDAV/Xml/Request/InviteReplyTest.php new file mode 100644 index 000000000..b07708999 --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/CalDAV/Xml/Request/InviteReplyTest.php @@ -0,0 +1,78 @@ + 'Sabre\\CalDAV\\Xml\\Request\\InviteReply', + ]; + + function testDeserialize() { + + $xml = << + + /principal/1 + /calendar/1 + + blabla + Summary + +XML; + + $result = $this->parse($xml); + $inviteReply = new InviteReply('/principal/1', '/calendar/1', 'blabla', 'Summary', DAV\Sharing\Plugin::INVITE_ACCEPTED); + + $this->assertEquals( + $inviteReply, + $result['value'] + ); + + } + + function testDeserializeDeclined() { + + $xml = << + + /principal/1 + /calendar/1 + + blabla + Summary + +XML; + + $result = $this->parse($xml); + $inviteReply = new InviteReply('/principal/1', '/calendar/1', 'blabla', 'Summary', DAV\Sharing\Plugin::INVITE_DECLINED); + + $this->assertEquals( + $inviteReply, + $result['value'] + ); + + } + + /** + * @expectedException \Sabre\DAV\Exception\BadRequest + */ + function testDeserializeNoHostUrl() { + + $xml = << + + /principal/1 + + blabla + Summary + +XML; + + $this->parse($xml); + + } +} diff --git a/vendor/sabre/dav/tests/Sabre/CalDAV/Xml/Request/ShareTest.php b/vendor/sabre/dav/tests/Sabre/CalDAV/Xml/Request/ShareTest.php new file mode 100644 index 000000000..73a2c3a13 --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/CalDAV/Xml/Request/ShareTest.php @@ -0,0 +1,83 @@ + 'Sabre\\CalDAV\\Xml\\Request\\Share', + ]; + + function testDeserialize() { + + $xml = << + + + mailto:eric@example.com + Eric York + Shared workspace + + + + mailto:foo@bar + + +XML; + + $result = $this->parse($xml); + $share = new Share([ + new Sharee([ + 'href' => 'mailto:eric@example.com', + 'access' => \Sabre\DAV\Sharing\Plugin::ACCESS_READWRITE, + 'properties' => [ + '{DAV:}displayname' => 'Eric York', + ], + 'comment' => 'Shared workspace', + ]), + new Sharee([ + 'href' => 'mailto:foo@bar', + 'access' => \Sabre\DAV\Sharing\Plugin::ACCESS_NOACCESS, + ]), + ]); + + $this->assertEquals( + $share, + $result['value'] + ); + + } + + function testDeserializeMinimal() { + + $xml = << + + + mailto:eric@example.com + + + +XML; + + $result = $this->parse($xml); + $share = new Share([ + new Sharee([ + 'href' => 'mailto:eric@example.com', + 'access' => \Sabre\DAV\Sharing\Plugin::ACCESS_READ, + ]), + ]); + + $this->assertEquals( + $share, + $result['value'] + ); + + } + +} diff --git a/vendor/sabre/dav/tests/Sabre/CardDAV/AbstractPluginTest.php b/vendor/sabre/dav/tests/Sabre/CardDAV/AbstractPluginTest.php new file mode 100644 index 000000000..552e2ba77 --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/CardDAV/AbstractPluginTest.php @@ -0,0 +1,43 @@ +backend = new Backend\Mock(); + $principalBackend = new DAVACL\PrincipalBackend\Mock(); + + $tree = [ + new AddressBookRoot($principalBackend, $this->backend), + new DAVACL\PrincipalCollection($principalBackend) + ]; + + $this->plugin = new Plugin(); + $this->plugin->directories = ['directory']; + $this->server = new DAV\Server($tree); + $this->server->sapi = new HTTP\SapiMock(); + $this->server->addPlugin($this->plugin); + $this->server->debugExceptions = true; + + } + +} diff --git a/vendor/sabre/dav/tests/Sabre/CardDAV/AddressBookHomeTest.php b/vendor/sabre/dav/tests/Sabre/CardDAV/AddressBookHomeTest.php new file mode 100644 index 000000000..871f4a457 --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/CardDAV/AddressBookHomeTest.php @@ -0,0 +1,159 @@ +backend = new Backend\Mock(); + $this->s = new AddressBookHome( + $this->backend, + 'principals/user1' + ); + + } + + function testGetName() { + + $this->assertEquals('user1', $this->s->getName()); + + } + + /** + * @expectedException Sabre\DAV\Exception\MethodNotAllowed + */ + function testSetName() { + + $this->s->setName('user2'); + + } + + /** + * @expectedException Sabre\DAV\Exception\MethodNotAllowed + */ + function testDelete() { + + $this->s->delete(); + + } + + function testGetLastModified() { + + $this->assertNull($this->s->getLastModified()); + + } + + /** + * @expectedException Sabre\DAV\Exception\MethodNotAllowed + */ + function testCreateFile() { + + $this->s->createFile('bla'); + + } + + /** + * @expectedException Sabre\DAV\Exception\MethodNotAllowed + */ + function testCreateDirectory() { + + $this->s->createDirectory('bla'); + + } + + function testGetChild() { + + $child = $this->s->getChild('book1'); + $this->assertInstanceOf('Sabre\\CardDAV\\AddressBook', $child); + $this->assertEquals('book1', $child->getName()); + + } + + /** + * @expectedException Sabre\DAV\Exception\NotFound + */ + function testGetChild404() { + + $this->s->getChild('book2'); + + } + + function testGetChildren() { + + $children = $this->s->getChildren(); + $this->assertEquals(2, count($children)); + $this->assertInstanceOf('Sabre\\CardDAV\\AddressBook', $children[0]); + $this->assertEquals('book1', $children[0]->getName()); + + } + + function testCreateExtendedCollection() { + + $resourceType = [ + '{' . Plugin::NS_CARDDAV . '}addressbook', + '{DAV:}collection', + ]; + $this->s->createExtendedCollection('book2', new MkCol($resourceType, ['{DAV:}displayname' => 'a-book 2'])); + + $this->assertEquals([ + 'id' => 'book2', + 'uri' => 'book2', + '{DAV:}displayname' => 'a-book 2', + 'principaluri' => 'principals/user1', + ], $this->backend->addressBooks[2]); + + } + + /** + * @expectedException Sabre\DAV\Exception\InvalidResourceType + */ + function testCreateExtendedCollectionInvalid() { + + $resourceType = [ + '{DAV:}collection', + ]; + $this->s->createExtendedCollection('book2', new MkCol($resourceType, ['{DAV:}displayname' => 'a-book 2'])); + + } + + + function testACLMethods() { + + $this->assertEquals('principals/user1', $this->s->getOwner()); + $this->assertNull($this->s->getGroup()); + $this->assertEquals([ + [ + 'privilege' => '{DAV:}all', + 'principal' => '{DAV:}owner', + 'protected' => true, + ], + ], $this->s->getACL()); + + } + + /** + * @expectedException Sabre\DAV\Exception\Forbidden + */ + function testSetACL() { + + $this->s->setACL([]); + + } + + function testGetSupportedPrivilegeSet() { + + $this->assertNull( + $this->s->getSupportedPrivilegeSet() + ); + + } +} diff --git a/vendor/sabre/dav/tests/Sabre/CardDAV/AddressBookQueryTest.php b/vendor/sabre/dav/tests/Sabre/CardDAV/AddressBookQueryTest.php new file mode 100644 index 000000000..f8da38a16 --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/CardDAV/AddressBookQueryTest.php @@ -0,0 +1,355 @@ + '1'] + ); + + $request->setBody( +' + + + + + + + +' + ); + + $response = new HTTP\ResponseMock(); + + $this->server->httpRequest = $request; + $this->server->httpResponse = $response; + + $this->server->exec(); + + $this->assertEquals(207, $response->status, 'Incorrect status code. Full response body:' . $response->body); + + // using the client for parsing + $client = new DAV\Client(['baseUri' => '/']); + + $result = $client->parseMultiStatus($response->body); + + $this->assertEquals([ + '/addressbooks/user1/book1/card1' => [ + 200 => [ + '{DAV:}getetag' => '"' . md5("BEGIN:VCARD\nVERSION:3.0\nUID:12345\nEND:VCARD") . '"', + ], + ], + '/addressbooks/user1/book1/card2' => [ + 404 => [ + '{DAV:}getetag' => null, + ], + ] + ], $result); + + + } + + function testQueryDepth0() { + + $request = new HTTP\Request( + 'REPORT', + '/addressbooks/user1/book1/card1', + ['Depth' => '0'] + ); + + $request->setBody( +' + + + + + + + +' + ); + + $response = new HTTP\ResponseMock(); + + $this->server->httpRequest = $request; + $this->server->httpResponse = $response; + + $this->server->exec(); + + $this->assertEquals(207, $response->status, 'Incorrect status code. Full response body:' . $response->body); + + // using the client for parsing + $client = new DAV\Client(['baseUri' => '/']); + + $result = $client->parseMultiStatus($response->body); + + $this->assertEquals([ + '/addressbooks/user1/book1/card1' => [ + 200 => [ + '{DAV:}getetag' => '"' . md5("BEGIN:VCARD\nVERSION:3.0\nUID:12345\nEND:VCARD") . '"', + ], + ], + ], $result); + + + } + + function testQueryNoMatch() { + + $request = new HTTP\Request( + 'REPORT', + '/addressbooks/user1/book1', + ['Depth' => '1'] + ); + + $request->setBody( +' + + + + + + + +' + ); + + $response = new HTTP\ResponseMock(); + + $this->server->httpRequest = $request; + $this->server->httpResponse = $response; + + $this->server->exec(); + + $this->assertEquals(207, $response->status, 'Incorrect status code. Full response body:' . $response->body); + + // using the client for parsing + $client = new DAV\Client(['baseUri' => '/']); + + $result = $client->parseMultiStatus($response->body); + + $this->assertEquals([], $result); + + } + + function testQueryLimit() { + + $request = HTTP\Sapi::createFromServerArray([ + 'REQUEST_METHOD' => 'REPORT', + 'REQUEST_URI' => '/addressbooks/user1/book1', + 'HTTP_DEPTH' => '1', + ]); + + $request->setBody( +' + + + + + + + + 1 +' + ); + + $response = new HTTP\ResponseMock(); + + $this->server->httpRequest = $request; + $this->server->httpResponse = $response; + + $this->server->exec(); + + $this->assertEquals(207, $response->status, 'Incorrect status code. Full response body:' . $response->body); + + // using the client for parsing + $client = new DAV\Client(['baseUri' => '/']); + + $result = $client->parseMultiStatus($response->body); + + $this->assertEquals([ + '/addressbooks/user1/book1/card1' => [ + 200 => [ + '{DAV:}getetag' => '"' . md5("BEGIN:VCARD\nVERSION:3.0\nUID:12345\nEND:VCARD") . '"', + ], + ], + ], $result); + + + } + + function testJson() { + + $request = new HTTP\Request( + 'REPORT', + '/addressbooks/user1/book1/card1', + ['Depth' => '0'] + ); + + $request->setBody( +' + + + + + +' + ); + + $response = new HTTP\ResponseMock(); + + $this->server->httpRequest = $request; + $this->server->httpResponse = $response; + + $this->server->exec(); + + $this->assertEquals(207, $response->status, 'Incorrect status code. Full response body:' . $response->body); + + // using the client for parsing + $client = new DAV\Client(['baseUri' => '/']); + + $result = $client->parseMultiStatus($response->body); + + $vobjVersion = \Sabre\VObject\Version::VERSION; + + $this->assertEquals([ + '/addressbooks/user1/book1/card1' => [ + 200 => [ + '{DAV:}getetag' => '"' . md5("BEGIN:VCARD\nVERSION:3.0\nUID:12345\nEND:VCARD") . '"', + '{urn:ietf:params:xml:ns:carddav}address-data' => '["vcard",[["version",{},"text","4.0"],["prodid",{},"text","-\/\/Sabre\/\/Sabre VObject ' . $vobjVersion . '\/\/EN"],["uid",{},"text","12345"]]]', + ], + ], + ], $result); + + } + + function testVCard4() { + + $request = new HTTP\Request( + 'REPORT', + '/addressbooks/user1/book1/card1', + ['Depth' => '0'] + ); + + $request->setBody( +' + + + + + +' + ); + + $response = new HTTP\ResponseMock(); + + $this->server->httpRequest = $request; + $this->server->httpResponse = $response; + + $this->server->exec(); + + $this->assertEquals(207, $response->status, 'Incorrect status code. Full response body:' . $response->body); + + // using the client for parsing + $client = new DAV\Client(['baseUri' => '/']); + + $result = $client->parseMultiStatus($response->body); + + $vobjVersion = \Sabre\VObject\Version::VERSION; + + $this->assertEquals([ + '/addressbooks/user1/book1/card1' => [ + 200 => [ + '{DAV:}getetag' => '"' . md5("BEGIN:VCARD\nVERSION:3.0\nUID:12345\nEND:VCARD") . '"', + '{urn:ietf:params:xml:ns:carddav}address-data' => "BEGIN:VCARD\r\nVERSION:4.0\r\nPRODID:-//Sabre//Sabre VObject $vobjVersion//EN\r\nUID:12345\r\nEND:VCARD\r\n", + ], + ], + ], $result); + + } + + function testAddressBookDepth0() { + + $request = new HTTP\Request( + 'REPORT', + '/addressbooks/user1/book1', + ['Depth' => '0'] + ); + + $request->setBody( + ' + + + + + +' + ); + + $response = new HTTP\ResponseMock(); + + $this->server->httpRequest = $request; + $this->server->httpResponse = $response; + + $this->server->exec(); + + $this->assertEquals(415, $response->status, 'Incorrect status code. Full response body:' . $response->body); + } + + function testAddressBookProperties() { + + $request = new HTTP\Request( + 'REPORT', + '/addressbooks/user1/book3', + ['Depth' => '1'] + ); + + $request->setBody( + ' + + + + + + + + +' + ); + + $response = new HTTP\ResponseMock(); + + $this->server->httpRequest = $request; + $this->server->httpResponse = $response; + + $this->server->exec(); + + $this->assertEquals(207, $response->status, 'Incorrect status code. Full response body:' . $response->body); + + // using the client for parsing + $client = new DAV\Client(['baseUri' => '/']); + + $result = $client->parseMultiStatus($response->body); + + $this->assertEquals([ + '/addressbooks/user1/book3/card3' => [ + 200 => [ + '{DAV:}getetag' => '"' . md5("BEGIN:VCARD\nVERSION:3.0\nUID:12345\nFN:Test-Card\nEMAIL;TYPE=home:bar@example.org\nEND:VCARD") . '"', + '{urn:ietf:params:xml:ns:carddav}address-data' => "BEGIN:VCARD\r\nVERSION:3.0\r\nUID:12345\r\nFN:Test-Card\r\nEND:VCARD\r\n", + ], + ], + ], $result); + + } +} diff --git a/vendor/sabre/dav/tests/Sabre/CardDAV/AddressBookRootTest.php b/vendor/sabre/dav/tests/Sabre/CardDAV/AddressBookRootTest.php new file mode 100644 index 000000000..fc20480f2 --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/CardDAV/AddressBookRootTest.php @@ -0,0 +1,31 @@ +assertEquals('addressbooks', $root->getName()); + + } + + function testGetChildForPrincipal() { + + $pBackend = new DAVACL\PrincipalBackend\Mock(); + $cBackend = new Backend\Mock(); + $root = new AddressBookRoot($pBackend, $cBackend); + + $children = $root->getChildren(); + $this->assertEquals(3, count($children)); + + $this->assertInstanceOf('Sabre\\CardDAV\\AddressBookHome', $children[0]); + $this->assertEquals('user1', $children[0]->getName()); + + } +} diff --git a/vendor/sabre/dav/tests/Sabre/CardDAV/AddressBookTest.php b/vendor/sabre/dav/tests/Sabre/CardDAV/AddressBookTest.php new file mode 100644 index 000000000..1f0064dd3 --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/CardDAV/AddressBookTest.php @@ -0,0 +1,194 @@ +backend = new Backend\Mock(); + $this->ab = new AddressBook( + $this->backend, + [ + 'uri' => 'book1', + 'id' => 'foo', + '{DAV:}displayname' => 'd-name', + 'principaluri' => 'principals/user1', + ] + ); + + } + + function testGetName() { + + $this->assertEquals('book1', $this->ab->getName()); + + } + + function testGetChild() { + + $card = $this->ab->getChild('card1'); + $this->assertInstanceOf('Sabre\\CardDAV\\Card', $card); + $this->assertEquals('card1', $card->getName()); + + } + + /** + * @expectedException Sabre\DAV\Exception\NotFound + */ + function testGetChildNotFound() { + + $card = $this->ab->getChild('card3'); + + } + + function testGetChildren() { + + $cards = $this->ab->getChildren(); + $this->assertEquals(2, count($cards)); + + $this->assertEquals('card1', $cards[0]->getName()); + $this->assertEquals('card2', $cards[1]->getName()); + + } + + /** + * @expectedException Sabre\DAV\Exception\MethodNotAllowed + */ + function testCreateDirectory() { + + $this->ab->createDirectory('name'); + + } + + function testCreateFile() { + + $file = fopen('php://memory', 'r+'); + fwrite($file, 'foo'); + rewind($file); + $this->ab->createFile('card2', $file); + + $this->assertEquals('foo', $this->backend->cards['foo']['card2']); + + } + + function testDelete() { + + $this->ab->delete(); + $this->assertEquals(1, count($this->backend->addressBooks)); + + } + + /** + * @expectedException Sabre\DAV\Exception\MethodNotAllowed + */ + function testSetName() { + + $this->ab->setName('foo'); + + } + + function testGetLastModified() { + + $this->assertNull($this->ab->getLastModified()); + + } + + function testUpdateProperties() { + + $propPatch = new PropPatch([ + '{DAV:}displayname' => 'barrr', + ]); + $this->ab->propPatch($propPatch); + $this->assertTrue($propPatch->commit()); + + $this->assertEquals('barrr', $this->backend->addressBooks[0]['{DAV:}displayname']); + + } + + function testGetProperties() { + + $props = $this->ab->getProperties(['{DAV:}displayname']); + $this->assertEquals([ + '{DAV:}displayname' => 'd-name', + ], $props); + + } + + function testACLMethods() { + + $this->assertEquals('principals/user1', $this->ab->getOwner()); + $this->assertNull($this->ab->getGroup()); + $this->assertEquals([ + [ + 'privilege' => '{DAV:}all', + 'principal' => '{DAV:}owner', + 'protected' => true, + ], + ], $this->ab->getACL()); + + } + + /** + * @expectedException Sabre\DAV\Exception\Forbidden + */ + function testSetACL() { + + $this->ab->setACL([]); + + } + + function testGetSupportedPrivilegeSet() { + + $this->assertNull( + $this->ab->getSupportedPrivilegeSet() + ); + + } + + function testGetSyncTokenNoSyncSupport() { + + $this->assertNull($this->ab->getSyncToken()); + + } + function testGetChangesNoSyncSupport() { + + $this->assertNull($this->ab->getChanges(1, null)); + + } + + function testGetSyncToken() { + + $this->driver = 'sqlite'; + $this->dropTables(['addressbooks', 'cards', 'addressbookchanges']); + $this->createSchema('addressbooks'); + $backend = new Backend\PDO( + $this->getPDO() + ); + $ab = new AddressBook($backend, ['id' => 1, '{DAV:}sync-token' => 2]); + $this->assertEquals(2, $ab->getSyncToken()); + } + + function testGetSyncToken2() { + + $this->driver = 'sqlite'; + $this->dropTables(['addressbooks', 'cards', 'addressbookchanges']); + $this->createSchema('addressbooks'); + $backend = new Backend\PDO( + $this->getPDO() + ); + $ab = new AddressBook($backend, ['id' => 1, '{http://sabredav.org/ns}sync-token' => 2]); + $this->assertEquals(2, $ab->getSyncToken()); + } + +} diff --git a/vendor/sabre/dav/tests/Sabre/CardDAV/Backend/AbstractPDOTest.php b/vendor/sabre/dav/tests/Sabre/CardDAV/Backend/AbstractPDOTest.php new file mode 100644 index 000000000..f62bfb1ae --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/CardDAV/Backend/AbstractPDOTest.php @@ -0,0 +1,373 @@ +dropTables([ + 'addressbooks', + 'cards', + 'addressbookchanges', + ]); + $this->createSchema('addressbooks'); + $pdo = $this->getPDO(); + + $this->backend = new PDO($pdo); + $pdo->exec("INSERT INTO addressbooks (principaluri, displayname, uri, description, synctoken) VALUES ('principals/user1', 'book1', 'book1', 'addressbook 1', 1)"); + $pdo->exec("INSERT INTO cards (addressbookid, carddata, uri, lastmodified, etag, size) VALUES (1, 'card1', 'card1', 0, '" . md5('card1') . "', 5)"); + + } + + function testGetAddressBooksForUser() { + + $result = $this->backend->getAddressBooksForUser('principals/user1'); + + $expected = [ + [ + 'id' => 1, + 'uri' => 'book1', + 'principaluri' => 'principals/user1', + '{DAV:}displayname' => 'book1', + '{' . CardDAV\Plugin::NS_CARDDAV . '}addressbook-description' => 'addressbook 1', + '{http://calendarserver.org/ns/}getctag' => 1, + '{http://sabredav.org/ns}sync-token' => 1 + ] + ]; + + $this->assertEquals($expected, $result); + + } + + function testUpdateAddressBookInvalidProp() { + + $propPatch = new PropPatch([ + '{DAV:}displayname' => 'updated', + '{' . CardDAV\Plugin::NS_CARDDAV . '}addressbook-description' => 'updated', + '{DAV:}foo' => 'bar', + ]); + + $this->backend->updateAddressBook(1, $propPatch); + $result = $propPatch->commit(); + + $this->assertFalse($result); + + $result = $this->backend->getAddressBooksForUser('principals/user1'); + + $expected = [ + [ + 'id' => 1, + 'uri' => 'book1', + 'principaluri' => 'principals/user1', + '{DAV:}displayname' => 'book1', + '{' . CardDAV\Plugin::NS_CARDDAV . '}addressbook-description' => 'addressbook 1', + '{http://calendarserver.org/ns/}getctag' => 1, + '{http://sabredav.org/ns}sync-token' => 1 + ] + ]; + + $this->assertEquals($expected, $result); + + } + + function testUpdateAddressBookNoProps() { + + $propPatch = new PropPatch([ + ]); + + $this->backend->updateAddressBook(1, $propPatch); + $result = $propPatch->commit(); + $this->assertTrue($result); + + $result = $this->backend->getAddressBooksForUser('principals/user1'); + + $expected = [ + [ + 'id' => 1, + 'uri' => 'book1', + 'principaluri' => 'principals/user1', + '{DAV:}displayname' => 'book1', + '{' . CardDAV\Plugin::NS_CARDDAV . '}addressbook-description' => 'addressbook 1', + '{http://calendarserver.org/ns/}getctag' => 1, + '{http://sabredav.org/ns}sync-token' => 1 + ] + ]; + + $this->assertEquals($expected, $result); + + + } + + function testUpdateAddressBookSuccess() { + + $propPatch = new PropPatch([ + '{DAV:}displayname' => 'updated', + '{' . CardDAV\Plugin::NS_CARDDAV . '}addressbook-description' => 'updated', + ]); + + $this->backend->updateAddressBook(1, $propPatch); + $result = $propPatch->commit(); + + $this->assertTrue($result); + + $result = $this->backend->getAddressBooksForUser('principals/user1'); + + $expected = [ + [ + 'id' => 1, + 'uri' => 'book1', + 'principaluri' => 'principals/user1', + '{DAV:}displayname' => 'updated', + '{' . CardDAV\Plugin::NS_CARDDAV . '}addressbook-description' => 'updated', + '{http://calendarserver.org/ns/}getctag' => 2, + '{http://sabredav.org/ns}sync-token' => 2 + ] + ]; + + $this->assertEquals($expected, $result); + + + } + + function testDeleteAddressBook() { + + $this->backend->deleteAddressBook(1); + + $this->assertEquals([], $this->backend->getAddressBooksForUser('principals/user1')); + + } + + /** + * @expectedException Sabre\DAV\Exception\BadRequest + */ + function testCreateAddressBookUnsupportedProp() { + + $this->backend->createAddressBook('principals/user1', 'book2', [ + '{DAV:}foo' => 'bar', + ]); + + } + + function testCreateAddressBookSuccess() { + + $this->backend->createAddressBook('principals/user1', 'book2', [ + '{DAV:}displayname' => 'book2', + '{' . CardDAV\Plugin::NS_CARDDAV . '}addressbook-description' => 'addressbook 2', + ]); + + $expected = [ + [ + 'id' => 1, + 'uri' => 'book1', + 'principaluri' => 'principals/user1', + '{DAV:}displayname' => 'book1', + '{' . CardDAV\Plugin::NS_CARDDAV . '}addressbook-description' => 'addressbook 1', + '{http://calendarserver.org/ns/}getctag' => 1, + '{http://sabredav.org/ns}sync-token' => 1, + ], + [ + 'id' => 2, + 'uri' => 'book2', + 'principaluri' => 'principals/user1', + '{DAV:}displayname' => 'book2', + '{' . CardDAV\Plugin::NS_CARDDAV . '}addressbook-description' => 'addressbook 2', + '{http://calendarserver.org/ns/}getctag' => 1, + '{http://sabredav.org/ns}sync-token' => 1, + ] + ]; + $result = $this->backend->getAddressBooksForUser('principals/user1'); + $this->assertEquals($expected, $result); + + } + + function testGetCards() { + + $result = $this->backend->getCards(1); + + $expected = [ + [ + 'id' => 1, + 'uri' => 'card1', + 'lastmodified' => 0, + 'etag' => '"' . md5('card1') . '"', + 'size' => 5 + ] + ]; + + $this->assertEquals($expected, $result); + + } + + function testGetCard() { + + $result = $this->backend->getCard(1, 'card1'); + + $expected = [ + 'id' => 1, + 'uri' => 'card1', + 'carddata' => 'card1', + 'lastmodified' => 0, + 'etag' => '"' . md5('card1') . '"', + 'size' => 5 + ]; + + if (is_resource($result['carddata'])) { + $result['carddata'] = stream_get_contents($result['carddata']); + } + + $this->assertEquals($expected, $result); + + } + + /** + * @depends testGetCard + */ + function testCreateCard() { + + $result = $this->backend->createCard(1, 'card2', 'data2'); + $this->assertEquals('"' . md5('data2') . '"', $result); + $result = $this->backend->getCard(1, 'card2'); + $this->assertEquals(2, $result['id']); + $this->assertEquals('card2', $result['uri']); + if (is_resource($result['carddata'])) { + $result['carddata'] = stream_get_contents($result['carddata']); + } + $this->assertEquals('data2', $result['carddata']); + + } + + /** + * @depends testCreateCard + */ + function testGetMultiple() { + + $result = $this->backend->createCard(1, 'card2', 'data2'); + $result = $this->backend->createCard(1, 'card3', 'data3'); + $check = [ + [ + 'id' => 1, + 'uri' => 'card1', + 'carddata' => 'card1', + 'lastmodified' => 0, + ], + [ + 'id' => 2, + 'uri' => 'card2', + 'carddata' => 'data2', + 'lastmodified' => time(), + ], + [ + 'id' => 3, + 'uri' => 'card3', + 'carddata' => 'data3', + 'lastmodified' => time(), + ], + ]; + + $result = $this->backend->getMultipleCards(1, ['card1', 'card2', 'card3']); + + foreach ($check as $index => $node) { + + foreach ($node as $k => $v) { + + $expected = $v; + $actual = $result[$index][$k]; + + switch ($k) { + case 'lastmodified' : + $this->assertInternalType('int', $actual); + break; + case 'carddata' : + if (is_resource($actual)) { + $actual = stream_get_contents($actual); + } + // No break intended. + default : + $this->assertEquals($expected, $actual); + break; + } + + } + + } + + + } + + /** + * @depends testGetCard + */ + function testUpdateCard() { + + $result = $this->backend->updateCard(1, 'card1', 'newdata'); + $this->assertEquals('"' . md5('newdata') . '"', $result); + + $result = $this->backend->getCard(1, 'card1'); + $this->assertEquals(1, $result['id']); + if (is_resource($result['carddata'])) { + $result['carddata'] = stream_get_contents($result['carddata']); + } + $this->assertEquals('newdata', $result['carddata']); + + } + + /** + * @depends testGetCard + */ + function testDeleteCard() { + + $this->backend->deleteCard(1, 'card1'); + $result = $this->backend->getCard(1, 'card1'); + $this->assertFalse($result); + + } + + function testGetChanges() { + + $backend = $this->backend; + $id = $backend->createAddressBook( + 'principals/user1', + 'bla', + [] + ); + $result = $backend->getChangesForAddressBook($id, null, 1); + + $this->assertEquals([ + 'syncToken' => 1, + "added" => [], + 'modified' => [], + 'deleted' => [], + ], $result); + + $currentToken = $result['syncToken']; + + $dummyCard = "BEGIN:VCARD\r\nEND:VCARD\r\n"; + + $backend->createCard($id, "card1.ics", $dummyCard); + $backend->createCard($id, "card2.ics", $dummyCard); + $backend->createCard($id, "card3.ics", $dummyCard); + $backend->updateCard($id, "card1.ics", $dummyCard); + $backend->deleteCard($id, "card2.ics"); + + $result = $backend->getChangesForAddressBook($id, $currentToken, 1); + + $this->assertEquals([ + 'syncToken' => 6, + 'modified' => ["card1.ics"], + 'deleted' => ["card2.ics"], + "added" => ["card3.ics"], + ], $result); + + } +} diff --git a/vendor/sabre/dav/tests/Sabre/CardDAV/Backend/Mock.php b/vendor/sabre/dav/tests/Sabre/CardDAV/Backend/Mock.php new file mode 100644 index 000000000..8638dc74a --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/CardDAV/Backend/Mock.php @@ -0,0 +1,258 @@ +addressBooks = $addressBooks; + $this->cards = $cards; + + if (is_null($this->addressBooks)) { + $this->addressBooks = [ + [ + 'id' => 'foo', + 'uri' => 'book1', + 'principaluri' => 'principals/user1', + '{DAV:}displayname' => 'd-name', + ], + [ + 'id' => 'bar', + 'uri' => 'book3', + 'principaluri' => 'principals/user1', + '{DAV:}displayname' => 'd-name', + ], + ]; + + $card2 = fopen('php://memory', 'r+'); + fwrite($card2, "BEGIN:VCARD\nVERSION:3.0\nUID:45678\nEND:VCARD"); + rewind($card2); + $this->cards = [ + 'foo' => [ + 'card1' => "BEGIN:VCARD\nVERSION:3.0\nUID:12345\nEND:VCARD", + 'card2' => $card2, + ], + 'bar' => [ + 'card3' => "BEGIN:VCARD\nVERSION:3.0\nUID:12345\nFN:Test-Card\nEMAIL;TYPE=home:bar@example.org\nEND:VCARD", + ], + ]; + } + + } + + + function getAddressBooksForUser($principalUri) { + + $books = []; + foreach ($this->addressBooks as $book) { + if ($book['principaluri'] === $principalUri) { + $books[] = $book; + } + } + return $books; + + } + + /** + * Updates properties for an address book. + * + * The list of mutations is stored in a Sabre\DAV\PropPatch object. + * To do the actual updates, you must tell this object which properties + * you're going to process with the handle() method. + * + * Calling the handle method is like telling the PropPatch object "I + * promise I can handle updating this property". + * + * Read the PropPatch documentation for more info and examples. + * + * @param string $addressBookId + * @param \Sabre\DAV\PropPatch $propPatch + * @return void + */ + function updateAddressBook($addressBookId, \Sabre\DAV\PropPatch $propPatch) { + + foreach ($this->addressBooks as &$book) { + if ($book['id'] !== $addressBookId) + continue; + + $propPatch->handleRemaining(function($mutations) use (&$book) { + foreach ($mutations as $key => $value) { + $book[$key] = $value; + } + return true; + }); + + } + + } + + function createAddressBook($principalUri, $url, array $properties) { + + $this->addressBooks[] = array_merge($properties, [ + 'id' => $url, + 'uri' => $url, + 'principaluri' => $principalUri, + ]); + + } + + function deleteAddressBook($addressBookId) { + + foreach ($this->addressBooks as $key => $value) { + if ($value['id'] === $addressBookId) + unset($this->addressBooks[$key]); + } + unset($this->cards[$addressBookId]); + + } + + /** + * Returns all cards for a specific addressbook id. + * + * This method should return the following properties for each card: + * * carddata - raw vcard data + * * uri - Some unique url + * * lastmodified - A unix timestamp + * + * It's recommended to also return the following properties: + * * etag - A unique etag. This must change every time the card changes. + * * size - The size of the card in bytes. + * + * If these last two properties are provided, less time will be spent + * calculating them. If they are specified, you can also ommit carddata. + * This may speed up certain requests, especially with large cards. + * + * @param mixed $addressBookId + * @return array + */ + function getCards($addressBookId) { + + $cards = []; + foreach ($this->cards[$addressBookId] as $uri => $data) { + if (is_resource($data)) { + $cards[] = [ + 'uri' => $uri, + 'carddata' => $data, + ]; + } else { + $cards[] = [ + 'uri' => $uri, + 'carddata' => $data, + 'etag' => '"' . md5($data) . '"', + 'size' => strlen($data) + ]; + } + } + return $cards; + + } + + /** + * Returns a specfic card. + * + * The same set of properties must be returned as with getCards. The only + * exception is that 'carddata' is absolutely required. + * + * If the card does not exist, you must return false. + * + * @param mixed $addressBookId + * @param string $cardUri + * @return array + */ + function getCard($addressBookId, $cardUri) { + + if (!isset($this->cards[$addressBookId][$cardUri])) { + return false; + } + + $data = $this->cards[$addressBookId][$cardUri]; + return [ + 'uri' => $cardUri, + 'carddata' => $data, + 'etag' => '"' . md5($data) . '"', + 'size' => strlen($data) + ]; + + } + + /** + * Creates a new card. + * + * The addressbook id will be passed as the first argument. This is the + * same id as it is returned from the getAddressBooksForUser method. + * + * The cardUri is a base uri, and doesn't include the full path. The + * cardData argument is the vcard body, and is passed as a string. + * + * It is possible to return an ETag from this method. This ETag is for the + * newly created resource, and must be enclosed with double quotes (that + * is, the string itself must contain the double quotes). + * + * You should only return the ETag if you store the carddata as-is. If a + * subsequent GET request on the same card does not have the same body, + * byte-by-byte and you did return an ETag here, clients tend to get + * confused. + * + * If you don't return an ETag, you can just return null. + * + * @param mixed $addressBookId + * @param string $cardUri + * @param string $cardData + * @return string|null + */ + function createCard($addressBookId, $cardUri, $cardData) { + + if (is_resource($cardData)) { + $cardData = stream_get_contents($cardData); + } + $this->cards[$addressBookId][$cardUri] = $cardData; + return '"' . md5($cardData) . '"'; + + } + + /** + * Updates a card. + * + * The addressbook id will be passed as the first argument. This is the + * same id as it is returned from the getAddressBooksForUser method. + * + * The cardUri is a base uri, and doesn't include the full path. The + * cardData argument is the vcard body, and is passed as a string. + * + * It is possible to return an ETag from this method. This ETag should + * match that of the updated resource, and must be enclosed with double + * quotes (that is: the string itself must contain the actual quotes). + * + * You should only return the ETag if you store the carddata as-is. If a + * subsequent GET request on the same card does not have the same body, + * byte-by-byte and you did return an ETag here, clients tend to get + * confused. + * + * If you don't return an ETag, you can just return null. + * + * @param mixed $addressBookId + * @param string $cardUri + * @param string $cardData + * @return string|null + */ + function updateCard($addressBookId, $cardUri, $cardData) { + + if (is_resource($cardData)) { + $cardData = stream_get_contents($cardData); + } + $this->cards[$addressBookId][$cardUri] = $cardData; + return '"' . md5($cardData) . '"'; + + } + + function deleteCard($addressBookId, $cardUri) { + + unset($this->cards[$addressBookId][$cardUri]); + + } + +} diff --git a/vendor/sabre/dav/tests/Sabre/CardDAV/Backend/PDOMySQLTest.php b/vendor/sabre/dav/tests/Sabre/CardDAV/Backend/PDOMySQLTest.php new file mode 100644 index 000000000..c1b0e274e --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/CardDAV/Backend/PDOMySQLTest.php @@ -0,0 +1,9 @@ +backend = new Backend\Mock(); + $this->card = new Card( + $this->backend, + [ + 'uri' => 'book1', + 'id' => 'foo', + 'principaluri' => 'principals/user1', + ], + [ + 'uri' => 'card1', + 'addressbookid' => 'foo', + 'carddata' => 'card', + ] + ); + + } + + function testGet() { + + $result = $this->card->get(); + $this->assertEquals('card', $result); + + } + function testGet2() { + + $this->card = new Card( + $this->backend, + [ + 'uri' => 'book1', + 'id' => 'foo', + 'principaluri' => 'principals/user1', + ], + [ + 'uri' => 'card1', + 'addressbookid' => 'foo', + ] + ); + $result = $this->card->get(); + $this->assertEquals("BEGIN:VCARD\nVERSION:3.0\nUID:12345\nEND:VCARD", $result); + + } + + + /** + * @depends testGet + */ + function testPut() { + + $file = fopen('php://memory', 'r+'); + fwrite($file, 'newdata'); + rewind($file); + $this->card->put($file); + $result = $this->card->get(); + $this->assertEquals('newdata', $result); + + } + + + function testDelete() { + + $this->card->delete(); + $this->assertEquals(1, count($this->backend->cards['foo'])); + + } + + function testGetContentType() { + + $this->assertEquals('text/vcard; charset=utf-8', $this->card->getContentType()); + + } + + function testGetETag() { + + $this->assertEquals('"' . md5('card') . '"', $this->card->getETag()); + + } + + function testGetETag2() { + + $card = new Card( + $this->backend, + [ + 'uri' => 'book1', + 'id' => 'foo', + 'principaluri' => 'principals/user1', + ], + [ + 'uri' => 'card1', + 'addressbookid' => 'foo', + 'carddata' => 'card', + 'etag' => '"blabla"', + ] + ); + $this->assertEquals('"blabla"', $card->getETag()); + + } + + function testGetLastModified() { + + $this->assertEquals(null, $this->card->getLastModified()); + + } + + function testGetSize() { + + $this->assertEquals(4, $this->card->getSize()); + $this->assertEquals(4, $this->card->getSize()); + + } + + function testGetSize2() { + + $card = new Card( + $this->backend, + [ + 'uri' => 'book1', + 'id' => 'foo', + 'principaluri' => 'principals/user1', + ], + [ + 'uri' => 'card1', + 'addressbookid' => 'foo', + 'etag' => '"blabla"', + 'size' => 4, + ] + ); + $this->assertEquals(4, $card->getSize()); + + } + + function testACLMethods() { + + $this->assertEquals('principals/user1', $this->card->getOwner()); + $this->assertNull($this->card->getGroup()); + $this->assertEquals([ + [ + 'privilege' => '{DAV:}all', + 'principal' => 'principals/user1', + 'protected' => true, + ], + ], $this->card->getACL()); + + } + function testOverrideACL() { + + $card = new Card( + $this->backend, + [ + 'uri' => 'book1', + 'id' => 'foo', + 'principaluri' => 'principals/user1', + ], + [ + 'uri' => 'card1', + 'addressbookid' => 'foo', + 'carddata' => 'card', + 'acl' => [ + [ + 'privilege' => '{DAV:}read', + 'principal' => 'principals/user1', + 'protected' => true, + ], + ], + ] + ); + $this->assertEquals([ + [ + 'privilege' => '{DAV:}read', + 'principal' => 'principals/user1', + 'protected' => true, + ], + ], $card->getACL()); + + } + + /** + * @expectedException Sabre\DAV\Exception\Forbidden + */ + function testSetACL() { + + $this->card->setACL([]); + + } + + function testGetSupportedPrivilegeSet() { + + $this->assertNull( + $this->card->getSupportedPrivilegeSet() + ); + + } + +} diff --git a/vendor/sabre/dav/tests/Sabre/CardDAV/IDirectoryTest.php b/vendor/sabre/dav/tests/Sabre/CardDAV/IDirectoryTest.php new file mode 100644 index 000000000..4796a131f --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/CardDAV/IDirectoryTest.php @@ -0,0 +1,30 @@ +addPlugin($plugin); + + $props = $server->getProperties('directory', ['{DAV:}resourcetype']); + $this->assertTrue($props['{DAV:}resourcetype']->is('{' . Plugin::NS_CARDDAV . '}directory')); + + } + +} + +class DirectoryMock extends DAV\SimpleCollection implements IDirectory { + + + +} diff --git a/vendor/sabre/dav/tests/Sabre/CardDAV/MultiGetTest.php b/vendor/sabre/dav/tests/Sabre/CardDAV/MultiGetTest.php new file mode 100644 index 000000000..2d57c6ae7 --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/CardDAV/MultiGetTest.php @@ -0,0 +1,99 @@ + 'REPORT', + 'REQUEST_URI' => '/addressbooks/user1/book1', + ]); + + $request->setBody( +' + + + + + + /addressbooks/user1/book1/card1 +' + ); + + $response = new HTTP\ResponseMock(); + + $this->server->httpRequest = $request; + $this->server->httpResponse = $response; + + $this->server->exec(); + + $this->assertEquals(207, $response->status, 'Incorrect status code. Full response body:' . $response->body); + + // using the client for parsing + $client = new DAV\Client(['baseUri' => '/']); + + $result = $client->parseMultiStatus($response->body); + + $this->assertEquals([ + '/addressbooks/user1/book1/card1' => [ + 200 => [ + '{DAV:}getetag' => '"' . md5("BEGIN:VCARD\nVERSION:3.0\nUID:12345\nEND:VCARD") . '"', + '{urn:ietf:params:xml:ns:carddav}address-data' => "BEGIN:VCARD\nVERSION:3.0\nUID:12345\nEND:VCARD", + ] + ] + ], $result); + + } + + function testMultiGetVCard4() { + + $request = HTTP\Sapi::createFromServerArray([ + 'REQUEST_METHOD' => 'REPORT', + 'REQUEST_URI' => '/addressbooks/user1/book1', + ]); + + $request->setBody( +' + + + + + + /addressbooks/user1/book1/card1 +' + ); + + $response = new HTTP\ResponseMock(); + + $this->server->httpRequest = $request; + $this->server->httpResponse = $response; + + $this->server->exec(); + + $this->assertEquals(207, $response->status, 'Incorrect status code. Full response body:' . $response->body); + + // using the client for parsing + $client = new DAV\Client(['baseUri' => '/']); + + $result = $client->parseMultiStatus($response->body); + + $prodId = "PRODID:-//Sabre//Sabre VObject " . \Sabre\VObject\Version::VERSION . "//EN"; + + $this->assertEquals([ + '/addressbooks/user1/book1/card1' => [ + 200 => [ + '{DAV:}getetag' => '"' . md5("BEGIN:VCARD\nVERSION:3.0\nUID:12345\nEND:VCARD") . '"', + '{urn:ietf:params:xml:ns:carddav}address-data' => "BEGIN:VCARD\r\nVERSION:4.0\r\n$prodId\r\nUID:12345\r\nEND:VCARD\r\n", + ] + ] + ], $result); + + } +} diff --git a/vendor/sabre/dav/tests/Sabre/CardDAV/PluginTest.php b/vendor/sabre/dav/tests/Sabre/CardDAV/PluginTest.php new file mode 100644 index 000000000..6962e7830 --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/CardDAV/PluginTest.php @@ -0,0 +1,102 @@ +assertEquals('{' . Plugin::NS_CARDDAV . '}addressbook', $this->server->resourceTypeMapping['Sabre\\CardDAV\\IAddressBook']); + + $this->assertTrue(in_array('addressbook', $this->plugin->getFeatures())); + $this->assertEquals('carddav', $this->plugin->getPluginInfo()['name']); + + } + + function testSupportedReportSet() { + + $this->assertEquals([ + '{' . Plugin::NS_CARDDAV . '}addressbook-multiget', + '{' . Plugin::NS_CARDDAV . '}addressbook-query', + ], $this->plugin->getSupportedReportSet('addressbooks/user1/book1')); + + } + + function testSupportedReportSetEmpty() { + + $this->assertEquals([ + ], $this->plugin->getSupportedReportSet('')); + + } + + function testAddressBookHomeSet() { + + $result = $this->server->getProperties('principals/user1', ['{' . Plugin::NS_CARDDAV . '}addressbook-home-set']); + + $this->assertEquals(1, count($result)); + $this->assertTrue(isset($result['{' . Plugin::NS_CARDDAV . '}addressbook-home-set'])); + $this->assertEquals('addressbooks/user1/', $result['{' . Plugin::NS_CARDDAV . '}addressbook-home-set']->getHref()); + + } + + function testDirectoryGateway() { + + $result = $this->server->getProperties('principals/user1', ['{' . Plugin::NS_CARDDAV . '}directory-gateway']); + + $this->assertEquals(1, count($result)); + $this->assertTrue(isset($result['{' . Plugin::NS_CARDDAV . '}directory-gateway'])); + $this->assertEquals(['directory'], $result['{' . Plugin::NS_CARDDAV . '}directory-gateway']->getHrefs()); + + } + + function testReportPassThrough() { + + $this->assertNull($this->plugin->report('{DAV:}foo', new \DomDocument(), '')); + + } + + function testHTMLActionsPanel() { + + $output = ''; + $r = $this->server->emit('onHTMLActionsPanel', [$this->server->tree->getNodeForPath('addressbooks/user1'), &$output]); + $this->assertFalse($r); + + $this->assertTrue(!!strpos($output, 'Display name')); + + } + + function testAddressbookPluginProperties() { + + $ns = '{' . Plugin::NS_CARDDAV . '}'; + $propFind = new DAV\PropFind('addressbooks/user1/book1', [ + $ns . 'supported-address-data', + $ns . 'supported-collation-set', + ]); + $node = $this->server->tree->getNodeForPath('addressbooks/user1/book1'); + $this->plugin->propFindEarly($propFind, $node); + + $this->assertInstanceOf( + 'Sabre\\CardDAV\\Xml\\Property\\SupportedAddressData', + $propFind->get($ns . 'supported-address-data') + ); + $this->assertInstanceOf( + 'Sabre\\CardDAV\\Xml\\Property\\SupportedCollationSet', + $propFind->get($ns . 'supported-collation-set') + ); + + + } + + function testGetTransform() { + + $request = new \Sabre\HTTP\Request('GET', '/addressbooks/user1/book1/card1', ['Accept: application/vcard+json']); + $response = new \Sabre\HTTP\ResponseMock(); + $this->server->invokeMethod($request, $response); + + $this->assertEquals(200, $response->getStatus()); + + } + +} diff --git a/vendor/sabre/dav/tests/Sabre/CardDAV/SogoStripContentTypeTest.php b/vendor/sabre/dav/tests/Sabre/CardDAV/SogoStripContentTypeTest.php new file mode 100644 index 000000000..d4bc48098 --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/CardDAV/SogoStripContentTypeTest.php @@ -0,0 +1,56 @@ + 1, + 'uri' => 'book1', + 'principaluri' => 'principals/user1', + ], + ]; + protected $carddavCards = [ + 1 => [ + 'card1.vcf' => "BEGIN:VCARD\nVERSION:3.0\nUID:12345\nEND:VCARD", + ], + ]; + + function testDontStrip() { + + $result = $this->server->getProperties('addressbooks/user1/book1/card1.vcf', ['{DAV:}getcontenttype']); + $this->assertEquals([ + '{DAV:}getcontenttype' => 'text/vcard; charset=utf-8' + ], $result); + + } + function testStrip() { + + $this->server->httpRequest = HTTP\Sapi::createFromServerArray([ + 'HTTP_USER_AGENT' => 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:10.0.2) Gecko/20120216 Thunderbird/10.0.2 Lightning/1.2.1', + ]); + $result = $this->server->getProperties('addressbooks/user1/book1/card1.vcf', ['{DAV:}getcontenttype']); + $this->assertEquals([ + '{DAV:}getcontenttype' => 'text/x-vcard' + ], $result); + + } + function testDontTouchOtherMimeTypes() { + + $this->server->httpRequest = new HTTP\Request('GET', '/addressbooks/user1/book1/card1.vcf', [ + 'User-Agent' => 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:10.0.2) Gecko/20120216 Thunderbird/10.0.2 Lightning/1.2.1', + ]); + + $propFind = new PropFind('hello', ['{DAV:}getcontenttype']); + $propFind->set('{DAV:}getcontenttype', 'text/plain'); + $this->carddavPlugin->propFindLate($propFind, new \Sabre\DAV\SimpleCollection('foo')); + $this->assertEquals('text/plain', $propFind->get('{DAV:}getcontenttype')); + + } + +} diff --git a/vendor/sabre/dav/tests/Sabre/CardDAV/TestUtil.php b/vendor/sabre/dav/tests/Sabre/CardDAV/TestUtil.php new file mode 100644 index 000000000..ec8a3501e --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/CardDAV/TestUtil.php @@ -0,0 +1,62 @@ +createAddressBook( + 'principals/user1', + 'UUID-123467', + [ + '{DAV:}displayname' => 'user1 addressbook', + '{urn:ietf:params:xml:ns:carddav}addressbook-description' => 'AddressBook description', + ] + ); + $backend->createAddressBook( + 'principals/user1', + 'UUID-123468', + [ + '{DAV:}displayname' => 'user1 addressbook2', + '{urn:ietf:params:xml:ns:carddav}addressbook-description' => 'AddressBook description', + ] + ); + $backend->createCard($addressbookId, 'UUID-2345', self::getTestCardData()); + return $pdo; + + } + + static function deleteSQLiteDB() { + $sqliteTest = new Backend\PDOSqliteTest(); + $pdo = $sqliteTest->tearDown(); + } + + static function getTestCardData() { + + $addressbookData = 'BEGIN:VCARD +VERSION:3.0 +PRODID:-//Acme Inc.//RoadRunner 1.0//EN +FN:Wile E. Coyote +N:Coyote;Wile;Erroll;; +ORG:Acme Inc. +UID:39A6B5ED-DD51-4AFE-A683-C35EE3749627 +REV:2012-06-20T07:00:39+00:00 +END:VCARD'; + + return $addressbookData; + + } + +} diff --git a/vendor/sabre/dav/tests/Sabre/CardDAV/VCFExportTest.php b/vendor/sabre/dav/tests/Sabre/CardDAV/VCFExportTest.php new file mode 100644 index 000000000..82d82fadd --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/CardDAV/VCFExportTest.php @@ -0,0 +1,135 @@ + 'book1', + 'uri' => 'book1', + 'principaluri' => 'principals/user1', + ] + ]; + protected $carddavCards = [ + 'book1' => [ + "card1" => "BEGIN:VCARD\r\nFN:Person1\r\nEND:VCARD\r\n", + "card2" => "BEGIN:VCARD\r\nFN:Person2\r\nEND:VCARD", + "card3" => "BEGIN:VCARD\r\nFN:Person3\r\nEND:VCARD\r\n", + "card4" => "BEGIN:VCARD\nFN:Person4\nEND:VCARD\n", + ] + ]; + + function setUp() { + + parent::setUp(); + $plugin = new VCFExportPlugin(); + $this->server->addPlugin( + $plugin + ); + + } + + function testSimple() { + + $plugin = $this->server->getPlugin('vcf-export'); + $this->assertInstanceOf('Sabre\\CardDAV\\VCFExportPlugin', $plugin); + + $this->assertEquals( + 'vcf-export', + $plugin->getPluginInfo()['name'] + ); + + } + + function testExport() { + + $request = HTTP\Sapi::createFromServerArray([ + 'REQUEST_URI' => '/addressbooks/user1/book1?export', + 'QUERY_STRING' => 'export', + 'REQUEST_METHOD' => 'GET', + ]); + + $response = $this->request($request); + $this->assertEquals(200, $response->status, $response->body); + + $expected = "BEGIN:VCARD +FN:Person1 +END:VCARD +BEGIN:VCARD +FN:Person2 +END:VCARD +BEGIN:VCARD +FN:Person3 +END:VCARD +BEGIN:VCARD +FN:Person4 +END:VCARD +"; + // We actually expected windows line endings + $expected = str_replace("\n", "\r\n", $expected); + + $this->assertEquals($expected, $response->body); + + } + + function testBrowserIntegration() { + + $plugin = $this->server->getPlugin('vcf-export'); + $actions = ''; + $addressbook = new AddressBook($this->carddavBackend, []); + $this->server->emit('browserButtonActions', ['/foo', $addressbook, &$actions]); + $this->assertContains('/foo?export', $actions); + + } + + function testContentDisposition() { + + $request = new HTTP\Request( + 'GET', + '/addressbooks/user1/book1?export' + ); + + $response = $this->request($request, 200); + $this->assertEquals('text/directory', $response->getHeader('Content-Type')); + $this->assertEquals( + 'attachment; filename="book1-' . date('Y-m-d') . '.vcf"', + $response->getHeader('Content-Disposition') + ); + + } + + function testContentDispositionBadChars() { + + $this->carddavBackend->createAddressBook( + 'principals/user1', + 'book-b_ad"(ch)ars', + [] + ); + $this->carddavBackend->createCard( + 'book-b_ad"(ch)ars', + 'card1', + "BEGIN:VCARD\r\nFN:Person1\r\nEND:VCARD\r\n" + ); + + $request = new HTTP\Request( + 'GET', + '/addressbooks/user1/book-b_ad"(ch)ars?export' + ); + + $response = $this->request($request, 200); + $this->assertEquals('text/directory', $response->getHeader('Content-Type')); + $this->assertEquals( + 'attachment; filename="book-b_adchars-' . date('Y-m-d') . '.vcf"', + $response->getHeader('Content-Disposition') + ); + + } + +} diff --git a/vendor/sabre/dav/tests/Sabre/CardDAV/ValidateFilterTest.php b/vendor/sabre/dav/tests/Sabre/CardDAV/ValidateFilterTest.php new file mode 100644 index 000000000..03c468f86 --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/CardDAV/ValidateFilterTest.php @@ -0,0 +1,209 @@ +assertTrue($this->plugin->validateFilters($input, $filters, $test), $message); + } else { + $this->assertFalse($this->plugin->validateFilters($input, $filters, $test), $message); + } + + } + + function data() { + + $body1 = << 'title', 'is-not-defined' => false, 'param-filters' => [], 'text-matches' => []]; + + // Check if FOO is defined + $filter2 = + ['name' => 'foo', 'is-not-defined' => false, 'param-filters' => [], 'text-matches' => []]; + + // Check if TITLE is not defined + $filter3 = + ['name' => 'title', 'is-not-defined' => true, 'param-filters' => [], 'text-matches' => []]; + + // Check if FOO is not defined + $filter4 = + ['name' => 'foo', 'is-not-defined' => true, 'param-filters' => [], 'text-matches' => []]; + + // Check if TEL[TYPE] is defined + $filter5 = + [ + 'name' => 'tel', + 'is-not-defined' => false, + 'test' => 'anyof', + 'param-filters' => [ + [ + 'name' => 'type', + 'is-not-defined' => false, + 'text-match' => null + ], + ], + 'text-matches' => [], + ]; + + // Check if TEL[FOO] is defined + $filter6 = $filter5; + $filter6['param-filters'][0]['name'] = 'FOO'; + + // Check if TEL[TYPE] is not defined + $filter7 = $filter5; + $filter7['param-filters'][0]['is-not-defined'] = true; + + // Check if TEL[FOO] is not defined + $filter8 = $filter5; + $filter8['param-filters'][0]['name'] = 'FOO'; + $filter8['param-filters'][0]['is-not-defined'] = true; + + // Combining property filters + $filter9 = $filter5; + $filter9['param-filters'][] = $filter6['param-filters'][0]; + + $filter10 = $filter5; + $filter10['param-filters'][] = $filter6['param-filters'][0]; + $filter10['test'] = 'allof'; + + // Check if URL contains 'google' + $filter11 = + [ + 'name' => 'url', + 'is-not-defined' => false, + 'test' => 'anyof', + 'param-filters' => [], + 'text-matches' => [ + [ + 'match-type' => 'contains', + 'value' => 'google', + 'negate-condition' => false, + 'collation' => 'i;octet', + ], + ], + ]; + + // Check if URL contains 'bing' + $filter12 = $filter11; + $filter12['text-matches'][0]['value'] = 'bing'; + + // Check if URL does not contain 'google' + $filter13 = $filter11; + $filter13['text-matches'][0]['negate-condition'] = true; + + // Check if URL does not contain 'bing' + $filter14 = $filter11; + $filter14['text-matches'][0]['value'] = 'bing'; + $filter14['text-matches'][0]['negate-condition'] = true; + + // Param filter with text + $filter15 = $filter5; + $filter15['param-filters'][0]['text-match'] = [ + 'match-type' => 'contains', + 'value' => 'WORK', + 'collation' => 'i;octet', + 'negate-condition' => false, + ]; + $filter16 = $filter15; + $filter16['param-filters'][0]['text-match']['negate-condition'] = true; + + + // Param filter + text filter + $filter17 = $filter5; + $filter17['test'] = 'anyof'; + $filter17['text-matches'][] = [ + 'match-type' => 'contains', + 'value' => '444', + 'collation' => 'i;octet', + 'negate-condition' => false, + ]; + + $filter18 = $filter17; + $filter18['text-matches'][0]['negate-condition'] = true; + + $filter18['test'] = 'allof'; + + return [ + + // Basic filters + [$body1, [$filter1], 'anyof',true], + [$body1, [$filter2], 'anyof',false], + [$body1, [$filter3], 'anyof',false], + [$body1, [$filter4], 'anyof',true], + + // Combinations + [$body1, [$filter1, $filter2], 'anyof',true], + [$body1, [$filter1, $filter2], 'allof',false], + [$body1, [$filter1, $filter4], 'anyof',true], + [$body1, [$filter1, $filter4], 'allof',true], + [$body1, [$filter2, $filter3], 'anyof',false], + [$body1, [$filter2, $filter3], 'allof',false], + + // Basic parameters + [$body1, [$filter5], 'anyof', true, 'TEL;TYPE is defined, so this should return true'], + [$body1, [$filter6], 'anyof', false, 'TEL;FOO is not defined, so this should return false'], + + [$body1, [$filter7], 'anyof', false, 'TEL;TYPE is defined, so this should return false'], + [$body1, [$filter8], 'anyof', true, 'TEL;TYPE is not defined, so this should return true'], + + // Combined parameters + [$body1, [$filter9], 'anyof', true], + [$body1, [$filter10], 'anyof', false], + + // Text-filters + [$body1, [$filter11], 'anyof', true], + [$body1, [$filter12], 'anyof', false], + [$body1, [$filter13], 'anyof', false], + [$body1, [$filter14], 'anyof', true], + + // Param filter with text-match + [$body1, [$filter15], 'anyof', true], + [$body1, [$filter16], 'anyof', false], + + // Param filter + text filter + [$body1, [$filter17], 'anyof', true], + [$body1, [$filter18], 'anyof', false], + [$body1, [$filter18], 'anyof', false], + ]; + + } + +} diff --git a/vendor/sabre/dav/tests/Sabre/CardDAV/ValidateVCardTest.php b/vendor/sabre/dav/tests/Sabre/CardDAV/ValidateVCardTest.php new file mode 100644 index 000000000..acba2cfc8 --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/CardDAV/ValidateVCardTest.php @@ -0,0 +1,305 @@ + 'addressbook1', + 'principaluri' => 'principals/admin', + 'uri' => 'addressbook1', + ] + ]; + + $this->cardBackend = new Backend\Mock($addressbooks, []); + $principalBackend = new DAVACL\PrincipalBackend\Mock(); + + $tree = [ + new AddressBookRoot($principalBackend, $this->cardBackend), + ]; + + $this->server = new DAV\Server($tree); + $this->server->sapi = new HTTP\SapiMock(); + $this->server->debugExceptions = true; + + $plugin = new Plugin(); + $this->server->addPlugin($plugin); + + $response = new HTTP\ResponseMock(); + $this->server->httpResponse = $response; + + } + + function request(HTTP\Request $request, $expectedStatus = null) { + + $this->server->httpRequest = $request; + $this->server->exec(); + + if ($expectedStatus) { + + $realStatus = $this->server->httpResponse->getStatus(); + + $msg = ''; + if ($realStatus !== $expectedStatus) { + $msg = 'Response body: ' . $this->server->httpResponse->getBodyAsString(); + } + $this->assertEquals( + $expectedStatus, + $realStatus, + $msg + ); + } + + return $this->server->httpResponse; + + } + + function testCreateFile() { + + $request = HTTP\Sapi::createFromServerArray([ + 'REQUEST_METHOD' => 'PUT', + 'REQUEST_URI' => '/addressbooks/admin/addressbook1/blabla.vcf', + ]); + + $response = $this->request($request); + + $this->assertEquals(415, $response->status); + + } + + function testCreateFileValid() { + + $request = new HTTP\Request( + 'PUT', + '/addressbooks/admin/addressbook1/blabla.vcf' + ); + + $vcard = <<setBody($vcard); + + $response = $this->request($request, 201); + + // The custom Ew header should not be set + $this->assertNull( + $response->getHeader('X-Sabre-Ew-Gross') + ); + // Valid, non-auto-fixed responses should contain an ETag. + $this->assertTrue( + $response->getHeader('ETag') !== null, + 'We did not receive an etag' + ); + + + $expected = [ + 'uri' => 'blabla.vcf', + 'carddata' => $vcard, + 'size' => strlen($vcard), + 'etag' => '"' . md5($vcard) . '"', + ]; + + $this->assertEquals($expected, $this->cardBackend->getCard('addressbook1', 'blabla.vcf')); + + } + + /** + * This test creates an intentionally broken vCard that vobject is able + * to automatically repair. + * + * @depends testCreateFileValid + */ + function testCreateVCardAutoFix() { + + $request = new HTTP\Request( + 'PUT', + '/addressbooks/admin/addressbook1/blabla.vcf' + ); + + // The error in this vcard is that there's not enough semi-colons in N + $vcard = <<setBody($vcard); + + $response = $this->request($request, 201); + + // Auto-fixed vcards should NOT return an etag + $this->assertNull( + $response->getHeader('ETag') + ); + + // We should have gotten an Ew header + $this->assertNotNull( + $response->getHeader('X-Sabre-Ew-Gross') + ); + + $expectedVCard = << 'blabla.vcf', + 'carddata' => $expectedVCard, + 'size' => strlen($expectedVCard), + 'etag' => '"' . md5($expectedVCard) . '"', + ]; + + $this->assertEquals($expected, $this->cardBackend->getCard('addressbook1', 'blabla.vcf')); + + } + + /** + * This test creates an intentionally broken vCard that vobject is able + * to automatically repair. + * + * However, we're supplying a heading asking the server to treat the + * request as strict, so the server should still let the request fail. + * + * @depends testCreateFileValid + */ + function testCreateVCardStrictFail() { + + $request = new HTTP\Request( + 'PUT', + '/addressbooks/admin/addressbook1/blabla.vcf', + [ + 'Prefer' => 'handling=strict', + ] + ); + + // The error in this vcard is that there's not enough semi-colons in N + $vcard = <<setBody($vcard); + $this->request($request, 415); + + } + + function testCreateFileNoUID() { + + $request = new HTTP\Request( + 'PUT', + '/addressbooks/admin/addressbook1/blabla.vcf' + ); + $vcard = <<setBody($vcard); + + $response = $this->request($request, 201); + + $foo = $this->cardBackend->getCard('addressbook1', 'blabla.vcf'); + $this->assertTrue( + strpos($foo['carddata'], 'UID') !== false, + print_r($foo, true) + ); + } + + function testCreateFileJson() { + + $request = new HTTP\Request( + 'PUT', + '/addressbooks/admin/addressbook1/blabla.vcf' + ); + $request->setBody('[ "vcard" , [ [ "VERSION", {}, "text", "4.0"], [ "UID" , {}, "text", "foo" ], [ "FN", {}, "text", "FirstName LastName"] ] ]'); + + $response = $this->request($request); + + $this->assertEquals(201, $response->status, 'Incorrect status returned! Full response body: ' . $response->body); + + $foo = $this->cardBackend->getCard('addressbook1', 'blabla.vcf'); + $this->assertEquals("BEGIN:VCARD\r\nVERSION:4.0\r\nUID:foo\r\nFN:FirstName LastName\r\nEND:VCARD\r\n", $foo['carddata']); + + } + + function testCreateFileVCalendar() { + + $request = HTTP\Sapi::createFromServerArray([ + 'REQUEST_METHOD' => 'PUT', + 'REQUEST_URI' => '/addressbooks/admin/addressbook1/blabla.vcf', + ]); + $request->setBody("BEGIN:VCALENDAR\r\nEND:VCALENDAR\r\n"); + + $response = $this->request($request); + + $this->assertEquals(415, $response->status, 'Incorrect status returned! Full response body: ' . $response->body); + + } + + function testUpdateFile() { + + $this->cardBackend->createCard('addressbook1', 'blabla.vcf', 'foo'); + $request = new HTTP\Request( + 'PUT', + '/addressbooks/admin/addressbook1/blabla.vcf' + ); + + $response = $this->request($request, 415); + + } + + function testUpdateFileParsableBody() { + + $this->cardBackend->createCard('addressbook1', 'blabla.vcf', 'foo'); + $request = new HTTP\Request( + 'PUT', + '/addressbooks/admin/addressbook1/blabla.vcf' + ); + + $body = "BEGIN:VCARD\r\nVERSION:4.0\r\nUID:foo\r\nFN:FirstName LastName\r\nEND:VCARD\r\n"; + $request->setBody($body); + + $response = $this->request($request, 204); + + $expected = [ + 'uri' => 'blabla.vcf', + 'carddata' => $body, + 'size' => strlen($body), + 'etag' => '"' . md5($body) . '"', + ]; + + $this->assertEquals($expected, $this->cardBackend->getCard('addressbook1', 'blabla.vcf')); + + } +} diff --git a/vendor/sabre/dav/tests/Sabre/CardDAV/Xml/Property/SupportedAddressDataTest.php b/vendor/sabre/dav/tests/Sabre/CardDAV/Xml/Property/SupportedAddressDataTest.php new file mode 100644 index 000000000..43abebdce --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/CardDAV/Xml/Property/SupportedAddressDataTest.php @@ -0,0 +1,38 @@ +assertInstanceOf('Sabre\CardDAV\Xml\Property\SupportedAddressData', $property); + + } + + /** + * @depends testSimple + */ + function testSerialize() { + + $property = new SupportedAddressData(); + + $this->namespaceMap[CardDAV\Plugin::NS_CARDDAV] = 'card'; + $xml = $this->write(['{DAV:}root' => $property]); + + $this->assertXmlStringEqualsXmlString( +' +' . +'' . +'' . +'' . +' +', $xml); + + } + +} diff --git a/vendor/sabre/dav/tests/Sabre/CardDAV/Xml/Property/SupportedCollationSetTest.php b/vendor/sabre/dav/tests/Sabre/CardDAV/Xml/Property/SupportedCollationSetTest.php new file mode 100644 index 000000000..e06aff101 --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/CardDAV/Xml/Property/SupportedCollationSetTest.php @@ -0,0 +1,38 @@ +assertInstanceOf('Sabre\CardDAV\Xml\Property\SupportedCollationSet', $property); + + } + + /** + * @depends testSimple + */ + function testSerialize() { + + $property = new SupportedCollationSet(); + + $this->namespaceMap[CardDAV\Plugin::NS_CARDDAV] = 'card'; + $xml = $this->write(['{DAV:}root' => $property]); + + $this->assertXmlStringEqualsXmlString( +' +' . +'i;ascii-casemap' . +'i;octet' . +'i;unicode-casemap' . +' +', $xml); + + } + +} diff --git a/vendor/sabre/dav/tests/Sabre/CardDAV/Xml/Request/AddressBookMultiGetTest.php b/vendor/sabre/dav/tests/Sabre/CardDAV/Xml/Request/AddressBookMultiGetTest.php new file mode 100644 index 000000000..9dcfd2f69 --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/CardDAV/Xml/Request/AddressBookMultiGetTest.php @@ -0,0 +1,88 @@ + 'Sabre\\CardDAV\\Xml\\Request\AddressBookMultiGetReport', + ]; + + /** + * @dataProvider providesAddressDataXml + * @param $xml + */ + function testDeserialize($xml, $expectedProps, $expectedVersion = '3.0') { + + $result = $this->parse($xml); + $addressBookMultiGetReport = new AddressBookMultiGetReport(); + $addressBookMultiGetReport->properties = [ + '{DAV:}getcontenttype', + '{DAV:}getetag', + '{urn:ietf:params:xml:ns:carddav}address-data', + ]; + $addressBookMultiGetReport->hrefs = ['/foo.vcf']; + $addressBookMultiGetReport->contentType = 'text/vcard'; + $addressBookMultiGetReport->version = $expectedVersion; + $addressBookMultiGetReport->addressDataProperties = $expectedProps; + + + $this->assertEquals( + $addressBookMultiGetReport, + $result['value'] + ); + + } + + function providesAddressDataXml() + { + $simpleXml = << + + + + + + + /foo.vcf + +XML; + $allPropsXml = << + + + + + + + + + /foo.vcf + +XML; + $multiplePropsXml = << + + + + + + + + + + + + + /foo.vcf + +XML; + return [ + 'address data with version' => [$simpleXml, [], '4.0'], + 'address data with inner all props' => [$allPropsXml, []], + 'address data with mutliple props' => [$multiplePropsXml, ['VERSION', 'UID', 'NICKNAME', 'EMAIL', 'FN']] + ]; + } +} diff --git a/vendor/sabre/dav/tests/Sabre/CardDAV/Xml/Request/AddressBookQueryReportTest.php b/vendor/sabre/dav/tests/Sabre/CardDAV/Xml/Request/AddressBookQueryReportTest.php new file mode 100644 index 000000000..3a2e4b46a --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/CardDAV/Xml/Request/AddressBookQueryReportTest.php @@ -0,0 +1,350 @@ + 'Sabre\\CardDAV\\Xml\\Request\AddressBookQueryReport', + ]; + + function testDeserialize() { + + $xml = << + + + + + + + + +XML; + + $result = $this->parse($xml); + $addressBookQueryReport = new AddressBookQueryReport(); + $addressBookQueryReport->properties = [ + '{DAV:}getetag', + ]; + $addressBookQueryReport->test = 'anyof'; + $addressBookQueryReport->filters = [ + [ + 'name' => 'uid', + 'test' => 'anyof', + 'is-not-defined' => false, + 'param-filters' => [], + 'text-matches' => [], + ] + ]; + + $this->assertEquals( + $addressBookQueryReport, + $result['value'] + ); + + } + + function testDeserializeAllOf() { + + $xml = << + + + + + + + + +XML; + + $result = $this->parse($xml); + $addressBookQueryReport = new AddressBookQueryReport(); + $addressBookQueryReport->properties = [ + '{DAV:}getetag', + ]; + $addressBookQueryReport->test = 'allof'; + $addressBookQueryReport->filters = [ + [ + 'name' => 'uid', + 'test' => 'anyof', + 'is-not-defined' => false, + 'param-filters' => [], + 'text-matches' => [], + ] + ]; + + $this->assertEquals( + $addressBookQueryReport, + $result['value'] + ); + + } + + /** + * @expectedException \Sabre\DAV\Exception\BadRequest + */ + function testDeserializeBadTest() { + + $xml = << + + + + + + + + +XML; + + $this->parse($xml); + + } + + /** + * We should error on this, but KDE does this, so we chose to support it. + */ + function testDeserializeNoFilter() { + + $xml = << + + + + + +XML; + + $result = $this->parse($xml); + $addressBookQueryReport = new AddressBookQueryReport(); + $addressBookQueryReport->properties = [ + '{DAV:}getetag', + ]; + $addressBookQueryReport->test = 'anyof'; + $addressBookQueryReport->filters = []; + + $this->assertEquals( + $addressBookQueryReport, + $result['value'] + ); + + } + + function testDeserializeComplex() { + + $xml = << + + + + + + + + + + + + + + + + Hello! + + + + No + + + 10 + +XML; + + $result = $this->parse($xml); + $addressBookQueryReport = new AddressBookQueryReport(); + $addressBookQueryReport->properties = [ + '{DAV:}getetag', + '{urn:ietf:params:xml:ns:carddav}address-data', + ]; + $addressBookQueryReport->test = 'anyof'; + $addressBookQueryReport->filters = [ + [ + 'name' => 'uid', + 'test' => 'anyof', + 'is-not-defined' => true, + 'param-filters' => [], + 'text-matches' => [], + ], + [ + 'name' => 'x-foo', + 'test' => 'allof', + 'is-not-defined' => false, + 'param-filters' => [ + [ + 'name' => 'x-param1', + 'is-not-defined' => false, + 'text-match' => null, + ], + [ + 'name' => 'x-param2', + 'is-not-defined' => true, + 'text-match' => null, + ], + [ + 'name' => 'x-param3', + 'is-not-defined' => false, + 'text-match' => [ + 'negate-condition' => false, + 'value' => 'Hello!', + 'match-type' => 'contains', + 'collation' => 'i;unicode-casemap', + ], + ], + ], + 'text-matches' => [], + ], + [ + 'name' => 'x-prop2', + 'test' => 'anyof', + 'is-not-defined' => false, + 'param-filters' => [], + 'text-matches' => [ + [ + 'negate-condition' => true, + 'value' => 'No', + 'match-type' => 'starts-with', + 'collation' => 'i;unicode-casemap', + ], + ], + ] + ]; + + $addressBookQueryReport->version = '4.0'; + $addressBookQueryReport->contentType = 'application/vcard+json'; + $addressBookQueryReport->limit = 10; + + $this->assertEquals( + $addressBookQueryReport, + $result['value'] + ); + + } + + /** + * @expectedException \Sabre\DAV\Exception\BadRequest + */ + function testDeserializeBadMatchType() { + + $xml = << + + + + + + + + Hello! + + + + +XML; + $this->parse($xml); + + } + + /** + * @expectedException \Sabre\DAV\Exception\BadRequest + */ + function testDeserializeBadMatchType2() { + + $xml = << + + + + + + + No + + + +XML; + $this->parse($xml); + + } + + /** + * @expectedException \Sabre\DAV\Exception\BadRequest + */ + function testDeserializeDoubleFilter() { + + $xml = << + + + + + + + + + +XML; + $this->parse($xml); + + } + + function testDeserializeAddressbookElements() { + + $xml = << + + + + + + + + + + + + + +XML; + + $result = $this->parse($xml); + $addressBookQueryReport = new AddressBookQueryReport(); + $addressBookQueryReport->properties = [ + '{DAV:}getetag', + '{urn:ietf:params:xml:ns:carddav}address-data' + ]; + $addressBookQueryReport->filters = []; + $addressBookQueryReport->test = 'anyof'; + $addressBookQueryReport->contentType = 'text/vcard'; + $addressBookQueryReport->version = '3.0'; + $addressBookQueryReport->addressDataProperties = [ + 'VERSION', + 'UID', + 'NICKNAME', + 'EMAIL', + 'FN', + 'TEL', + ]; + + $this->assertEquals( + $addressBookQueryReport, + $result['value'] + ); + + } + + +} diff --git a/vendor/sabre/dav/tests/Sabre/DAV/AbstractServer.php b/vendor/sabre/dav/tests/Sabre/DAV/AbstractServer.php new file mode 100644 index 000000000..6a8d389a0 --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/DAV/AbstractServer.php @@ -0,0 +1,64 @@ +response = new HTTP\ResponseMock(); + $this->server = new Server($this->getRootNode()); + $this->server->sapi = new HTTP\SapiMock(); + $this->server->httpResponse = $this->response; + $this->server->debugExceptions = true; + $this->deleteTree(SABRE_TEMPDIR, false); + file_put_contents(SABRE_TEMPDIR . '/test.txt', 'Test contents'); + mkdir(SABRE_TEMPDIR . '/dir'); + file_put_contents(SABRE_TEMPDIR . '/dir/child.txt', 'Child contents'); + + + } + + function tearDown() { + + $this->deleteTree(SABRE_TEMPDIR, false); + + } + + protected function getRootNode() { + + return new FS\Directory(SABRE_TEMPDIR); + + } + + private function deleteTree($path, $deleteRoot = true) { + + foreach (scandir($path) as $node) { + + if ($node == '.' || $node == '.svn' || $node == '..') continue; + $myPath = $path . '/' . $node; + if (is_file($myPath)) { + unlink($myPath); + } else { + $this->deleteTree($myPath); + } + + } + if ($deleteRoot) rmdir($path); + + } + +} diff --git a/vendor/sabre/dav/tests/Sabre/DAV/Auth/Backend/AbstractBasicTest.php b/vendor/sabre/dav/tests/Sabre/DAV/Auth/Backend/AbstractBasicTest.php new file mode 100644 index 000000000..917f5ec3f --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/DAV/Auth/Backend/AbstractBasicTest.php @@ -0,0 +1,91 @@ +assertFalse( + $backend->check($request, $response)[0] + ); + + } + + function testCheckUnknownUser() { + + $request = HTTP\Sapi::createFromServerArray([ + 'PHP_AUTH_USER' => 'username', + 'PHP_AUTH_PW' => 'wrongpassword', + ]); + $response = new HTTP\Response(); + + $backend = new AbstractBasicMock(); + + $this->assertFalse( + $backend->check($request, $response)[0] + ); + + } + + function testCheckSuccess() { + + $request = HTTP\Sapi::createFromServerArray([ + 'PHP_AUTH_USER' => 'username', + 'PHP_AUTH_PW' => 'password', + ]); + $response = new HTTP\Response(); + + $backend = new AbstractBasicMock(); + $this->assertEquals( + [true, 'principals/username'], + $backend->check($request, $response) + ); + + } + + function testRequireAuth() { + + $request = new HTTP\Request(); + $response = new HTTP\Response(); + + $backend = new AbstractBasicMock(); + $backend->setRealm('writing unittests on a saturday night'); + $backend->challenge($request, $response); + + $this->assertContains( + 'Basic realm="writing unittests on a saturday night"', + $response->getHeader('WWW-Authenticate') + ); + + } + +} + + +class AbstractBasicMock extends AbstractBasic { + + /** + * Validates a username and password + * + * This method should return true or false depending on if login + * succeeded. + * + * @param string $username + * @param string $password + * @return bool + */ + function validateUserPass($username, $password) { + + return ($username == 'username' && $password == 'password'); + + } + +} diff --git a/vendor/sabre/dav/tests/Sabre/DAV/Auth/Backend/AbstractBearerTest.php b/vendor/sabre/dav/tests/Sabre/DAV/Auth/Backend/AbstractBearerTest.php new file mode 100644 index 000000000..c38578830 --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/DAV/Auth/Backend/AbstractBearerTest.php @@ -0,0 +1,90 @@ +assertFalse( + $backend->check($request, $response)[0] + ); + + } + + function testCheckInvalidToken() { + + $request = HTTP\Sapi::createFromServerArray([ + 'HTTP_AUTHORIZATION' => 'Bearer foo', + ]); + $response = new HTTP\Response(); + + $backend = new AbstractBearerMock(); + + $this->assertFalse( + $backend->check($request, $response)[0] + ); + + } + + function testCheckSuccess() { + + $request = HTTP\Sapi::createFromServerArray([ + 'HTTP_AUTHORIZATION' => 'Bearer valid', + ]); + $response = new HTTP\Response(); + + $backend = new AbstractBearerMock(); + $this->assertEquals( + [true, 'principals/username'], + $backend->check($request, $response) + ); + + } + + function testRequireAuth() { + + $request = new HTTP\Request(); + $response = new HTTP\Response(); + + $backend = new AbstractBearerMock(); + $backend->setRealm('writing unittests on a saturday night'); + $backend->challenge($request, $response); + + $this->assertEquals( + 'Bearer realm="writing unittests on a saturday night"', + $response->getHeader('WWW-Authenticate') + ); + + } + +} + + +class AbstractBearerMock extends AbstractBearer { + + /** + * Validates a bearer token + * + * This method should return true or false depending on if login + * succeeded. + * + * @param string $bearerToken + * @return bool + */ + function validateBearerToken($bearerToken) { + + return 'valid' === $bearerToken ? 'principals/username' : false; + + } + +} diff --git a/vendor/sabre/dav/tests/Sabre/DAV/Auth/Backend/AbstractDigestTest.php b/vendor/sabre/dav/tests/Sabre/DAV/Auth/Backend/AbstractDigestTest.php new file mode 100644 index 000000000..14c72aaa0 --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/DAV/Auth/Backend/AbstractDigestTest.php @@ -0,0 +1,138 @@ +assertFalse( + $backend->check($request, $response)[0] + ); + + } + + function testCheckBadGetUserInfoResponse() { + + $header = 'username=null, realm=myRealm, nonce=12345, uri=/, response=HASH, opaque=1, qop=auth, nc=1, cnonce=1'; + $request = HTTP\Sapi::createFromServerArray([ + 'PHP_AUTH_DIGEST' => $header, + ]); + $response = new HTTP\Response(); + + $backend = new AbstractDigestMock(); + $this->assertFalse( + $backend->check($request, $response)[0] + ); + + } + + /** + * @expectedException Sabre\DAV\Exception + */ + function testCheckBadGetUserInfoResponse2() { + + $header = 'username=array, realm=myRealm, nonce=12345, uri=/, response=HASH, opaque=1, qop=auth, nc=1, cnonce=1'; + $request = HTTP\Sapi::createFromServerArray([ + 'PHP_AUTH_DIGEST' => $header, + ]); + + $response = new HTTP\Response(); + + $backend = new AbstractDigestMock(); + $backend->check($request, $response); + + } + + function testCheckUnknownUser() { + + $header = 'username=false, realm=myRealm, nonce=12345, uri=/, response=HASH, opaque=1, qop=auth, nc=1, cnonce=1'; + $request = HTTP\Sapi::createFromServerArray([ + 'PHP_AUTH_DIGEST' => $header, + ]); + + $response = new HTTP\Response(); + + $backend = new AbstractDigestMock(); + $this->assertFalse( + $backend->check($request, $response)[0] + ); + + } + + function testCheckBadPassword() { + + $header = 'username=user, realm=myRealm, nonce=12345, uri=/, response=HASH, opaque=1, qop=auth, nc=1, cnonce=1'; + $request = HTTP\Sapi::createFromServerArray([ + 'PHP_AUTH_DIGEST' => $header, + 'REQUEST_METHOD' => 'PUT', + ]); + + $response = new HTTP\Response(); + + $backend = new AbstractDigestMock(); + $this->assertFalse( + $backend->check($request, $response)[0] + ); + + } + + function testCheck() { + + $digestHash = md5('HELLO:12345:1:1:auth:' . md5('GET:/')); + $header = 'username=user, realm=myRealm, nonce=12345, uri=/, response=' . $digestHash . ', opaque=1, qop=auth, nc=1, cnonce=1'; + $request = HTTP\Sapi::createFromServerArray([ + 'REQUEST_METHOD' => 'GET', + 'PHP_AUTH_DIGEST' => $header, + 'REQUEST_URI' => '/', + ]); + + $response = new HTTP\Response(); + + $backend = new AbstractDigestMock(); + $this->assertEquals( + [true, 'principals/user'], + $backend->check($request, $response) + ); + + } + + function testRequireAuth() { + + $request = new HTTP\Request(); + $response = new HTTP\Response(); + + $backend = new AbstractDigestMock(); + $backend->setRealm('writing unittests on a saturday night'); + $backend->challenge($request, $response); + + $this->assertStringStartsWith( + 'Digest realm="writing unittests on a saturday night"', + $response->getHeader('WWW-Authenticate') + ); + + } + +} + + +class AbstractDigestMock extends AbstractDigest { + + function getDigestHash($realm, $userName) { + + switch ($userName) { + case 'null' : return null; + case 'false' : return false; + case 'array' : return []; + case 'user' : return 'HELLO'; + } + + } + +} diff --git a/vendor/sabre/dav/tests/Sabre/DAV/Auth/Backend/AbstractPDOTest.php b/vendor/sabre/dav/tests/Sabre/DAV/Auth/Backend/AbstractPDOTest.php new file mode 100644 index 000000000..b14e9fa2e --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/DAV/Auth/Backend/AbstractPDOTest.php @@ -0,0 +1,45 @@ +dropTables('users'); + $this->createSchema('users'); + + $this->getPDO()->query( + "INSERT INTO users (username,digesta1) VALUES ('user','hash')" + + ); + + } + + function testConstruct() { + + $pdo = $this->getPDO(); + $backend = new PDO($pdo); + $this->assertTrue($backend instanceof PDO); + + } + + /** + * @depends testConstruct + */ + function testUserInfo() { + + $pdo = $this->getPDO(); + $backend = new PDO($pdo); + + $this->assertNull($backend->getDigestHash('realm', 'blabla')); + + $expected = 'hash'; + + $this->assertEquals($expected, $backend->getDigestHash('realm', 'user')); + + } + +} diff --git a/vendor/sabre/dav/tests/Sabre/DAV/Auth/Backend/ApacheTest.php b/vendor/sabre/dav/tests/Sabre/DAV/Auth/Backend/ApacheTest.php new file mode 100644 index 000000000..29cbc2162 --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/DAV/Auth/Backend/ApacheTest.php @@ -0,0 +1,71 @@ +assertInstanceOf('Sabre\DAV\Auth\Backend\Apache', $backend); + + } + + function testNoHeader() { + + $request = new HTTP\Request(); + $response = new HTTP\Response(); + $backend = new Apache(); + + $this->assertFalse( + $backend->check($request, $response)[0] + ); + + } + + function testRemoteUser() { + + $request = HTTP\Sapi::createFromServerArray([ + 'REMOTE_USER' => 'username', + ]); + $response = new HTTP\Response(); + $backend = new Apache(); + + $this->assertEquals( + [true, 'principals/username'], + $backend->check($request, $response) + ); + + } + + function testRedirectRemoteUser() { + + $request = HTTP\Sapi::createFromServerArray([ + 'REDIRECT_REMOTE_USER' => 'username', + ]); + $response = new HTTP\Response(); + $backend = new Apache(); + + $this->assertEquals( + [true, 'principals/username'], + $backend->check($request, $response) + ); + + } + + function testRequireAuth() { + + $request = new HTTP\Request(); + $response = new HTTP\Response(); + + $backend = new Apache(); + $backend->challenge($request, $response); + + $this->assertNull( + $response->getHeader('WWW-Authenticate') + ); + + } +} diff --git a/vendor/sabre/dav/tests/Sabre/DAV/Auth/Backend/BasicCallBackTest.php b/vendor/sabre/dav/tests/Sabre/DAV/Auth/Backend/BasicCallBackTest.php new file mode 100644 index 000000000..167f31eab --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/DAV/Auth/Backend/BasicCallBackTest.php @@ -0,0 +1,36 @@ + 'Basic ' . base64_encode('foo:bar'), + ]); + $response = new Response(); + + $this->assertEquals( + [true, 'principals/foo'], + $backend->check($request, $response) + ); + + $this->assertEquals(['foo', 'bar'], $args); + + } + +} diff --git a/vendor/sabre/dav/tests/Sabre/DAV/Auth/Backend/FileTest.php b/vendor/sabre/dav/tests/Sabre/DAV/Auth/Backend/FileTest.php new file mode 100644 index 000000000..f694f4806 --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/DAV/Auth/Backend/FileTest.php @@ -0,0 +1,41 @@ +assertTrue($file instanceof File); + + } + + /** + * @expectedException Sabre\DAV\Exception + */ + function testLoadFileBroken() { + + file_put_contents(SABRE_TEMPDIR . '/backend', 'user:realm:hash'); + $file = new File(SABRE_TEMPDIR . '/backend'); + + } + + function testLoadFile() { + + file_put_contents(SABRE_TEMPDIR . '/backend', 'user:realm:' . md5('user:realm:password')); + $file = new File(); + $file->loadFile(SABRE_TEMPDIR . '/backend'); + + $this->assertFalse($file->getDigestHash('realm', 'blabla')); + $this->assertEquals(md5('user:realm:password'), $file->getDigestHash('realm', 'user')); + + } + +} diff --git a/vendor/sabre/dav/tests/Sabre/DAV/Auth/Backend/Mock.php b/vendor/sabre/dav/tests/Sabre/DAV/Auth/Backend/Mock.php new file mode 100644 index 000000000..369bc249e --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/DAV/Auth/Backend/Mock.php @@ -0,0 +1,87 @@ +principal = $principal; + + } + + /** + * When this method is called, the backend must check if authentication was + * successful. + * + * The returned value must be one of the following + * + * [true, "principals/username"] + * [false, "reason for failure"] + * + * If authentication was successful, it's expected that the authentication + * backend returns a so-called principal url. + * + * Examples of a principal url: + * + * principals/admin + * principals/user1 + * principals/users/joe + * principals/uid/123457 + * + * If you don't use WebDAV ACL (RFC3744) we recommend that you simply + * return a string such as: + * + * principals/users/[username] + * + * @param RequestInterface $request + * @param ResponseInterface $response + * @return array + */ + function check(RequestInterface $request, ResponseInterface $response) { + + if ($this->invalidCheckResponse) { + return 'incorrect!'; + } + if ($this->fail) { + return [false, "fail!"]; + } + return [true, $this->principal]; + + } + + /** + * This method is called when a user could not be authenticated, and + * authentication was required for the current request. + * + * This gives you the oppurtunity to set authentication headers. The 401 + * status code will already be set. + * + * In this case of Basic Auth, this would for example mean that the + * following header needs to be set: + * + * $response->addHeader('WWW-Authenticate', 'Basic realm=SabreDAV'); + * + * Keep in mind that in the case of multiple authentication backends, other + * WWW-Authenticate headers may already have been set, and you'll want to + * append your own WWW-Authenticate header instead of overwriting the + * existing one. + * + * @param RequestInterface $request + * @param ResponseInterface $response + * @return void + */ + function challenge(RequestInterface $request, ResponseInterface $response) { + + } + +} diff --git a/vendor/sabre/dav/tests/Sabre/DAV/Auth/Backend/PDOMySQLTest.php b/vendor/sabre/dav/tests/Sabre/DAV/Auth/Backend/PDOMySQLTest.php new file mode 100644 index 000000000..18f59793a --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/DAV/Auth/Backend/PDOMySQLTest.php @@ -0,0 +1,9 @@ +assertTrue($plugin instanceof Plugin); + $fakeServer->addPlugin($plugin); + $this->assertEquals($plugin, $fakeServer->getPlugin('auth')); + $this->assertInternalType('array', $plugin->getPluginInfo()); + + } + + /** + * @depends testInit + */ + function testAuthenticate() { + + $fakeServer = new DAV\Server(new DAV\SimpleCollection('bla')); + $plugin = new Plugin(new Backend\Mock()); + $fakeServer->addPlugin($plugin); + $this->assertTrue( + $fakeServer->emit('beforeMethod', [new HTTP\Request(), new HTTP\Response()]) + ); + + } + + /** + * @depends testInit + * @expectedException Sabre\DAV\Exception\NotAuthenticated + */ + function testAuthenticateFail() { + + $fakeServer = new DAV\Server(new DAV\SimpleCollection('bla')); + $backend = new Backend\Mock(); + $backend->fail = true; + + $plugin = new Plugin($backend); + $fakeServer->addPlugin($plugin); + $fakeServer->emit('beforeMethod', [new HTTP\Request(), new HTTP\Response()]); + + } + + /** + * @depends testAuthenticateFail + */ + function testAuthenticateFailDontAutoRequire() { + + $fakeServer = new DAV\Server(new DAV\SimpleCollection('bla')); + $backend = new Backend\Mock(); + $backend->fail = true; + + $plugin = new Plugin($backend); + $plugin->autoRequireLogin = false; + $fakeServer->addPlugin($plugin); + $this->assertTrue( + $fakeServer->emit('beforeMethod', [new HTTP\Request(), new HTTP\Response()]) + ); + $this->assertEquals(1, count($plugin->getLoginFailedReasons())); + + } + + /** + * @depends testAuthenticate + */ + function testMultipleBackend() { + + $fakeServer = new DAV\Server(new DAV\SimpleCollection('bla')); + $backend1 = new Backend\Mock(); + $backend2 = new Backend\Mock(); + $backend2->fail = true; + + $plugin = new Plugin(); + $plugin->addBackend($backend1); + $plugin->addBackend($backend2); + + $fakeServer->addPlugin($plugin); + $fakeServer->emit('beforeMethod', [new HTTP\Request(), new HTTP\Response()]); + + $this->assertEquals('principals/admin', $plugin->getCurrentPrincipal()); + + } + + /** + * @depends testInit + * @expectedException Sabre\DAV\Exception + */ + function testNoAuthBackend() { + + $fakeServer = new DAV\Server(new DAV\SimpleCollection('bla')); + + $plugin = new Plugin(); + $fakeServer->addPlugin($plugin); + $fakeServer->emit('beforeMethod', [new HTTP\Request(), new HTTP\Response()]); + + } + /** + * @depends testInit + * @expectedException Sabre\DAV\Exception + */ + function testInvalidCheckResponse() { + + $fakeServer = new DAV\Server(new DAV\SimpleCollection('bla')); + $backend = new Backend\Mock(); + $backend->invalidCheckResponse = true; + + $plugin = new Plugin($backend); + $fakeServer->addPlugin($plugin); + $fakeServer->emit('beforeMethod', [new HTTP\Request(), new HTTP\Response()]); + + } + + /** + * @depends testAuthenticate + */ + function testGetCurrentPrincipal() { + + $fakeServer = new DAV\Server(new DAV\SimpleCollection('bla')); + $plugin = new Plugin(new Backend\Mock()); + $fakeServer->addPlugin($plugin); + $fakeServer->emit('beforeMethod', [new HTTP\Request(), new HTTP\Response()]); + $this->assertEquals('principals/admin', $plugin->getCurrentPrincipal()); + + } + +} diff --git a/vendor/sabre/dav/tests/Sabre/DAV/BasicNodeTest.php b/vendor/sabre/dav/tests/Sabre/DAV/BasicNodeTest.php new file mode 100644 index 000000000..ec104ec80 --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/DAV/BasicNodeTest.php @@ -0,0 +1,235 @@ +put('hi'); + + } + + /** + * @expectedException Sabre\DAV\Exception\Forbidden + */ + function testGet() { + + $file = new FileMock(); + $file->get(); + + } + + function testGetSize() { + + $file = new FileMock(); + $this->assertEquals(0, $file->getSize()); + + } + + + function testGetETag() { + + $file = new FileMock(); + $this->assertNull($file->getETag()); + + } + + function testGetContentType() { + + $file = new FileMock(); + $this->assertNull($file->getContentType()); + + } + + /** + * @expectedException Sabre\DAV\Exception\Forbidden + */ + function testDelete() { + + $file = new FileMock(); + $file->delete(); + + } + + /** + * @expectedException Sabre\DAV\Exception\Forbidden + */ + function testSetName() { + + $file = new FileMock(); + $file->setName('hi'); + + } + + function testGetLastModified() { + + $file = new FileMock(); + // checking if lastmod is within the range of a few seconds + $lastMod = $file->getLastModified(); + $compareTime = ($lastMod + 1) - time(); + $this->assertTrue($compareTime < 3); + + } + + function testGetChild() { + + $dir = new DirectoryMock(); + $file = $dir->getChild('mockfile'); + $this->assertTrue($file instanceof FileMock); + + } + + function testChildExists() { + + $dir = new DirectoryMock(); + $this->assertTrue($dir->childExists('mockfile')); + + } + + function testChildExistsFalse() { + + $dir = new DirectoryMock(); + $this->assertFalse($dir->childExists('mockfile2')); + + } + + /** + * @expectedException Sabre\DAV\Exception\NotFound + */ + function testGetChild404() { + + $dir = new DirectoryMock(); + $file = $dir->getChild('blabla'); + + } + + /** + * @expectedException Sabre\DAV\Exception\Forbidden + */ + function testCreateFile() { + + $dir = new DirectoryMock(); + $dir->createFile('hello', 'data'); + + } + + /** + * @expectedException Sabre\DAV\Exception\Forbidden + */ + function testCreateDirectory() { + + $dir = new DirectoryMock(); + $dir->createDirectory('hello'); + + } + + function testSimpleDirectoryConstruct() { + + $dir = new SimpleCollection('simpledir', []); + $this->assertInstanceOf('Sabre\DAV\SimpleCollection', $dir); + + } + + /** + * @depends testSimpleDirectoryConstruct + */ + function testSimpleDirectoryConstructChild() { + + $file = new FileMock(); + $dir = new SimpleCollection('simpledir', [$file]); + $file2 = $dir->getChild('mockfile'); + + $this->assertEquals($file, $file2); + + } + + /** + * @expectedException Sabre\DAV\Exception + * @depends testSimpleDirectoryConstruct + */ + function testSimpleDirectoryBadParam() { + + $dir = new SimpleCollection('simpledir', ['string shouldn\'t be here']); + + } + + /** + * @depends testSimpleDirectoryConstruct + */ + function testSimpleDirectoryAddChild() { + + $file = new FileMock(); + $dir = new SimpleCollection('simpledir'); + $dir->addChild($file); + $file2 = $dir->getChild('mockfile'); + + $this->assertEquals($file, $file2); + + } + + /** + * @depends testSimpleDirectoryConstruct + * @depends testSimpleDirectoryAddChild + */ + function testSimpleDirectoryGetChildren() { + + $file = new FileMock(); + $dir = new SimpleCollection('simpledir'); + $dir->addChild($file); + + $this->assertEquals([$file], $dir->getChildren()); + + } + + /* + * @depends testSimpleDirectoryConstruct + */ + function testSimpleDirectoryGetName() { + + $dir = new SimpleCollection('simpledir'); + $this->assertEquals('simpledir', $dir->getName()); + + } + + /** + * @depends testSimpleDirectoryConstruct + * @expectedException Sabre\DAV\Exception\NotFound + */ + function testSimpleDirectoryGetChild404() { + + $dir = new SimpleCollection('simpledir'); + $dir->getChild('blabla'); + + } +} + +class DirectoryMock extends Collection { + + function getName() { + + return 'mockdir'; + + } + + function getChildren() { + + return [new FileMock()]; + + } + +} + +class FileMock extends File { + + function getName() { + + return 'mockfile'; + + } + +} diff --git a/vendor/sabre/dav/tests/Sabre/DAV/Browser/GuessContentTypeTest.php b/vendor/sabre/dav/tests/Sabre/DAV/Browser/GuessContentTypeTest.php new file mode 100644 index 000000000..54a3053ec --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/DAV/Browser/GuessContentTypeTest.php @@ -0,0 +1,70 @@ +server->getPropertiesForPath('/somefile.jpg', $properties); + $this->assertArrayHasKey(0, $result); + $this->assertArrayHasKey(404, $result[0]); + $this->assertArrayHasKey('{DAV:}getcontenttype', $result[0][404]); + + } + + /** + * @depends testGetProperties + */ + function testGetPropertiesPluginEnabled() { + + $this->server->addPlugin(new GuessContentType()); + $properties = [ + '{DAV:}getcontenttype', + ]; + $result = $this->server->getPropertiesForPath('/somefile.jpg', $properties); + $this->assertArrayHasKey(0, $result); + $this->assertArrayHasKey(200, $result[0], 'We received: ' . print_r($result, true)); + $this->assertArrayHasKey('{DAV:}getcontenttype', $result[0][200]); + $this->assertEquals('image/jpeg', $result[0][200]['{DAV:}getcontenttype']); + + } + + /** + * @depends testGetPropertiesPluginEnabled + */ + function testGetPropertiesUnknown() { + + $this->server->addPlugin(new GuessContentType()); + $properties = [ + '{DAV:}getcontenttype', + ]; + $result = $this->server->getPropertiesForPath('/somefile.hoi', $properties); + $this->assertArrayHasKey(0, $result); + $this->assertArrayHasKey(200, $result[0]); + $this->assertArrayHasKey('{DAV:}getcontenttype', $result[0][200]); + $this->assertEquals('application/octet-stream', $result[0][200]['{DAV:}getcontenttype']); + + } +} diff --git a/vendor/sabre/dav/tests/Sabre/DAV/Browser/MapGetToPropFindTest.php b/vendor/sabre/dav/tests/Sabre/DAV/Browser/MapGetToPropFindTest.php new file mode 100644 index 000000000..33c4ede96 --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/DAV/Browser/MapGetToPropFindTest.php @@ -0,0 +1,44 @@ +server->addPlugin(new MapGetToPropFind()); + + } + + function testCollectionGet() { + + $serverVars = [ + 'REQUEST_URI' => '/', + 'REQUEST_METHOD' => 'GET', + ]; + + $request = HTTP\Sapi::createFromServerArray($serverVars); + $request->setBody(''); + $this->server->httpRequest = ($request); + $this->server->exec(); + + $this->assertEquals(207, $this->response->status, 'Incorrect status response received. Full response body: ' . $this->response->body); + $this->assertEquals([ + 'X-Sabre-Version' => [DAV\Version::VERSION], + 'Content-Type' => ['application/xml; charset=utf-8'], + 'DAV' => ['1, 3, extended-mkcol'], + 'Vary' => ['Brief,Prefer'], + ], + $this->response->getHeaders() + ); + + } + + +} diff --git a/vendor/sabre/dav/tests/Sabre/DAV/Browser/PluginTest.php b/vendor/sabre/dav/tests/Sabre/DAV/Browser/PluginTest.php new file mode 100644 index 000000000..f20c50f86 --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/DAV/Browser/PluginTest.php @@ -0,0 +1,186 @@ +server->addPlugin($this->plugin = new Plugin()); + $this->server->tree->getNodeForPath('')->createDirectory('dir2'); + + } + + function testCollectionGet() { + + $request = new HTTP\Request('GET', '/dir'); + $this->server->httpRequest = $request; + $this->server->exec(); + + $this->assertEquals(200, $this->response->getStatus(), "Incorrect status received. Full response body: " . $this->response->getBodyAsString()); + $this->assertEquals( + [ + 'X-Sabre-Version' => [DAV\Version::VERSION], + 'Content-Type' => ['text/html; charset=utf-8'], + 'Content-Security-Policy' => ["default-src 'none'; img-src 'self'; style-src 'self'; font-src 'self';"] + ], + $this->response->getHeaders() + ); + + $body = $this->response->getBodyAsString(); + $this->assertTrue(strpos($body, 'dir') !== false, $body); + $this->assertTrue(strpos($body, '<a href="/dir/child.txt">') !== false); + + } + + /** + * Adding the If-None-Match should have 0 effect, but it threw an error. + */ + function testCollectionGetIfNoneMatch() { + + $request = new HTTP\Request('GET', '/dir'); + $request->setHeader('If-None-Match', '"foo-bar"'); + $this->server->httpRequest = $request; + $this->server->exec(); + + $this->assertEquals(200, $this->response->getStatus(), "Incorrect status received. Full response body: " . $this->response->getBodyAsString()); + $this->assertEquals( + [ + 'X-Sabre-Version' => [DAV\Version::VERSION], + 'Content-Type' => ['text/html; charset=utf-8'], + 'Content-Security-Policy' => ["default-src 'none'; img-src 'self'; style-src 'self'; font-src 'self';"] + ], + $this->response->getHeaders() + ); + + $body = $this->response->getBodyAsString(); + $this->assertTrue(strpos($body, '<title>dir') !== false, $body); + $this->assertTrue(strpos($body, '<a href="/dir/child.txt">') !== false); + + } + function testCollectionGetRoot() { + + $request = new HTTP\Request('GET', '/'); + $this->server->httpRequest = ($request); + $this->server->exec(); + + $this->assertEquals(200, $this->response->status, "Incorrect status received. Full response body: " . $this->response->getBodyAsString()); + $this->assertEquals( + [ + 'X-Sabre-Version' => [DAV\Version::VERSION], + 'Content-Type' => ['text/html; charset=utf-8'], + 'Content-Security-Policy' => ["default-src 'none'; img-src 'self'; style-src 'self'; font-src 'self';"] + ], + $this->response->getHeaders() + ); + + $body = $this->response->getBodyAsString(); + $this->assertTrue(strpos($body, '<title>/') !== false, $body); + $this->assertTrue(strpos($body, '<a href="/dir/">') !== false); + $this->assertTrue(strpos($body, '<span class="btn disabled">') !== false); + + } + + function testGETPassthru() { + + $request = new HTTP\Request('GET', '/random'); + $response = new HTTP\Response(); + $this->assertNull( + $this->plugin->httpGet($request, $response) + ); + + } + + function testPostOtherContentType() { + + $request = new HTTP\Request('POST', '/', ['Content-Type' => 'text/xml']); + $this->server->httpRequest = $request; + $this->server->exec(); + + $this->assertEquals(501, $this->response->status); + + } + + function testPostNoSabreAction() { + + $request = new HTTP\Request('POST', '/', ['Content-Type' => 'application/x-www-form-urlencoded']); + $request->setPostData([]); + $this->server->httpRequest = $request; + $this->server->exec(); + + $this->assertEquals(501, $this->response->status); + + } + + function testPostMkCol() { + + $serverVars = [ + 'REQUEST_URI' => '/', + 'REQUEST_METHOD' => 'POST', + 'CONTENT_TYPE' => 'application/x-www-form-urlencoded', + ]; + $postVars = [ + 'sabreAction' => 'mkcol', + 'name' => 'new_collection', + ]; + + $request = HTTP\Sapi::createFromServerArray($serverVars); + $request->setPostData($postVars); + $this->server->httpRequest = $request; + $this->server->exec(); + + $this->assertEquals(302, $this->response->status); + $this->assertEquals([ + 'X-Sabre-Version' => [DAV\Version::VERSION], + 'Location' => ['/'], + ], $this->response->getHeaders()); + + $this->assertTrue(is_dir(SABRE_TEMPDIR . '/new_collection')); + + } + + function testGetAsset() { + + $request = new HTTP\Request('GET', '/?sabreAction=asset&assetName=favicon.ico'); + $this->server->httpRequest = $request; + $this->server->exec(); + + $this->assertEquals(200, $this->response->getStatus(), 'Error: ' . $this->response->body); + $this->assertEquals([ + 'X-Sabre-Version' => [DAV\Version::VERSION], + 'Content-Type' => ['image/vnd.microsoft.icon'], + 'Content-Length' => ['4286'], + 'Cache-Control' => ['public, max-age=1209600'], + 'Content-Security-Policy' => ["default-src 'none'; img-src 'self'; style-src 'self'; font-src 'self';"] + ], $this->response->getHeaders()); + + } + + function testGetAsset404() { + + $request = new HTTP\Request('GET', '/?sabreAction=asset&assetName=flavicon.ico'); + $this->server->httpRequest = $request; + $this->server->exec(); + + $this->assertEquals(404, $this->response->getStatus(), 'Error: ' . $this->response->body); + + } + + function testGetAssetEscapeBasePath() { + + $request = new HTTP\Request('GET', '/?sabreAction=asset&assetName=./../assets/favicon.ico'); + $this->server->httpRequest = $request; + $this->server->exec(); + + $this->assertEquals(404, $this->response->getStatus(), 'Error: ' . $this->response->body); + + } +} diff --git a/vendor/sabre/dav/tests/Sabre/DAV/Browser/PropFindAllTest.php b/vendor/sabre/dav/tests/Sabre/DAV/Browser/PropFindAllTest.php new file mode 100644 index 000000000..08c2080bb --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/DAV/Browser/PropFindAllTest.php @@ -0,0 +1,70 @@ +<?php + +namespace Sabre\DAV\Browser; + +class PropFindAllTest extends \PHPUnit_Framework_TestCase { + + function testHandleSimple() { + + $pf = new PropFindAll('foo'); + $pf->handle('{DAV:}displayname', 'foo'); + + $this->assertEquals(200, $pf->getStatus('{DAV:}displayname')); + $this->assertEquals('foo', $pf->get('{DAV:}displayname')); + + + } + + function testHandleCallBack() { + + $pf = new PropFindAll('foo'); + $pf->handle('{DAV:}displayname', function() { return 'foo'; }); + + $this->assertEquals(200, $pf->getStatus('{DAV:}displayname')); + $this->assertEquals('foo', $pf->get('{DAV:}displayname')); + + } + + function testSet() { + + $pf = new PropFindAll('foo'); + $pf->set('{DAV:}displayname', 'foo'); + + $this->assertEquals(200, $pf->getStatus('{DAV:}displayname')); + $this->assertEquals('foo', $pf->get('{DAV:}displayname')); + + } + + function testSetNull() { + + $pf = new PropFindAll('foo'); + $pf->set('{DAV:}displayname', null); + + $this->assertEquals(404, $pf->getStatus('{DAV:}displayname')); + $this->assertEquals(null, $pf->get('{DAV:}displayname')); + + } + + function testGet404Properties() { + + $pf = new PropFindAll('foo'); + $pf->set('{DAV:}displayname', null); + $this->assertEquals( + ['{DAV:}displayname'], + $pf->get404Properties() + ); + + } + + function testGet404PropertiesNothing() { + + $pf = new PropFindAll('foo'); + $pf->set('{DAV:}displayname', 'foo'); + $this->assertEquals( + ['{http://sabredav.org/ns}idk'], + $pf->get404Properties() + ); + + } + +} diff --git a/vendor/sabre/dav/tests/Sabre/DAV/ClientMock.php b/vendor/sabre/dav/tests/Sabre/DAV/ClientMock.php new file mode 100644 index 000000000..5a48b063c --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/DAV/ClientMock.php @@ -0,0 +1,34 @@ +<?php + +namespace Sabre\DAV; + +use Sabre\HTTP\RequestInterface; + +class ClientMock extends Client { + + public $request; + public $response; + + public $url; + public $curlSettings; + + /** + * Just making this method public + * + * @param string $url + * @return string + */ + function getAbsoluteUrl($url) { + + return parent::getAbsoluteUrl($url); + + } + + function doRequest(RequestInterface $request) { + + $this->request = $request; + return $this->response; + + } + +} diff --git a/vendor/sabre/dav/tests/Sabre/DAV/ClientTest.php b/vendor/sabre/dav/tests/Sabre/DAV/ClientTest.php new file mode 100644 index 000000000..687f61e2f --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/DAV/ClientTest.php @@ -0,0 +1,306 @@ +<?php + +namespace Sabre\DAV; + +use Sabre\HTTP\Request; +use Sabre\HTTP\Response; + +require_once 'Sabre/DAV/ClientMock.php'; + +class ClientTest extends \PHPUnit_Framework_TestCase { + + function setUp() { + + if (!function_exists('curl_init')) { + $this->markTestSkipped('CURL must be installed to test the client'); + } + + } + + function testConstruct() { + + $client = new ClientMock([ + 'baseUri' => '/', + ]); + $this->assertInstanceOf('Sabre\DAV\ClientMock', $client); + + } + + /** + * @expectedException InvalidArgumentException + */ + function testConstructNoBaseUri() { + + $client = new ClientMock([]); + + } + + function testAuth() { + + $client = new ClientMock([ + 'baseUri' => '/', + 'userName' => 'foo', + 'password' => 'bar', + ]); + + $this->assertEquals("foo:bar", $client->curlSettings[CURLOPT_USERPWD]); + $this->assertEquals(CURLAUTH_BASIC | CURLAUTH_DIGEST, $client->curlSettings[CURLOPT_HTTPAUTH]); + + } + + function testBasicAuth() { + + $client = new ClientMock([ + 'baseUri' => '/', + 'userName' => 'foo', + 'password' => 'bar', + 'authType' => Client::AUTH_BASIC + ]); + + $this->assertEquals("foo:bar", $client->curlSettings[CURLOPT_USERPWD]); + $this->assertEquals(CURLAUTH_BASIC, $client->curlSettings[CURLOPT_HTTPAUTH]); + + } + + function testDigestAuth() { + + $client = new ClientMock([ + 'baseUri' => '/', + 'userName' => 'foo', + 'password' => 'bar', + 'authType' => Client::AUTH_DIGEST + ]); + + $this->assertEquals("foo:bar", $client->curlSettings[CURLOPT_USERPWD]); + $this->assertEquals(CURLAUTH_DIGEST, $client->curlSettings[CURLOPT_HTTPAUTH]); + + } + + function testNTLMAuth() { + + $client = new ClientMock([ + 'baseUri' => '/', + 'userName' => 'foo', + 'password' => 'bar', + 'authType' => Client::AUTH_NTLM + ]); + + $this->assertEquals("foo:bar", $client->curlSettings[CURLOPT_USERPWD]); + $this->assertEquals(CURLAUTH_NTLM, $client->curlSettings[CURLOPT_HTTPAUTH]); + + } + + function testProxy() { + + $client = new ClientMock([ + 'baseUri' => '/', + 'proxy' => 'localhost:8888', + ]); + + $this->assertEquals("localhost:8888", $client->curlSettings[CURLOPT_PROXY]); + + } + + function testEncoding() { + + $client = new ClientMock([ + 'baseUri' => '/', + 'encoding' => Client::ENCODING_IDENTITY | Client::ENCODING_GZIP | Client::ENCODING_DEFLATE, + ]); + + $this->assertEquals("identity,deflate,gzip", $client->curlSettings[CURLOPT_ENCODING]); + + } + + function testPropFind() { + + $client = new ClientMock([ + 'baseUri' => '/', + ]); + + $responseBody = <<<XML +<?xml version="1.0"?> +<multistatus xmlns="DAV:"> + <response> + <href>/foo</href> + <propstat> + <prop> + <displayname>bar</displayname> + </prop> + <status>HTTP/1.1 200 OK</status> + </propstat> + </response> +</multistatus> +XML; + + $client->response = new Response(207, [], $responseBody); + $result = $client->propFind('foo', ['{DAV:}displayname', '{urn:zim}gir']); + + $this->assertEquals(['{DAV:}displayname' => 'bar'], $result); + + $request = $client->request; + $this->assertEquals('PROPFIND', $request->getMethod()); + $this->assertEquals('/foo', $request->getUrl()); + $this->assertEquals([ + 'Depth' => ['0'], + 'Content-Type' => ['application/xml'], + ], $request->getHeaders()); + + } + + /** + * @expectedException \Sabre\HTTP\ClientHttpException + */ + function testPropFindError() { + + $client = new ClientMock([ + 'baseUri' => '/', + ]); + + $client->response = new Response(405, []); + $client->propFind('foo', ['{DAV:}displayname', '{urn:zim}gir']); + + } + + function testPropFindDepth1() { + + $client = new ClientMock([ + 'baseUri' => '/', + ]); + + $responseBody = <<<XML +<?xml version="1.0"?> +<multistatus xmlns="DAV:"> + <response> + <href>/foo</href> + <propstat> + <prop> + <displayname>bar</displayname> + </prop> + <status>HTTP/1.1 200 OK</status> + </propstat> + </response> +</multistatus> +XML; + + $client->response = new Response(207, [], $responseBody); + $result = $client->propFind('foo', ['{DAV:}displayname', '{urn:zim}gir'], 1); + + $this->assertEquals([ + '/foo' => [ + '{DAV:}displayname' => 'bar' + ], + ], $result); + + $request = $client->request; + $this->assertEquals('PROPFIND', $request->getMethod()); + $this->assertEquals('/foo', $request->getUrl()); + $this->assertEquals([ + 'Depth' => ['1'], + 'Content-Type' => ['application/xml'], + ], $request->getHeaders()); + + } + + function testPropPatch() { + + $client = new ClientMock([ + 'baseUri' => '/', + ]); + + $responseBody = <<<XML +<?xml version="1.0"?> +<multistatus xmlns="DAV:"> + <response> + <href>/foo</href> + <propstat> + <prop> + <displayname>bar</displayname> + </prop> + <status>HTTP/1.1 200 OK</status> + </propstat> + </response> +</multistatus> +XML; + + $client->response = new Response(207, [], $responseBody); + $result = $client->propPatch('foo', ['{DAV:}displayname' => 'hi', '{urn:zim}gir' => null]); + $this->assertTrue($result); + $request = $client->request; + $this->assertEquals('PROPPATCH', $request->getMethod()); + $this->assertEquals('/foo', $request->getUrl()); + $this->assertEquals([ + 'Content-Type' => ['application/xml'], + ], $request->getHeaders()); + + } + + /** + * @depends testPropPatch + * @expectedException \Sabre\HTTP\ClientHttpException + */ + function testPropPatchHTTPError() { + + $client = new ClientMock([ + 'baseUri' => '/', + ]); + + $client->response = new Response(403, [], ''); + $client->propPatch('foo', ['{DAV:}displayname' => 'hi', '{urn:zim}gir' => null]); + + } + + /** + * @depends testPropPatch + * @expectedException Sabre\HTTP\ClientException + */ + function testPropPatchMultiStatusError() { + + $client = new ClientMock([ + 'baseUri' => '/', + ]); + + $responseBody = <<<XML +<?xml version="1.0"?> +<multistatus xmlns="DAV:"> +<response> + <href>/foo</href> + <propstat> + <prop> + <displayname /> + </prop> + <status>HTTP/1.1 403 Forbidden</status> + </propstat> +</response> +</multistatus> +XML; + + $client->response = new Response(207, [], $responseBody); + $client->propPatch('foo', ['{DAV:}displayname' => 'hi', '{urn:zim}gir' => null]); + + } + + function testOPTIONS() { + + $client = new ClientMock([ + 'baseUri' => '/', + ]); + + $client->response = new Response(207, [ + 'DAV' => 'calendar-access, extended-mkcol', + ]); + $result = $client->options(); + + $this->assertEquals( + ['calendar-access', 'extended-mkcol'], + $result + ); + + $request = $client->request; + $this->assertEquals('OPTIONS', $request->getMethod()); + $this->assertEquals('/', $request->getUrl()); + $this->assertEquals([ + ], $request->getHeaders()); + + } +} diff --git a/vendor/sabre/dav/tests/Sabre/DAV/CorePluginTest.php b/vendor/sabre/dav/tests/Sabre/DAV/CorePluginTest.php new file mode 100644 index 000000000..5c6f07ae8 --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/DAV/CorePluginTest.php @@ -0,0 +1,14 @@ +<?php + +namespace Sabre\DAV; + +class CorePluginTest extends \PHPUnit_Framework_TestCase { + + function testGetInfo() { + + $corePlugin = new CorePlugin(); + $this->assertEquals('core', $corePlugin->getPluginInfo()['name']); + + } + +} diff --git a/vendor/sabre/dav/tests/Sabre/DAV/DbTestHelperTrait.php b/vendor/sabre/dav/tests/Sabre/DAV/DbTestHelperTrait.php new file mode 100644 index 000000000..63e35fb88 --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/DAV/DbTestHelperTrait.php @@ -0,0 +1,143 @@ +<?php + +namespace Sabre\DAV; + +use PDO; +use PDOException; + +class DbCache { + + static $cache = []; + +} + +trait DbTestHelperTrait { + + /** + * Should be "mysql", "pgsql", "sqlite". + */ + public $driver = null; + + /** + * Returns a fully configured PDO object. + * + * @return PDO + */ + function getDb() { + + if (!$this->driver) { + throw new \Exception('You must set the $driver public property'); + } + + if (array_key_exists($this->driver, DbCache::$cache)) { + $pdo = DbCache::$cache[$this->driver]; + if ($pdo === null) { + $this->markTestSkipped($this->driver . ' was not enabled, not correctly configured or of the wrong version'); + } + return $pdo; + } + + try { + + switch ($this->driver) { + + case 'mysql' : + $pdo = new PDO(SABRE_MYSQLDSN, SABRE_MYSQLUSER, SABRE_MYSQLPASS); + break; + case 'sqlite' : + $pdo = new \PDO('sqlite:' . SABRE_TEMPDIR . '/testdb'); + break; + case 'pgsql' : + $pdo = new \PDO(SABRE_PGSQLDSN); + $version = $pdo->query('SELECT VERSION()')->fetchColumn(); + preg_match('|([0-9\.]){5,}|', $version, $matches); + $version = $matches[0]; + if (version_compare($version, '9.5.0', '<')) { + DbCache::$cache[$this->driver] = null; + $this->markTestSkipped('We require at least Postgres 9.5. This server is running ' . $version); + } + break; + + + + } + $pdo->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION); + + } catch (PDOException $e) { + + $this->markTestSkipped($this->driver . ' was not enabled or not correctly configured. Error message: ' . $e->getMessage()); + + } + + DbCache::$cache[$this->driver] = $pdo; + return $pdo; + + } + + /** + * Alias for getDb + * + * @return PDO + */ + function getPDO() { + + return $this->getDb(); + + } + + /** + * Uses .sql files from the examples directory to initialize the database. + * + * @param string $schemaName + * @return void + */ + function createSchema($schemaName) { + + $db = $this->getDb(); + + $queries = file_get_contents( + __DIR__ . '/../../../examples/sql/' . $this->driver . '.' . $schemaName . '.sql' + ); + + foreach (explode(';', $queries) as $query) { + + if (trim($query) === '') { + continue; + } + + $db->exec($query); + + } + + } + + /** + * Drops tables, if they exist + * + * @param string|string[] $tableNames + * @return void + */ + function dropTables($tableNames) { + + $tableNames = (array)$tableNames; + $db = $this->getDb(); + foreach ($tableNames as $tableName) { + $db->exec('DROP TABLE IF EXISTS ' . $tableName); + } + + + } + + function tearDown() { + + switch ($this->driver) { + + case 'sqlite' : + // Recreating sqlite, just in case + unset(DbCache::$cache[$this->driver]); + unlink(SABRE_TEMPDIR . '/testdb'); + } + + } + +} diff --git a/vendor/sabre/dav/tests/Sabre/DAV/Exception/LockedTest.php b/vendor/sabre/dav/tests/Sabre/DAV/Exception/LockedTest.php new file mode 100644 index 000000000..174a561b5 --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/DAV/Exception/LockedTest.php @@ -0,0 +1,67 @@ +<?php + +namespace Sabre\DAV\Exception; + +use DOMDocument; +use Sabre\DAV; + +class LockedTest extends \PHPUnit_Framework_TestCase { + + function testSerialize() { + + $dom = new DOMDocument('1.0'); + $dom->formatOutput = true; + $root = $dom->createElement('d:root'); + + $dom->appendChild($root); + $root->setAttribute('xmlns:d', 'DAV:'); + + $lockInfo = new DAV\Locks\LockInfo(); + $lockInfo->uri = '/foo'; + $locked = new Locked($lockInfo); + + $locked->serialize(new DAV\Server(), $root); + + $output = $dom->saveXML(); + + $expected = '<?xml version="1.0"?> +<d:root xmlns:d="DAV:"> + <d:lock-token-submitted xmlns:d="DAV:"> + <d:href>/foo</d:href> + </d:lock-token-submitted> +</d:root> +'; + + $this->assertEquals($expected, $output); + + } + + function testSerializeAmpersand() { + + $dom = new DOMDocument('1.0'); + $dom->formatOutput = true; + $root = $dom->createElement('d:root'); + + $dom->appendChild($root); + $root->setAttribute('xmlns:d', 'DAV:'); + + $lockInfo = new DAV\Locks\LockInfo(); + $lockInfo->uri = '/foo&bar'; + $locked = new Locked($lockInfo); + + $locked->serialize(new DAV\Server(), $root); + + $output = $dom->saveXML(); + + $expected = '<?xml version="1.0"?> +<d:root xmlns:d="DAV:"> + <d:lock-token-submitted xmlns:d="DAV:"> + <d:href>/foo&bar</d:href> + </d:lock-token-submitted> +</d:root> +'; + + $this->assertEquals($expected, $output); + + } +} diff --git a/vendor/sabre/dav/tests/Sabre/DAV/Exception/PaymentRequiredTest.php b/vendor/sabre/dav/tests/Sabre/DAV/Exception/PaymentRequiredTest.php new file mode 100644 index 000000000..7142937b4 --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/DAV/Exception/PaymentRequiredTest.php @@ -0,0 +1,14 @@ +<?php + +namespace Sabre\DAV\Exception; + +class PaymentRequiredTest extends \PHPUnit_Framework_TestCase { + + function testGetHTTPCode() { + + $ex = new PaymentRequired(); + $this->assertEquals(402, $ex->getHTTPCode()); + + } + +} diff --git a/vendor/sabre/dav/tests/Sabre/DAV/Exception/ServiceUnavailableTest.php b/vendor/sabre/dav/tests/Sabre/DAV/Exception/ServiceUnavailableTest.php new file mode 100644 index 000000000..1cc691e6d --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/DAV/Exception/ServiceUnavailableTest.php @@ -0,0 +1,14 @@ +<?php + +namespace Sabre\DAV\Exception; + +class ServiceUnavailableTest extends \PHPUnit_Framework_TestCase { + + function testGetHTTPCode() { + + $ex = new ServiceUnavailable(); + $this->assertEquals(503, $ex->getHTTPCode()); + + } + +} diff --git a/vendor/sabre/dav/tests/Sabre/DAV/Exception/TooManyMatchesTest.php b/vendor/sabre/dav/tests/Sabre/DAV/Exception/TooManyMatchesTest.php new file mode 100644 index 000000000..0f58e8726 --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/DAV/Exception/TooManyMatchesTest.php @@ -0,0 +1,35 @@ +<?php + +namespace Sabre\DAV\Exception; + +use DOMDocument; +use Sabre\DAV; + +class TooManyMatchesTest extends \PHPUnit_Framework_TestCase { + + function testSerialize() { + + $dom = new DOMDocument('1.0'); + $dom->formatOutput = true; + $root = $dom->createElement('d:root'); + + $dom->appendChild($root); + $root->setAttribute('xmlns:d', 'DAV:'); + + $locked = new TooManyMatches(); + + $locked->serialize(new DAV\Server(), $root); + + $output = $dom->saveXML(); + + $expected = '<?xml version="1.0"?> +<d:root xmlns:d="DAV:"> + <d:number-of-matches-within-limits xmlns:d="DAV:"/> +</d:root> +'; + + $this->assertEquals($expected, $output); + + } + +} diff --git a/vendor/sabre/dav/tests/Sabre/DAV/ExceptionTest.php b/vendor/sabre/dav/tests/Sabre/DAV/ExceptionTest.php new file mode 100644 index 000000000..0eb4f3dd8 --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/DAV/ExceptionTest.php @@ -0,0 +1,30 @@ +<?php + +namespace Sabre\DAV; + +class ExceptionTest extends \PHPUnit_Framework_TestCase { + + function testStatus() { + + $e = new Exception(); + $this->assertEquals(500, $e->getHTTPCode()); + + } + + function testExceptionStatuses() { + + $c = [ + 'Sabre\\DAV\\Exception\\NotAuthenticated' => 401, + 'Sabre\\DAV\\Exception\\InsufficientStorage' => 507, + ]; + + foreach ($c as $class => $status) { + + $obj = new $class(); + $this->assertEquals($status, $obj->getHTTPCode()); + + } + + } + +} diff --git a/vendor/sabre/dav/tests/Sabre/DAV/FSExt/DirectoryTest.php b/vendor/sabre/dav/tests/Sabre/DAV/FSExt/DirectoryTest.php new file mode 100644 index 000000000..097ebd26b --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/DAV/FSExt/DirectoryTest.php @@ -0,0 +1,30 @@ +<?php + +namespace Sabre\DAV\FSExt; + +class DirectoryTest extends \PHPUnit_Framework_TestCase { + + function create() { + + return new Directory(SABRE_TEMPDIR); + + } + + function testCreate() { + + $dir = $this->create(); + $this->assertEquals(basename(SABRE_TEMPDIR), $dir->getName()); + + } + + /** + * @expectedException \Sabre\DAV\Exception\Forbidden + */ + function testChildExistDot() { + + $dir = $this->create(); + $dir->childExists('..'); + + } + +} diff --git a/vendor/sabre/dav/tests/Sabre/DAV/FSExt/FileTest.php b/vendor/sabre/dav/tests/Sabre/DAV/FSExt/FileTest.php new file mode 100644 index 000000000..f5d65a44f --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/DAV/FSExt/FileTest.php @@ -0,0 +1,110 @@ +<?php + +namespace Sabre\DAV\FSExt; + +require_once 'Sabre/TestUtil.php'; + +class FileTest extends \PHPUnit_Framework_TestCase { + + function setUp() { + + file_put_contents(SABRE_TEMPDIR . '/file.txt', 'Contents'); + + } + + function tearDown() { + + \Sabre\TestUtil::clearTempDir(); + + } + + function testPut() { + + $filename = SABRE_TEMPDIR . '/file.txt'; + $file = new File($filename); + $result = $file->put('New contents'); + + $this->assertEquals('New contents', file_get_contents(SABRE_TEMPDIR . '/file.txt')); + $this->assertEquals( + '"' . + sha1( + fileinode($filename) . + filesize($filename) . + filemtime($filename) + ) . '"', + $result + ); + + } + + function testRange() { + + $file = new File(SABRE_TEMPDIR . '/file.txt'); + $file->put('0000000'); + $file->patch('111', 2, 3); + + $this->assertEquals('0001110', file_get_contents(SABRE_TEMPDIR . '/file.txt')); + + } + + function testRangeStream() { + + $stream = fopen('php://memory', 'r+'); + fwrite($stream, "222"); + rewind($stream); + + $file = new File(SABRE_TEMPDIR . '/file.txt'); + $file->put('0000000'); + $file->patch($stream, 2, 3); + + $this->assertEquals('0002220', file_get_contents(SABRE_TEMPDIR . '/file.txt')); + + } + + + function testGet() { + + $file = new File(SABRE_TEMPDIR . '/file.txt'); + $this->assertEquals('Contents', stream_get_contents($file->get())); + + } + + function testDelete() { + + $file = new File(SABRE_TEMPDIR . '/file.txt'); + $file->delete(); + + $this->assertFalse(file_exists(SABRE_TEMPDIR . '/file.txt')); + + } + + function testGetETag() { + + $filename = SABRE_TEMPDIR . '/file.txt'; + $file = new File($filename); + $this->assertEquals( + '"' . + sha1( + fileinode($filename) . + filesize($filename) . + filemtime($filename) + ) . '"', + $file->getETag() + ); + } + + function testGetContentType() { + + $file = new File(SABRE_TEMPDIR . '/file.txt'); + $this->assertNull($file->getContentType()); + + } + + function testGetSize() { + + $file = new File(SABRE_TEMPDIR . '/file.txt'); + $this->assertEquals(8, $file->getSize()); + + } + +} diff --git a/vendor/sabre/dav/tests/Sabre/DAV/FSExt/ServerTest.php b/vendor/sabre/dav/tests/Sabre/DAV/FSExt/ServerTest.php new file mode 100644 index 000000000..20fca490a --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/DAV/FSExt/ServerTest.php @@ -0,0 +1,246 @@ +<?php + +namespace Sabre\DAV\FSExt; + +use Sabre\DAV; +use Sabre\HTTP; + +require_once 'Sabre/DAV/AbstractServer.php'; + +class ServerTest extends DAV\AbstractServer{ + + protected function getRootNode() { + + return new Directory($this->tempDir); + + } + + function testGet() { + + $request = new HTTP\Request('GET', '/test.txt'); + $filename = $this->tempDir . '/test.txt'; + $this->server->httpRequest = $request; + $this->server->exec(); + + $this->assertEquals(200, $this->response->getStatus(), 'Invalid status code received.'); + $this->assertEquals([ + 'X-Sabre-Version' => [DAV\Version::VERSION], + 'Content-Type' => ['application/octet-stream'], + 'Content-Length' => [13], + 'Last-Modified' => [HTTP\Util::toHTTPDate(new \DateTime('@' . filemtime($filename)))], + 'ETag' => ['"' . sha1(fileinode($filename) . filesize($filename) . filemtime($filename)) . '"'], + ], + $this->response->getHeaders() + ); + + + $this->assertEquals('Test contents', stream_get_contents($this->response->body)); + + } + + function testHEAD() { + + $request = new HTTP\Request('HEAD', '/test.txt'); + $filename = $this->tempDir . '/test.txt'; + $this->server->httpRequest = ($request); + $this->server->exec(); + + $this->assertEquals([ + 'X-Sabre-Version' => [DAV\Version::VERSION], + 'Content-Type' => ['application/octet-stream'], + 'Content-Length' => [13], + 'Last-Modified' => [HTTP\Util::toHTTPDate(new \DateTime('@' . filemtime($this->tempDir . '/test.txt')))], + 'ETag' => ['"' . sha1(fileinode($filename) . filesize($filename) . filemtime($filename)) . '"'], + ], + $this->response->getHeaders() + ); + + $this->assertEquals(200, $this->response->status); + $this->assertEquals('', $this->response->body); + + } + + function testPut() { + + $request = new HTTP\Request('PUT', '/testput.txt'); + $filename = $this->tempDir . '/testput.txt'; + $request->setBody('Testing new file'); + $this->server->httpRequest = ($request); + $this->server->exec(); + + $this->assertEquals([ + 'X-Sabre-Version' => [DAV\Version::VERSION], + 'Content-Length' => ['0'], + 'ETag' => ['"' . sha1(fileinode($filename) . filesize($filename) . filemtime($filename)) . '"'], + ], $this->response->getHeaders()); + + $this->assertEquals(201, $this->response->status); + $this->assertEquals('', $this->response->body); + $this->assertEquals('Testing new file', file_get_contents($filename)); + + } + + function testPutAlreadyExists() { + + $request = new HTTP\Request('PUT', '/test.txt', ['If-None-Match' => '*']); + $request->setBody('Testing new file'); + $this->server->httpRequest = ($request); + $this->server->exec(); + + $this->assertEquals([ + 'X-Sabre-Version' => [DAV\Version::VERSION], + 'Content-Type' => ['application/xml; charset=utf-8'], + ], $this->response->getHeaders()); + + $this->assertEquals(412, $this->response->status); + $this->assertNotEquals('Testing new file', file_get_contents($this->tempDir . '/test.txt')); + + } + + function testMkcol() { + + $request = new HTTP\Request('MKCOL', '/testcol'); + $this->server->httpRequest = ($request); + $this->server->exec(); + + $this->assertEquals([ + 'X-Sabre-Version' => [DAV\Version::VERSION], + 'Content-Length' => ['0'], + ], $this->response->getHeaders()); + + $this->assertEquals(201, $this->response->status); + $this->assertEquals('', $this->response->body); + $this->assertTrue(is_dir($this->tempDir . '/testcol')); + + } + + function testPutUpdate() { + + $request = new HTTP\Request('PUT', '/test.txt'); + $request->setBody('Testing updated file'); + $this->server->httpRequest = ($request); + $this->server->exec(); + + $this->assertEquals('0', $this->response->getHeader('Content-Length')); + + $this->assertEquals(204, $this->response->status); + $this->assertEquals('', $this->response->body); + $this->assertEquals('Testing updated file', file_get_contents($this->tempDir . '/test.txt')); + + } + + function testDelete() { + + $request = new HTTP\Request('DELETE', '/test.txt'); + $this->server->httpRequest = ($request); + $this->server->exec(); + + $this->assertEquals([ + 'X-Sabre-Version' => [DAV\Version::VERSION], + 'Content-Length' => ['0'], + ], $this->response->getHeaders()); + + $this->assertEquals(204, $this->response->status); + $this->assertEquals('', $this->response->body); + $this->assertFalse(file_exists($this->tempDir . '/test.txt')); + + } + + function testDeleteDirectory() { + + mkdir($this->tempDir . '/testcol'); + file_put_contents($this->tempDir . '/testcol/test.txt', 'Hi! I\'m a file with a short lifespan'); + + $request = new HTTP\Request('DELETE', '/testcol'); + $this->server->httpRequest = ($request); + $this->server->exec(); + + $this->assertEquals([ + 'X-Sabre-Version' => [DAV\Version::VERSION], + 'Content-Length' => ['0'], + ], $this->response->getHeaders()); + $this->assertEquals(204, $this->response->status); + $this->assertEquals('', $this->response->body); + $this->assertFalse(file_exists($this->tempDir . '/testcol')); + + } + + function testOptions() { + + $request = new HTTP\Request('OPTIONS', '/'); + $this->server->httpRequest = ($request); + $this->server->exec(); + + $this->assertEquals([ + 'DAV' => ['1, 3, extended-mkcol'], + 'MS-Author-Via' => ['DAV'], + 'Allow' => ['OPTIONS, GET, HEAD, DELETE, PROPFIND, PUT, PROPPATCH, COPY, MOVE, REPORT'], + 'Accept-Ranges' => ['bytes'], + 'Content-Length' => ['0'], + 'X-Sabre-Version' => [DAV\Version::VERSION], + ], $this->response->getHeaders()); + + $this->assertEquals(200, $this->response->status); + $this->assertEquals('', $this->response->body); + + } + + function testMove() { + + mkdir($this->tempDir . '/testcol'); + + $request = new HTTP\Request('MOVE', '/test.txt', ['Destination' => '/testcol/test2.txt']); + $this->server->httpRequest = ($request); + $this->server->exec(); + + $this->assertEquals(201, $this->response->status); + $this->assertEquals('', $this->response->body); + + $this->assertEquals([ + 'Content-Length' => ['0'], + 'X-Sabre-Version' => [DAV\Version::VERSION], + ], $this->response->getHeaders()); + + $this->assertTrue( + is_file($this->tempDir . '/testcol/test2.txt') + ); + + + } + + /** + * This test checks if it's possible to move a non-FSExt collection into a + * FSExt collection. + * + * The moveInto function *should* ignore the object and let sabredav itself + * execute the slow move. + */ + function testMoveOtherObject() { + + mkdir($this->tempDir . '/tree1'); + mkdir($this->tempDir . '/tree2'); + + $tree = new DAV\Tree(new DAV\SimpleCollection('root', [ + new DAV\FS\Directory($this->tempDir . '/tree1'), + new DAV\FSExt\Directory($this->tempDir . '/tree2'), + ])); + $this->server->tree = $tree; + + $request = new HTTP\Request('MOVE', '/tree1', ['Destination' => '/tree2/tree1']); + $this->server->httpRequest = ($request); + $this->server->exec(); + + $this->assertEquals(201, $this->response->status); + $this->assertEquals('', $this->response->body); + + $this->assertEquals([ + 'Content-Length' => ['0'], + 'X-Sabre-Version' => [DAV\Version::VERSION], + ], $this->response->getHeaders()); + + $this->assertTrue( + is_dir($this->tempDir . '/tree2/tree1') + ); + + } +} diff --git a/vendor/sabre/dav/tests/Sabre/DAV/GetIfConditionsTest.php b/vendor/sabre/dav/tests/Sabre/DAV/GetIfConditionsTest.php new file mode 100644 index 000000000..d41abc00a --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/DAV/GetIfConditionsTest.php @@ -0,0 +1,337 @@ +<?php + +namespace Sabre\DAV; + +use Sabre\HTTP; + +require_once 'Sabre/HTTP/ResponseMock.php'; +require_once 'Sabre/DAV/AbstractServer.php'; + +class GetIfConditionsTest extends AbstractServer { + + function testNoConditions() { + + $request = new HTTP\Request(); + + $conditions = $this->server->getIfConditions($request); + $this->assertEquals([], $conditions); + + } + + function testLockToken() { + + $request = new HTTP\Request('GET', '/path/', ['If' => '(<opaquelocktoken:token1>)']); + $conditions = $this->server->getIfConditions($request); + + $compare = [ + + [ + 'uri' => 'path', + 'tokens' => [ + [ + 'negate' => false, + 'token' => 'opaquelocktoken:token1', + 'etag' => '', + ], + ], + + ], + + ]; + + $this->assertEquals($compare, $conditions); + + } + + function testNotLockToken() { + + $serverVars = [ + 'HTTP_IF' => '(Not <opaquelocktoken:token1>)', + 'REQUEST_URI' => '/bla' + ]; + + $request = HTTP\Sapi::createFromServerArray($serverVars); + $conditions = $this->server->getIfConditions($request); + + $compare = [ + + [ + 'uri' => 'bla', + 'tokens' => [ + [ + 'negate' => true, + 'token' => 'opaquelocktoken:token1', + 'etag' => '', + ], + ], + + ], + + ]; + $this->assertEquals($compare, $conditions); + + } + + function testLockTokenUrl() { + + $serverVars = [ + 'HTTP_IF' => '<http://www.example.com/> (<opaquelocktoken:token1>)', + ]; + + $request = HTTP\Sapi::createFromServerArray($serverVars); + $conditions = $this->server->getIfConditions($request); + + $compare = [ + + [ + 'uri' => '', + 'tokens' => [ + [ + 'negate' => false, + 'token' => 'opaquelocktoken:token1', + 'etag' => '', + ], + ], + + ], + + ]; + $this->assertEquals($compare, $conditions); + + } + + function test2LockTokens() { + + $serverVars = [ + 'HTTP_IF' => '(<opaquelocktoken:token1>) (Not <opaquelocktoken:token2>)', + 'REQUEST_URI' => '/bla', + ]; + + $request = HTTP\Sapi::createFromServerArray($serverVars); + $conditions = $this->server->getIfConditions($request); + + $compare = [ + + [ + 'uri' => 'bla', + 'tokens' => [ + [ + 'negate' => false, + 'token' => 'opaquelocktoken:token1', + 'etag' => '', + ], + [ + 'negate' => true, + 'token' => 'opaquelocktoken:token2', + 'etag' => '', + ], + ], + + ], + + ]; + $this->assertEquals($compare, $conditions); + + } + + function test2UriLockTokens() { + + $serverVars = [ + 'HTTP_IF' => '<http://www.example.org/node1> (<opaquelocktoken:token1>) <http://www.example.org/node2> (Not <opaquelocktoken:token2>)', + ]; + + $request = HTTP\Sapi::createFromServerArray($serverVars); + $conditions = $this->server->getIfConditions($request); + + $compare = [ + + [ + 'uri' => 'node1', + 'tokens' => [ + [ + 'negate' => false, + 'token' => 'opaquelocktoken:token1', + 'etag' => '', + ], + ], + ], + [ + 'uri' => 'node2', + 'tokens' => [ + [ + 'negate' => true, + 'token' => 'opaquelocktoken:token2', + 'etag' => '', + ], + ], + + ], + + ]; + $this->assertEquals($compare, $conditions); + + } + + function test2UriMultiLockTokens() { + + $serverVars = [ + 'HTTP_IF' => '<http://www.example.org/node1> (<opaquelocktoken:token1>) (<opaquelocktoken:token2>) <http://www.example.org/node2> (Not <opaquelocktoken:token3>)', + ]; + + $request = HTTP\Sapi::createFromServerArray($serverVars); + $conditions = $this->server->getIfConditions($request); + + $compare = [ + + [ + 'uri' => 'node1', + 'tokens' => [ + [ + 'negate' => false, + 'token' => 'opaquelocktoken:token1', + 'etag' => '', + ], + [ + 'negate' => false, + 'token' => 'opaquelocktoken:token2', + 'etag' => '', + ], + ], + ], + [ + 'uri' => 'node2', + 'tokens' => [ + [ + 'negate' => true, + 'token' => 'opaquelocktoken:token3', + 'etag' => '', + ], + ], + + ], + + ]; + $this->assertEquals($compare, $conditions); + + } + + function testEtag() { + + $serverVars = [ + 'HTTP_IF' => '(["etag1"])', + 'REQUEST_URI' => '/foo', + ]; + + $request = HTTP\Sapi::createFromServerArray($serverVars); + $conditions = $this->server->getIfConditions($request); + + $compare = [ + + [ + 'uri' => 'foo', + 'tokens' => [ + [ + 'negate' => false, + 'token' => '', + 'etag' => '"etag1"', + ], + ], + ], + + ]; + $this->assertEquals($compare, $conditions); + + } + + function test2Etags() { + + $serverVars = [ + 'HTTP_IF' => '<http://www.example.org/> (["etag1"]) (["etag2"])', + ]; + + $request = HTTP\Sapi::createFromServerArray($serverVars); + $conditions = $this->server->getIfConditions($request); + + $compare = [ + + [ + 'uri' => '', + 'tokens' => [ + [ + 'negate' => false, + 'token' => '', + 'etag' => '"etag1"', + ], + [ + 'negate' => false, + 'token' => '', + 'etag' => '"etag2"', + ], + ], + ], + + ]; + $this->assertEquals($compare, $conditions); + + } + + function testComplexIf() { + + $serverVars = [ + 'HTTP_IF' => '<http://www.example.org/node1> (<opaquelocktoken:token1> ["etag1"]) ' . + '(Not <opaquelocktoken:token2>) (["etag2"]) <http://www.example.org/node2> ' . + '(<opaquelocktoken:token3>) (Not <opaquelocktoken:token4>) (["etag3"])', + ]; + + $request = HTTP\Sapi::createFromServerArray($serverVars); + $conditions = $this->server->getIfConditions($request); + + $compare = [ + + [ + 'uri' => 'node1', + 'tokens' => [ + [ + 'negate' => false, + 'token' => 'opaquelocktoken:token1', + 'etag' => '"etag1"', + ], + [ + 'negate' => true, + 'token' => 'opaquelocktoken:token2', + 'etag' => '', + ], + [ + 'negate' => false, + 'token' => '', + 'etag' => '"etag2"', + ], + ], + ], + [ + 'uri' => 'node2', + 'tokens' => [ + [ + 'negate' => false, + 'token' => 'opaquelocktoken:token3', + 'etag' => '', + ], + [ + 'negate' => true, + 'token' => 'opaquelocktoken:token4', + 'etag' => '', + ], + [ + 'negate' => false, + 'token' => '', + 'etag' => '"etag3"', + ], + ], + ], + + ]; + $this->assertEquals($compare, $conditions); + + } + +} diff --git a/vendor/sabre/dav/tests/Sabre/DAV/HTTPPreferParsingTest.php b/vendor/sabre/dav/tests/Sabre/DAV/HTTPPreferParsingTest.php new file mode 100644 index 000000000..cd8bee968 --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/DAV/HTTPPreferParsingTest.php @@ -0,0 +1,188 @@ +<?php + +namespace Sabre\DAV; + +use Sabre\HTTP; + +class HTTPPreferParsingTest extends \Sabre\DAVServerTest { + + function testParseSimple() { + + $httpRequest = HTTP\Sapi::createFromServerArray([ + 'HTTP_PREFER' => 'return-asynch', + ]); + + $server = new Server(); + $server->httpRequest = $httpRequest; + + $this->assertEquals([ + 'respond-async' => true, + 'return' => null, + 'handling' => null, + 'wait' => null, + ], $server->getHTTPPrefer()); + + } + + function testParseValue() { + + $httpRequest = HTTP\Sapi::createFromServerArray([ + 'HTTP_PREFER' => 'wait=10', + ]); + + $server = new Server(); + $server->httpRequest = $httpRequest; + + $this->assertEquals([ + 'respond-async' => false, + 'return' => null, + 'handling' => null, + 'wait' => '10', + ], $server->getHTTPPrefer()); + + } + + function testParseMultiple() { + + $httpRequest = HTTP\Sapi::createFromServerArray([ + 'HTTP_PREFER' => 'return-minimal, strict,lenient', + ]); + + $server = new Server(); + $server->httpRequest = $httpRequest; + + $this->assertEquals([ + 'respond-async' => false, + 'return' => 'minimal', + 'handling' => 'lenient', + 'wait' => null, + ], $server->getHTTPPrefer()); + + } + + function testParseWeirdValue() { + + $httpRequest = HTTP\Sapi::createFromServerArray([ + 'HTTP_PREFER' => 'BOOOH', + ]); + + $server = new Server(); + $server->httpRequest = $httpRequest; + + $this->assertEquals([ + 'respond-async' => false, + 'return' => null, + 'handling' => null, + 'wait' => null, + 'boooh' => true, + ], $server->getHTTPPrefer()); + + } + + function testBrief() { + + $httpRequest = HTTP\Sapi::createFromServerArray([ + 'HTTP_BRIEF' => 't', + ]); + + $server = new Server(); + $server->httpRequest = $httpRequest; + + $this->assertEquals([ + 'respond-async' => false, + 'return' => 'minimal', + 'handling' => null, + 'wait' => null, + ], $server->getHTTPPrefer()); + + } + + /** + * propfindMinimal + * + * @return void + */ + function testpropfindMinimal() { + + $request = HTTP\Sapi::createFromServerArray([ + 'REQUEST_METHOD' => 'PROPFIND', + 'REQUEST_URI' => '/', + 'HTTP_PREFER' => 'return-minimal', + ]); + $request->setBody(<<<BLA +<?xml version="1.0"?> +<d:propfind xmlns:d="DAV:"> + <d:prop> + <d:something /> + <d:resourcetype /> + </d:prop> +</d:propfind> +BLA + ); + + $response = $this->request($request); + + $body = $response->getBodyAsString(); + + $this->assertEquals(207, $response->getStatus(), $body); + + $this->assertTrue(strpos($body, 'resourcetype') !== false, $body); + $this->assertTrue(strpos($body, 'something') === false, $body); + + } + + function testproppatchMinimal() { + + $request = new HTTP\Request('PROPPATCH', '/', ['Prefer' => 'return-minimal']); + $request->setBody(<<<BLA +<?xml version="1.0"?> +<d:propertyupdate xmlns:d="DAV:"> + <d:set> + <d:prop> + <d:something>nope!</d:something> + </d:prop> + </d:set> +</d:propertyupdate> +BLA + ); + + $this->server->on('propPatch', function($path, PropPatch $propPatch) { + + $propPatch->handle('{DAV:}something', function($props) { + return true; + }); + + }); + + $response = $this->request($request); + + $this->assertEquals(0, strlen($response->body), 'Expected empty body: ' . $response->body); + $this->assertEquals(204, $response->status); + + } + + function testproppatchMinimalError() { + + $request = new HTTP\Request('PROPPATCH', '/', ['Prefer' => 'return-minimal']); + $request->setBody(<<<BLA +<?xml version="1.0"?> +<d:propertyupdate xmlns:d="DAV:"> + <d:set> + <d:prop> + <d:something>nope!</d:something> + </d:prop> + </d:set> +</d:propertyupdate> +BLA + ); + + $response = $this->request($request); + + $body = $response->getBodyAsString(); + + $this->assertEquals(207, $response->status); + $this->assertTrue(strpos($body, 'something') !== false); + $this->assertTrue(strpos($body, '403 Forbidden') !== false, $body); + + } +} diff --git a/vendor/sabre/dav/tests/Sabre/DAV/HttpCopyTest.php b/vendor/sabre/dav/tests/Sabre/DAV/HttpCopyTest.php new file mode 100644 index 000000000..b5e64369e --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/DAV/HttpCopyTest.php @@ -0,0 +1,199 @@ +<?php + +namespace Sabre\DAV; + +use Sabre\DAVServerTest; +use Sabre\HTTP; + +/** + * Tests related to the COPY request. + * + * @copyright Copyright (C) fruux GmbH (https://fruux.com/) + * @author Evert Pot (http://evertpot.com/) + * @license http://sabre.io/license/ Modified BSD License + */ +class HttpCopyTest extends DAVServerTest { + + /** + * Sets up the DAV tree. + * + * @return void + */ + function setUpTree() { + + $this->tree = new Mock\Collection('root', [ + 'file1' => 'content1', + 'file2' => 'content2', + 'coll1' => [ + 'file3' => 'content3', + 'file4' => 'content4', + ] + ]); + + } + + function testCopyFile() { + + $request = new HTTP\Request('COPY', '/file1', [ + 'Destination' => '/file5' + ]); + $response = $this->request($request); + $this->assertEquals(201, $response->getStatus()); + $this->assertEquals('content1', $this->tree->getChild('file5')->get()); + + } + + function testCopyFileToSelf() { + + $request = new HTTP\Request('COPY', '/file1', [ + 'Destination' => '/file1' + ]); + $response = $this->request($request); + $this->assertEquals(403, $response->getStatus()); + + } + + function testCopyFileToExisting() { + + $request = new HTTP\Request('COPY', '/file1', [ + 'Destination' => '/file2' + ]); + $response = $this->request($request); + $this->assertEquals(204, $response->getStatus()); + $this->assertEquals('content1', $this->tree->getChild('file2')->get()); + + } + + function testCopyFileToExistingOverwriteT() { + + $request = new HTTP\Request('COPY', '/file1', [ + 'Destination' => '/file2', + 'Overwrite' => 'T', + ]); + $response = $this->request($request); + $this->assertEquals(204, $response->getStatus()); + $this->assertEquals('content1', $this->tree->getChild('file2')->get()); + + } + + function testCopyFileToExistingOverwriteBadValue() { + + $request = new HTTP\Request('COPY', '/file1', [ + 'Destination' => '/file2', + 'Overwrite' => 'B', + ]); + $response = $this->request($request); + $this->assertEquals(400, $response->getStatus()); + + } + + function testCopyFileNonExistantParent() { + + $request = new HTTP\Request('COPY', '/file1', [ + 'Destination' => '/notfound/file2', + ]); + $response = $this->request($request); + $this->assertEquals(409, $response->getStatus()); + + } + + function testCopyFileToExistingOverwriteF() { + + $request = new HTTP\Request('COPY', '/file1', [ + 'Destination' => '/file2', + 'Overwrite' => 'F', + ]); + $response = $this->request($request); + $this->assertEquals(412, $response->getStatus()); + $this->assertEquals('content2', $this->tree->getChild('file2')->get()); + + } + + function testCopyFileToExistinBlockedCreateDestination() { + + $this->server->on('beforeBind', function($path) { + + if ($path === 'file2') { + return false; + } + + }); + $request = new HTTP\Request('COPY', '/file1', [ + 'Destination' => '/file2', + 'Overwrite' => 'T', + ]); + $response = $this->request($request); + + // This checks if the destination file is intact. + $this->assertEquals('content2', $this->tree->getChild('file2')->get()); + + } + + function testCopyColl() { + + $request = new HTTP\Request('COPY', '/coll1', [ + 'Destination' => '/coll2' + ]); + $response = $this->request($request); + $this->assertEquals(201, $response->getStatus()); + $this->assertEquals('content3', $this->tree->getChild('coll2')->getChild('file3')->get()); + + } + + function testCopyCollToSelf() { + + $request = new HTTP\Request('COPY', '/coll1', [ + 'Destination' => '/coll1' + ]); + $response = $this->request($request); + $this->assertEquals(403, $response->getStatus()); + + } + + function testCopyCollToExisting() { + + $request = new HTTP\Request('COPY', '/coll1', [ + 'Destination' => '/file2' + ]); + $response = $this->request($request); + $this->assertEquals(204, $response->getStatus()); + $this->assertEquals('content3', $this->tree->getChild('file2')->getChild('file3')->get()); + + } + + function testCopyCollToExistingOverwriteT() { + + $request = new HTTP\Request('COPY', '/coll1', [ + 'Destination' => '/file2', + 'Overwrite' => 'T', + ]); + $response = $this->request($request); + $this->assertEquals(204, $response->getStatus()); + $this->assertEquals('content3', $this->tree->getChild('file2')->getChild('file3')->get()); + + } + + function testCopyCollToExistingOverwriteF() { + + $request = new HTTP\Request('COPY', '/coll1', [ + 'Destination' => '/file2', + 'Overwrite' => 'F', + ]); + $response = $this->request($request); + $this->assertEquals(412, $response->getStatus()); + $this->assertEquals('content2', $this->tree->getChild('file2')->get()); + + } + + function testCopyCollIntoSubtree() { + + $request = new HTTP\Request('COPY', '/coll1', [ + 'Destination' => '/coll1/subcol', + ]); + $response = $this->request($request); + $this->assertEquals(409, $response->getStatus()); + + } + + +} diff --git a/vendor/sabre/dav/tests/Sabre/DAV/HttpDeleteTest.php b/vendor/sabre/dav/tests/Sabre/DAV/HttpDeleteTest.php new file mode 100644 index 000000000..bd1b33150 --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/DAV/HttpDeleteTest.php @@ -0,0 +1,137 @@ +<?php + +namespace Sabre\DAV; + +use Sabre\DAVServerTest; +use Sabre\HTTP; + +/** + * Tests related to the PUT request. + * + * @copyright Copyright (C) fruux GmbH (https://fruux.com/) + * @author Evert Pot (http://evertpot.com/) + * @license http://sabre.io/license/ Modified BSD License + */ +class HttpDeleteTest extends DAVServerTest { + + /** + * Sets up the DAV tree. + * + * @return void + */ + function setUpTree() { + + $this->tree = new Mock\Collection('root', [ + 'file1' => 'foo', + 'dir' => [ + 'subfile' => 'bar', + 'subfile2' => 'baz', + ], + ]); + + } + + /** + * A successful DELETE + */ + function testDelete() { + + $request = new HTTP\Request('DELETE', '/file1'); + + $response = $this->request($request); + + $this->assertEquals( + 204, + $response->getStatus(), + "Incorrect status code. Response body: " . $response->getBodyAsString() + ); + + $this->assertEquals( + [ + 'X-Sabre-Version' => [Version::VERSION], + 'Content-Length' => ['0'], + ], + $response->getHeaders() + ); + + } + + /** + * Deleting a Directory + */ + function testDeleteDirectory() { + + $request = new HTTP\Request('DELETE', '/dir'); + + $response = $this->request($request); + + $this->assertEquals( + 204, + $response->getStatus(), + "Incorrect status code. Response body: " . $response->getBodyAsString() + ); + + $this->assertEquals( + [ + 'X-Sabre-Version' => [Version::VERSION], + 'Content-Length' => ['0'], + ], + $response->getHeaders() + ); + + } + + /** + * DELETE on a node that does not exist + */ + function testDeleteNotFound() { + + $request = new HTTP\Request('DELETE', '/file2'); + $response = $this->request($request); + + $this->assertEquals( + 404, + $response->getStatus(), + "Incorrect status code. Response body: " . $response->getBodyAsString() + ); + + } + + /** + * DELETE with preconditions + */ + function testDeletePreconditions() { + + $request = new HTTP\Request('DELETE', '/file1', [ + 'If-Match' => '"' . md5('foo') . '"', + ]); + + $response = $this->request($request); + + $this->assertEquals( + 204, + $response->getStatus(), + "Incorrect status code. Response body: " . $response->getBodyAsString() + ); + + } + + /** + * DELETE with incorrect preconditions + */ + function testDeletePreconditionsFailed() { + + $request = new HTTP\Request('DELETE', '/file1', [ + 'If-Match' => '"' . md5('bar') . '"', + ]); + + $response = $this->request($request); + + $this->assertEquals( + 412, + $response->getStatus(), + "Incorrect status code. Response body: " . $response->getBodyAsString() + ); + + } +} diff --git a/vendor/sabre/dav/tests/Sabre/DAV/HttpGetTest.php b/vendor/sabre/dav/tests/Sabre/DAV/HttpGetTest.php new file mode 100644 index 000000000..1eefba706 --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/DAV/HttpGetTest.php @@ -0,0 +1,158 @@ +<?php + +namespace Sabre\DAV; + +use Sabre\DAVServerTest; +use Sabre\HTTP; + +/** + * Tests related to the GET request. + * + * @copyright Copyright (C) fruux GmbH (https://fruux.com/) + * @author Evert Pot (http://evertpot.com/) + * @license http://sabre.io/license/ Modified BSD License + */ +class HttpGetTest extends DAVServerTest { + + /** + * Sets up the DAV tree. + * + * @return void + */ + function setUpTree() { + + $this->tree = new Mock\Collection('root', [ + 'file1' => 'foo', + new Mock\Collection('dir', []), + new Mock\StreamingFile('streaming', 'stream') + ]); + + } + + function testGet() { + + $request = new HTTP\Request('GET', '/file1'); + $response = $this->request($request); + + $this->assertEquals(200, $response->getStatus()); + + // Removing Last-Modified because it keeps changing. + $response->removeHeader('Last-Modified'); + + $this->assertEquals( + [ + 'X-Sabre-Version' => [Version::VERSION], + 'Content-Type' => ['application/octet-stream'], + 'Content-Length' => [3], + 'ETag' => ['"' . md5('foo') . '"'], + ], + $response->getHeaders() + ); + + $this->assertEquals('foo', $response->getBodyAsString()); + + } + + function testGetHttp10() { + + $request = new HTTP\Request('GET', '/file1'); + $request->setHttpVersion('1.0'); + $response = $this->request($request); + + $this->assertEquals(200, $response->getStatus()); + + // Removing Last-Modified because it keeps changing. + $response->removeHeader('Last-Modified'); + + $this->assertEquals( + [ + 'X-Sabre-Version' => [Version::VERSION], + 'Content-Type' => ['application/octet-stream'], + 'Content-Length' => [3], + 'ETag' => ['"' . md5('foo') . '"'], + ], + $response->getHeaders() + ); + + $this->assertEquals('1.0', $response->getHttpVersion()); + + $this->assertEquals('foo', $response->getBodyAsString()); + + } + + function testGet404() { + + $request = new HTTP\Request('GET', '/notfound'); + $response = $this->request($request); + + $this->assertEquals(404, $response->getStatus()); + + } + + function testGet404_aswell() { + + $request = new HTTP\Request('GET', '/file1/subfile'); + $response = $this->request($request); + + $this->assertEquals(404, $response->getStatus()); + + } + + /** + * We automatically normalize double slashes. + */ + function testGetDoubleSlash() { + + $request = new HTTP\Request('GET', '//file1'); + $response = $this->request($request); + + $this->assertEquals(200, $response->getStatus()); + + // Removing Last-Modified because it keeps changing. + $response->removeHeader('Last-Modified'); + + $this->assertEquals( + [ + 'X-Sabre-Version' => [Version::VERSION], + 'Content-Type' => ['application/octet-stream'], + 'Content-Length' => [3], + 'ETag' => ['"' . md5('foo') . '"'], + ], + $response->getHeaders() + ); + + $this->assertEquals('foo', $response->getBodyAsString()); + + } + + function testGetCollection() { + + $request = new HTTP\Request('GET', '/dir'); + $response = $this->request($request); + + $this->assertEquals(501, $response->getStatus()); + + } + + function testGetStreaming() { + + $request = new HTTP\Request('GET', '/streaming'); + $response = $this->request($request); + + $this->assertEquals(200, $response->getStatus()); + + // Removing Last-Modified because it keeps changing. + $response->removeHeader('Last-Modified'); + + $this->assertEquals( + [ + 'X-Sabre-Version' => [Version::VERSION], + 'Content-Type' => ['application/octet-stream'], + ], + $response->getHeaders() + ); + + $this->assertEquals('stream', $response->getBodyAsString()); + + } +} diff --git a/vendor/sabre/dav/tests/Sabre/DAV/HttpHeadTest.php b/vendor/sabre/dav/tests/Sabre/DAV/HttpHeadTest.php new file mode 100644 index 000000000..2cd1c5ea3 --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/DAV/HttpHeadTest.php @@ -0,0 +1,97 @@ +<?php + +namespace Sabre\DAV; + +use Sabre\DAVServerTest; +use Sabre\HTTP; + +/** + * Tests related to the HEAD request. + * + * @copyright Copyright (C) fruux GmbH (https://fruux.com/) + * @author Evert Pot (http://evertpot.com/) + * @license http://sabre.io/license/ Modified BSD License + */ +class HttpHeadTest extends DAVServerTest { + + /** + * Sets up the DAV tree. + * + * @return void + */ + function setUpTree() { + + $this->tree = new Mock\Collection('root', [ + 'file1' => 'foo', + new Mock\Collection('dir', []), + new Mock\StreamingFile('streaming', 'stream') + ]); + + } + + function testHEAD() { + + $request = new HTTP\Request('HEAD', '//file1'); + $response = $this->request($request); + + $this->assertEquals(200, $response->getStatus()); + + // Removing Last-Modified because it keeps changing. + $response->removeHeader('Last-Modified'); + + $this->assertEquals( + [ + 'X-Sabre-Version' => [Version::VERSION], + 'Content-Type' => ['application/octet-stream'], + 'Content-Length' => [3], + 'ETag' => ['"' . md5('foo') . '"'], + ], + $response->getHeaders() + ); + + $this->assertEquals('', $response->getBodyAsString()); + + } + + /** + * According to the specs, HEAD should behave identical to GET. But, broken + * clients needs HEAD requests on collections to respond with a 200, so + * that's what we do. + */ + function testHEADCollection() { + + $request = new HTTP\Request('HEAD', '/dir'); + $response = $this->request($request); + + $this->assertEquals(200, $response->getStatus()); + + } + + /** + * HEAD automatically internally maps to GET via a sub-request. + * The Auth plugin must not be triggered twice for these, so we'll + * test for that. + */ + function testDoubleAuth() { + + $count = 0; + + $authBackend = new Auth\Backend\BasicCallBack(function($userName, $password) use (&$count) { + $count++; + return true; + }); + $this->server->addPlugin( + new Auth\Plugin( + $authBackend + ) + ); + $request = new HTTP\Request('HEAD', '/file1', ['Authorization' => 'Basic ' . base64_encode('user:pass')]); + $response = $this->request($request); + + $this->assertEquals(200, $response->getStatus()); + + $this->assertEquals(1, $count, 'Auth was triggered twice :('); + + } + +} diff --git a/vendor/sabre/dav/tests/Sabre/DAV/HttpMoveTest.php b/vendor/sabre/dav/tests/Sabre/DAV/HttpMoveTest.php new file mode 100644 index 000000000..52f7c674e --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/DAV/HttpMoveTest.php @@ -0,0 +1,119 @@ +<?php + +namespace Sabre\DAV; + +use Sabre\DAVServerTest; +use Sabre\HTTP; + +/** + * Tests related to the MOVE request. + * + * @copyright Copyright (C) fruux GmbH (https://fruux.com/) + * @author Evert Pot (http://evertpot.com/) + * @license http://sabre.io/license/ Modified BSD License + */ +class HttpMoveTest extends DAVServerTest { + + /** + * Sets up the DAV tree. + * + * @return void + */ + function setUpTree() { + + $this->tree = new Mock\Collection('root', [ + 'file1' => 'content1', + 'file2' => 'content2', + ]); + + } + + function testMoveToSelf() { + + $request = new HTTP\Request('MOVE', '/file1', [ + 'Destination' => '/file1' + ]); + $response = $this->request($request); + $this->assertEquals(403, $response->getStatus()); + $this->assertEquals('content1', $this->tree->getChild('file1')->get()); + + } + + function testMove() { + + $request = new HTTP\Request('MOVE', '/file1', [ + 'Destination' => '/file3' + ]); + $response = $this->request($request); + $this->assertEquals(201, $response->getStatus(), print_r($response, true)); + $this->assertEquals('content1', $this->tree->getChild('file3')->get()); + $this->assertFalse($this->tree->childExists('file1')); + + } + + function testMoveToExisting() { + + $request = new HTTP\Request('MOVE', '/file1', [ + 'Destination' => '/file2' + ]); + $response = $this->request($request); + $this->assertEquals(204, $response->getStatus(), print_r($response, true)); + $this->assertEquals('content1', $this->tree->getChild('file2')->get()); + $this->assertFalse($this->tree->childExists('file1')); + + } + + function testMoveToExistingOverwriteT() { + + $request = new HTTP\Request('MOVE', '/file1', [ + 'Destination' => '/file2', + 'Overwrite' => 'T', + ]); + $response = $this->request($request); + $this->assertEquals(204, $response->getStatus(), print_r($response, true)); + $this->assertEquals('content1', $this->tree->getChild('file2')->get()); + $this->assertFalse($this->tree->childExists('file1')); + + } + + function testMoveToExistingOverwriteF() { + + $request = new HTTP\Request('MOVE', '/file1', [ + 'Destination' => '/file2', + 'Overwrite' => 'F', + ]); + $response = $this->request($request); + $this->assertEquals(412, $response->getStatus(), print_r($response, true)); + $this->assertEquals('content1', $this->tree->getChild('file1')->get()); + $this->assertEquals('content2', $this->tree->getChild('file2')->get()); + $this->assertTrue($this->tree->childExists('file1')); + $this->assertTrue($this->tree->childExists('file2')); + + } + + /** + * If we MOVE to an existing file, but a plugin prevents the original from + * being deleted, we need to make sure that the server does not delete + * the destination. + */ + function testMoveToExistingBlockedDeleteSource() { + + $this->server->on('beforeUnbind', function($path) { + + if ($path === 'file1') { + throw new \Sabre\DAV\Exception\Forbidden('uh oh'); + } + + }); + $request = new HTTP\Request('MOVE', '/file1', [ + 'Destination' => '/file2' + ]); + $response = $this->request($request); + $this->assertEquals(403, $response->getStatus(), print_r($response, true)); + $this->assertEquals('content1', $this->tree->getChild('file1')->get()); + $this->assertEquals('content2', $this->tree->getChild('file2')->get()); + $this->assertTrue($this->tree->childExists('file1')); + $this->assertTrue($this->tree->childExists('file2')); + + } +} diff --git a/vendor/sabre/dav/tests/Sabre/DAV/HttpPutTest.php b/vendor/sabre/dav/tests/Sabre/DAV/HttpPutTest.php new file mode 100644 index 000000000..86480b1c2 --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/DAV/HttpPutTest.php @@ -0,0 +1,349 @@ +<?php + +namespace Sabre\DAV; + +use Sabre\DAVServerTest; +use Sabre\HTTP; + +/** + * Tests related to the PUT request. + * + * @copyright Copyright (C) fruux GmbH (https://fruux.com/) + * @author Evert Pot (http://evertpot.com/) + * @license http://sabre.io/license/ Modified BSD License + */ +class HttpPutTest extends DAVServerTest { + + /** + * Sets up the DAV tree. + * + * @return void + */ + function setUpTree() { + + $this->tree = new Mock\Collection('root', [ + 'file1' => 'foo', + ]); + + } + + /** + * A successful PUT of a new file. + */ + function testPut() { + + $request = new HTTP\Request('PUT', '/file2', [], 'hello'); + + $response = $this->request($request); + + $this->assertEquals(201, $response->getStatus(), 'Incorrect status code received. Full response body:' . $response->getBodyAsString()); + + $this->assertEquals( + 'hello', + $this->server->tree->getNodeForPath('file2')->get() + ); + + $this->assertEquals( + [ + 'X-Sabre-Version' => [Version::VERSION], + 'Content-Length' => ['0'], + 'ETag' => ['"' . md5('hello') . '"'] + ], + $response->getHeaders() + ); + + } + + /** + * A successful PUT on an existing file. + * + * @depends testPut + */ + function testPutExisting() { + + $request = new HTTP\Request('PUT', '/file1', [], 'bar'); + + $response = $this->request($request); + + $this->assertEquals(204, $response->getStatus()); + + $this->assertEquals( + 'bar', + $this->server->tree->getNodeForPath('file1')->get() + ); + + $this->assertEquals( + [ + 'X-Sabre-Version' => [Version::VERSION], + 'Content-Length' => ['0'], + 'ETag' => ['"' . md5('bar') . '"'] + ], + $response->getHeaders() + ); + + } + + /** + * PUT on existing file with If-Match: * + * + * @depends testPutExisting + */ + function testPutExistingIfMatchStar() { + + $request = new HTTP\Request( + 'PUT', + '/file1', + ['If-Match' => '*'], + 'hello' + ); + + $response = $this->request($request); + + $this->assertEquals(204, $response->getStatus()); + + $this->assertEquals( + 'hello', + $this->server->tree->getNodeForPath('file1')->get() + ); + + $this->assertEquals( + [ + 'X-Sabre-Version' => [Version::VERSION], + 'Content-Length' => ['0'], + 'ETag' => ['"' . md5('hello') . '"'] + ], + $response->getHeaders() + ); + + } + + /** + * PUT on existing file with If-Match: with a correct etag + * + * @depends testPutExisting + */ + function testPutExistingIfMatchCorrect() { + + $request = new HTTP\Request( + 'PUT', + '/file1', + ['If-Match' => '"' . md5('foo') . '"'], + 'hello' + ); + + $response = $this->request($request); + + $this->assertEquals(204, $response->status); + + $this->assertEquals( + 'hello', + $this->server->tree->getNodeForPath('file1')->get() + ); + + $this->assertEquals( + [ + 'X-Sabre-Version' => [Version::VERSION], + 'Content-Length' => ['0'], + 'ETag' => ['"' . md5('hello') . '"'], + ], + $response->getHeaders() + ); + + } + + /** + * PUT with Content-Range should be rejected. + * + * @depends testPut + */ + function testPutContentRange() { + + $request = new HTTP\Request( + 'PUT', + '/file2', + ['Content-Range' => 'bytes/100-200'], + 'hello' + ); + + $response = $this->request($request); + $this->assertEquals(400, $response->getStatus()); + + } + + /** + * PUT on non-existing file with If-None-Match: * should work. + * + * @depends testPut + */ + function testPutIfNoneMatchStar() { + + $request = new HTTP\Request( + 'PUT', + '/file2', + ['If-None-Match' => '*'], + 'hello' + ); + + $response = $this->request($request); + + $this->assertEquals(201, $response->getStatus()); + + $this->assertEquals( + 'hello', + $this->server->tree->getNodeForPath('file2')->get() + ); + + $this->assertEquals( + [ + 'X-Sabre-Version' => [Version::VERSION], + 'Content-Length' => ['0'], + 'ETag' => ['"' . md5('hello') . '"'] + ], + $response->getHeaders() + ); + + } + + /** + * PUT on non-existing file with If-Match: * should fail. + * + * @depends testPut + */ + function testPutIfMatchStar() { + + $request = new HTTP\Request( + 'PUT', + '/file2', + ['If-Match' => '*'], + 'hello' + ); + + $response = $this->request($request); + + $this->assertEquals(412, $response->getStatus()); + + } + + /** + * PUT on existing file with If-None-Match: * should fail. + * + * @depends testPut + */ + function testPutExistingIfNoneMatchStar() { + + $request = new HTTP\Request( + 'PUT', + '/file1', + ['If-None-Match' => '*'], + 'hello' + ); + $request->setBody('hello'); + + $response = $this->request($request); + + $this->assertEquals(412, $response->getStatus()); + + } + + /** + * PUT thats created in a non-collection should be rejected. + * + * @depends testPut + */ + function testPutNoParent() { + + $request = new HTTP\Request( + 'PUT', + '/file1/file2', + [], + 'hello' + ); + + $response = $this->request($request); + $this->assertEquals(409, $response->getStatus()); + + } + + /** + * Finder may sometimes make a request, which gets its content-body + * stripped. We can't always prevent this from happening, but in some cases + * we can detected this and return an error instead. + * + * @depends testPut + */ + function testFinderPutSuccess() { + + $request = new HTTP\Request( + 'PUT', + '/file2', + ['X-Expected-Entity-Length' => '5'], + 'hello' + ); + $response = $this->request($request); + + $this->assertEquals(201, $response->getStatus()); + + $this->assertEquals( + 'hello', + $this->server->tree->getNodeForPath('file2')->get() + ); + + $this->assertEquals( + [ + 'X-Sabre-Version' => [Version::VERSION], + 'Content-Length' => ['0'], + 'ETag' => ['"' . md5('hello') . '"'], + ], + $response->getHeaders() + ); + + } + + /** + * Same as the last one, but in this case we're mimicing a failed request. + * + * @depends testFinderPutSuccess + */ + function testFinderPutFail() { + + $request = new HTTP\Request( + 'PUT', + '/file2', + ['X-Expected-Entity-Length' => '5'], + '' + ); + + $response = $this->request($request); + + $this->assertEquals(403, $response->getStatus()); + + } + + /** + * Plugins can intercept PUT. We need to make sure that works. + * + * @depends testPut + */ + function testPutIntercept() { + + $this->server->on('beforeBind', function($uri) { + $this->server->httpResponse->setStatus(418); + return false; + }); + + $request = new HTTP\Request('PUT', '/file2', [], 'hello'); + $response = $this->request($request); + + $this->assertEquals(418, $response->getStatus(), 'Incorrect status code received. Full response body: ' . $response->getBodyAsString()); + + $this->assertFalse( + $this->server->tree->nodeExists('file2') + ); + + $this->assertEquals([ + 'X-Sabre-Version' => [Version::VERSION], + ], $response->getHeaders()); + + } + +} diff --git a/vendor/sabre/dav/tests/Sabre/DAV/Issue33Test.php b/vendor/sabre/dav/tests/Sabre/DAV/Issue33Test.php new file mode 100644 index 000000000..ba2cf3dc1 --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/DAV/Issue33Test.php @@ -0,0 +1,106 @@ +<?php + +namespace Sabre\DAV; + +use Sabre\HTTP; + +require_once 'Sabre/TestUtil.php'; + +class Issue33Test extends \PHPUnit_Framework_TestCase { + + function setUp() { + + \Sabre\TestUtil::clearTempDir(); + + } + + function testCopyMoveInfo() { + + $bar = new SimpleCollection('bar'); + $root = new SimpleCollection('webdav', [$bar]); + + $server = new Server($root); + $server->setBaseUri('/webdav/'); + + $serverVars = [ + 'REQUEST_URI' => '/webdav/bar', + 'HTTP_DESTINATION' => 'http://dev2.tribalos.com/webdav/%C3%A0fo%C3%B3', + 'HTTP_OVERWRITE' => 'F', + ]; + + $request = HTTP\Sapi::createFromServerArray($serverVars); + + $server->httpRequest = $request; + + $info = $server->getCopyAndMoveInfo($request); + + $this->assertEquals('%C3%A0fo%C3%B3', urlencode($info['destination'])); + $this->assertFalse($info['destinationExists']); + $this->assertFalse($info['destinationNode']); + + } + + function testTreeMove() { + + mkdir(SABRE_TEMPDIR . '/issue33'); + $dir = new FS\Directory(SABRE_TEMPDIR . '/issue33'); + + $dir->createDirectory('bar'); + + $tree = new Tree($dir); + $tree->move('bar', urldecode('%C3%A0fo%C3%B3')); + + $node = $tree->getNodeForPath(urldecode('%C3%A0fo%C3%B3')); + $this->assertEquals(urldecode('%C3%A0fo%C3%B3'), $node->getName()); + + } + + function testDirName() { + + $dirname1 = 'bar'; + $dirname2 = urlencode('%C3%A0fo%C3%B3'); + + $this->assertTrue(dirname($dirname1) == dirname($dirname2)); + + } + + /** + * @depends testTreeMove + * @depends testCopyMoveInfo + */ + function testEverything() { + + // Request object + $serverVars = [ + 'REQUEST_METHOD' => 'MOVE', + 'REQUEST_URI' => '/webdav/bar', + 'HTTP_DESTINATION' => 'http://dev2.tribalos.com/webdav/%C3%A0fo%C3%B3', + 'HTTP_OVERWRITE' => 'F', + ]; + + $request = HTTP\Sapi::createFromServerArray($serverVars); + $request->setBody(''); + + $response = new HTTP\ResponseMock(); + + // Server setup + mkdir(SABRE_TEMPDIR . '/issue33'); + $dir = new FS\Directory(SABRE_TEMPDIR . '/issue33'); + + $dir->createDirectory('bar'); + + $tree = new Tree($dir); + + $server = new Server($tree); + $server->setBaseUri('/webdav/'); + + $server->httpRequest = $request; + $server->httpResponse = $response; + $server->sapi = new HTTP\SapiMock(); + $server->exec(); + + $this->assertTrue(file_exists(SABRE_TEMPDIR . '/issue33/' . urldecode('%C3%A0fo%C3%B3'))); + + } + +} diff --git a/vendor/sabre/dav/tests/Sabre/DAV/Locks/Backend/AbstractTest.php b/vendor/sabre/dav/tests/Sabre/DAV/Locks/Backend/AbstractTest.php new file mode 100644 index 000000000..bbde69097 --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/DAV/Locks/Backend/AbstractTest.php @@ -0,0 +1,196 @@ +<?php + +namespace Sabre\DAV\Locks\Backend; + +use Sabre\DAV; + +abstract class AbstractTest extends \PHPUnit_Framework_TestCase { + + /** + * @abstract + * @return AbstractBackend + */ + abstract function getBackend(); + + function testSetup() { + + $backend = $this->getBackend(); + $this->assertInstanceOf('Sabre\\DAV\\Locks\\Backend\\AbstractBackend', $backend); + + } + + /** + * @depends testSetup + */ + function testGetLocks() { + + $backend = $this->getBackend(); + + $lock = new DAV\Locks\LockInfo(); + $lock->owner = 'Sinterklaas'; + $lock->timeout = 60; + $lock->created = time(); + $lock->token = 'MY-UNIQUE-TOKEN'; + $lock->uri = 'someuri'; + + $this->assertTrue($backend->lock('someuri', $lock)); + + $locks = $backend->getLocks('someuri', false); + + $this->assertEquals(1, count($locks)); + $this->assertEquals('Sinterklaas', $locks[0]->owner); + $this->assertEquals('someuri', $locks[0]->uri); + + } + + /** + * @depends testGetLocks + */ + function testGetLocksParent() { + + $backend = $this->getBackend(); + + $lock = new DAV\Locks\LockInfo(); + $lock->owner = 'Sinterklaas'; + $lock->timeout = 60; + $lock->created = time(); + $lock->depth = DAV\Server::DEPTH_INFINITY; + $lock->token = 'MY-UNIQUE-TOKEN'; + + $this->assertTrue($backend->lock('someuri', $lock)); + + $locks = $backend->getLocks('someuri/child', false); + + $this->assertEquals(1, count($locks)); + $this->assertEquals('Sinterklaas', $locks[0]->owner); + $this->assertEquals('someuri', $locks[0]->uri); + + } + + + /** + * @depends testGetLocks + */ + function testGetLocksParentDepth0() { + + $backend = $this->getBackend(); + + $lock = new DAV\Locks\LockInfo(); + $lock->owner = 'Sinterklaas'; + $lock->timeout = 60; + $lock->created = time(); + $lock->depth = 0; + $lock->token = 'MY-UNIQUE-TOKEN'; + + $this->assertTrue($backend->lock('someuri', $lock)); + + $locks = $backend->getLocks('someuri/child', false); + + $this->assertEquals(0, count($locks)); + + } + + function testGetLocksChildren() { + + $backend = $this->getBackend(); + + $lock = new DAV\Locks\LockInfo(); + $lock->owner = 'Sinterklaas'; + $lock->timeout = 60; + $lock->created = time(); + $lock->depth = 0; + $lock->token = 'MY-UNIQUE-TOKEN'; + + $this->assertTrue($backend->lock('someuri/child', $lock)); + + $locks = $backend->getLocks('someuri/child', false); + $this->assertEquals(1, count($locks)); + + $locks = $backend->getLocks('someuri', false); + $this->assertEquals(0, count($locks)); + + $locks = $backend->getLocks('someuri', true); + $this->assertEquals(1, count($locks)); + + } + + /** + * @depends testGetLocks + */ + function testLockRefresh() { + + $backend = $this->getBackend(); + + $lock = new DAV\Locks\LockInfo(); + $lock->owner = 'Sinterklaas'; + $lock->timeout = 60; + $lock->created = time(); + $lock->token = 'MY-UNIQUE-TOKEN'; + + $this->assertTrue($backend->lock('someuri', $lock)); + /* Second time */ + + $lock->owner = 'Santa Clause'; + $this->assertTrue($backend->lock('someuri', $lock)); + + $locks = $backend->getLocks('someuri', false); + + $this->assertEquals(1, count($locks)); + + $this->assertEquals('Santa Clause', $locks[0]->owner); + $this->assertEquals('someuri', $locks[0]->uri); + + } + + /** + * @depends testGetLocks + */ + function testUnlock() { + + $backend = $this->getBackend(); + + $lock = new DAV\Locks\LockInfo(); + $lock->owner = 'Sinterklaas'; + $lock->timeout = 60; + $lock->created = time(); + $lock->token = 'MY-UNIQUE-TOKEN'; + + $this->assertTrue($backend->lock('someuri', $lock)); + + $locks = $backend->getLocks('someuri', false); + $this->assertEquals(1, count($locks)); + + $this->assertTrue($backend->unlock('someuri', $lock)); + + $locks = $backend->getLocks('someuri', false); + $this->assertEquals(0, count($locks)); + + } + + /** + * @depends testUnlock + */ + function testUnlockUnknownToken() { + + $backend = $this->getBackend(); + + $lock = new DAV\Locks\LockInfo(); + $lock->owner = 'Sinterklaas'; + $lock->timeout = 60; + $lock->created = time(); + $lock->token = 'MY-UNIQUE-TOKEN'; + + $this->assertTrue($backend->lock('someuri', $lock)); + + $locks = $backend->getLocks('someuri', false); + $this->assertEquals(1, count($locks)); + + $lock->token = 'SOME-OTHER-TOKEN'; + $this->assertFalse($backend->unlock('someuri', $lock)); + + $locks = $backend->getLocks('someuri', false); + $this->assertEquals(1, count($locks)); + + } + +} diff --git a/vendor/sabre/dav/tests/Sabre/DAV/Locks/Backend/FileTest.php b/vendor/sabre/dav/tests/Sabre/DAV/Locks/Backend/FileTest.php new file mode 100644 index 000000000..537996f3b --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/DAV/Locks/Backend/FileTest.php @@ -0,0 +1,24 @@ +<?php + +namespace Sabre\DAV\Locks\Backend; + +require_once 'Sabre/TestUtil.php'; + +class FileTest extends AbstractTest { + + function getBackend() { + + \Sabre\TestUtil::clearTempDir(); + $backend = new File(SABRE_TEMPDIR . '/lockdb'); + return $backend; + + } + + + function tearDown() { + + \Sabre\TestUtil::clearTempDir(); + + } + +} diff --git a/vendor/sabre/dav/tests/Sabre/DAV/Locks/Backend/Mock.php b/vendor/sabre/dav/tests/Sabre/DAV/Locks/Backend/Mock.php new file mode 100644 index 000000000..dd4758071 --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/DAV/Locks/Backend/Mock.php @@ -0,0 +1,139 @@ +<?php + +namespace Sabre\DAV\Locks\Backend; + +use Sabre\DAV\Locks\LockInfo; + +/** + * Locks Mock backend. + * + * This backend stores lock information in memory. Mainly useful for testing. + * + * @copyright Copyright (C) fruux GmbH (https://fruux.com/) + * @author Evert Pot (http://evertpot.com/) + * @license http://sabre.io/license/ Modified BSD License + */ +class Mock extends AbstractBackend { + + /** + * Returns a list of Sabre\DAV\Locks\LockInfo objects + * + * This method should return all the locks for a particular uri, including + * locks that might be set on a parent uri. + * + * If returnChildLocks is set to true, this method should also look for + * any locks in the subtree of the uri for locks. + * + * @param string $uri + * @param bool $returnChildLocks + * @return array + */ + function getLocks($uri, $returnChildLocks) { + + $newLocks = []; + + $locks = $this->getData(); + + foreach ($locks as $lock) { + + if ($lock->uri === $uri || + //deep locks on parents + ($lock->depth != 0 && strpos($uri, $lock->uri . '/') === 0) || + + // locks on children + ($returnChildLocks && (strpos($lock->uri, $uri . '/') === 0))) { + + $newLocks[] = $lock; + + } + + } + + // Checking if we can remove any of these locks + foreach ($newLocks as $k => $lock) { + if (time() > $lock->timeout + $lock->created) unset($newLocks[$k]); + } + return $newLocks; + + } + + /** + * Locks a uri + * + * @param string $uri + * @param LockInfo $lockInfo + * @return bool + */ + function lock($uri, LockInfo $lockInfo) { + + // We're making the lock timeout 30 minutes + $lockInfo->timeout = 1800; + $lockInfo->created = time(); + $lockInfo->uri = $uri; + + $locks = $this->getData(); + + foreach ($locks as $k => $lock) { + if ( + ($lock->token == $lockInfo->token) || + (time() > $lock->timeout + $lock->created) + ) { + unset($locks[$k]); + } + } + $locks[] = $lockInfo; + $this->putData($locks); + return true; + + } + + /** + * Removes a lock from a uri + * + * @param string $uri + * @param LockInfo $lockInfo + * @return bool + */ + function unlock($uri, LockInfo $lockInfo) { + + $locks = $this->getData(); + foreach ($locks as $k => $lock) { + + if ($lock->token == $lockInfo->token) { + + unset($locks[$k]); + $this->putData($locks); + return true; + + } + } + return false; + + } + + protected $data = []; + + /** + * Loads the lockdata from the filesystem. + * + * @return array + */ + protected function getData() { + + return $this->data; + + } + + /** + * Saves the lockdata + * + * @param array $newData + * @return void + */ + protected function putData(array $newData) { + + $this->data = $newData; + + } + +} diff --git a/vendor/sabre/dav/tests/Sabre/DAV/Locks/Backend/PDOMySQLTest.php b/vendor/sabre/dav/tests/Sabre/DAV/Locks/Backend/PDOMySQLTest.php new file mode 100644 index 000000000..0ba02fc8b --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/DAV/Locks/Backend/PDOMySQLTest.php @@ -0,0 +1,9 @@ +<?php + +namespace Sabre\DAV\Locks\Backend; + +class PDOMySQLTest extends PDOTest { + + public $driver = 'mysql'; + +} diff --git a/vendor/sabre/dav/tests/Sabre/DAV/Locks/Backend/PDOPgSqlTest.php b/vendor/sabre/dav/tests/Sabre/DAV/Locks/Backend/PDOPgSqlTest.php new file mode 100644 index 000000000..39ee56419 --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/DAV/Locks/Backend/PDOPgSqlTest.php @@ -0,0 +1,9 @@ +<?php + +namespace Sabre\DAV\Locks\Backend; + +class PDOPgSqlTest extends PDOTest { + + public $driver = 'pgsql'; + +} diff --git a/vendor/sabre/dav/tests/Sabre/DAV/Locks/Backend/PDOSqliteTest.php b/vendor/sabre/dav/tests/Sabre/DAV/Locks/Backend/PDOSqliteTest.php new file mode 100644 index 000000000..4b126dcf3 --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/DAV/Locks/Backend/PDOSqliteTest.php @@ -0,0 +1,9 @@ +<?php + +namespace Sabre\DAV\Locks\Backend; + +class PDOSqliteTest extends PDOTest { + + public $driver = 'sqlite'; + +} diff --git a/vendor/sabre/dav/tests/Sabre/DAV/Locks/Backend/PDOTest.php b/vendor/sabre/dav/tests/Sabre/DAV/Locks/Backend/PDOTest.php new file mode 100644 index 000000000..a27eae93c --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/DAV/Locks/Backend/PDOTest.php @@ -0,0 +1,20 @@ +<?php + +namespace Sabre\DAV\Locks\Backend; + +abstract class PDOTest extends AbstractTest { + + use \Sabre\DAV\DbTestHelperTrait; + + function getBackend() { + + $this->dropTables('locks'); + $this->createSchema('locks'); + + $pdo = $this->getPDO(); + + return new PDO($pdo); + + } + +} diff --git a/vendor/sabre/dav/tests/Sabre/DAV/Locks/MSWordTest.php b/vendor/sabre/dav/tests/Sabre/DAV/Locks/MSWordTest.php new file mode 100644 index 000000000..1111db5b5 --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/DAV/Locks/MSWordTest.php @@ -0,0 +1,124 @@ +<?php + +namespace Sabre\DAV\Locks; + +use Sabre\DAV; +use Sabre\HTTP; + +require_once 'Sabre/HTTP/ResponseMock.php'; +require_once 'Sabre/TestUtil.php'; + +class MSWordTest extends \PHPUnit_Framework_TestCase { + + function tearDown() { + + \Sabre\TestUtil::clearTempDir(); + + } + + function testLockEtc() { + + mkdir(SABRE_TEMPDIR . '/mstest'); + $tree = new DAV\FS\Directory(SABRE_TEMPDIR . '/mstest'); + + $server = new DAV\Server($tree); + $server->debugExceptions = true; + $locksBackend = new Backend\File(SABRE_TEMPDIR . '/locksdb'); + $locksPlugin = new Plugin($locksBackend); + $server->addPlugin($locksPlugin); + + $response1 = new HTTP\ResponseMock(); + + $server->httpRequest = $this->getLockRequest(); + $server->httpResponse = $response1; + $server->sapi = new HTTP\SapiMock(); + $server->exec(); + + $this->assertEquals(201, $server->httpResponse->getStatus(), 'Full response body:' . $response1->getBodyAsString()); + $this->assertTrue(!!$server->httpResponse->getHeaders('Lock-Token')); + $lockToken = $server->httpResponse->getHeader('Lock-Token'); + + //sleep(10); + + $response2 = new HTTP\ResponseMock(); + + $server->httpRequest = $this->getLockRequest2(); + $server->httpResponse = $response2; + $server->exec(); + + $this->assertEquals(201, $server->httpResponse->status); + $this->assertTrue(!!$server->httpResponse->getHeaders('Lock-Token')); + + //sleep(10); + + $response3 = new HTTP\ResponseMock(); + $server->httpRequest = $this->getPutRequest($lockToken); + $server->httpResponse = $response3; + $server->exec(); + + $this->assertEquals(204, $server->httpResponse->status); + + } + + function getLockRequest() { + + $request = HTTP\Sapi::createFromServerArray([ + 'REQUEST_METHOD' => 'LOCK', + 'HTTP_CONTENT_TYPE' => 'application/xml', + 'HTTP_TIMEOUT' => 'Second-3600', + 'REQUEST_URI' => '/Nouveau%20Microsoft%20Office%20Excel%20Worksheet.xlsx', + ]); + + $request->setBody('<D:lockinfo xmlns:D="DAV:"> + <D:lockscope> + <D:exclusive /> + </D:lockscope> + <D:locktype> + <D:write /> + </D:locktype> + <D:owner> + <D:href>PC-Vista\User</D:href> + </D:owner> +</D:lockinfo>'); + + return $request; + + } + function getLockRequest2() { + + $request = HTTP\Sapi::createFromServerArray([ + 'REQUEST_METHOD' => 'LOCK', + 'HTTP_CONTENT_TYPE' => 'application/xml', + 'HTTP_TIMEOUT' => 'Second-3600', + 'REQUEST_URI' => '/~$Nouveau%20Microsoft%20Office%20Excel%20Worksheet.xlsx', + ]); + + $request->setBody('<D:lockinfo xmlns:D="DAV:"> + <D:lockscope> + <D:exclusive /> + </D:lockscope> + <D:locktype> + <D:write /> + </D:locktype> + <D:owner> + <D:href>PC-Vista\User</D:href> + </D:owner> +</D:lockinfo>'); + + return $request; + + } + + function getPutRequest($lockToken) { + + $request = HTTP\Sapi::createFromServerArray([ + 'REQUEST_METHOD' => 'PUT', + 'REQUEST_URI' => '/Nouveau%20Microsoft%20Office%20Excel%20Worksheet.xlsx', + 'HTTP_IF' => 'If: (' . $lockToken . ')', + ]); + $request->setBody('FAKE BODY'); + return $request; + + } + +} diff --git a/vendor/sabre/dav/tests/Sabre/DAV/Locks/Plugin2Test.php b/vendor/sabre/dav/tests/Sabre/DAV/Locks/Plugin2Test.php new file mode 100644 index 000000000..7af490795 --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/DAV/Locks/Plugin2Test.php @@ -0,0 +1,69 @@ +<?php + +namespace Sabre\DAV\Locks; + +use Sabre\HTTP\Request; + +class Plugin2Test extends \Sabre\DAVServerTest { + + public $setupLocks = true; + + function setUpTree() { + + $this->tree = new \Sabre\DAV\FS\Directory(SABRE_TEMPDIR); + + } + + function tearDown() { + + \Sabre\TestUtil::clearTempDir(); + + } + + /** + * This test first creates a file with LOCK and then deletes it. + * + * After deleting the file, the lock should no longer be in the lock + * backend. + * + * Reported in ticket #487 + */ + function testUnlockAfterDelete() { + + $body = '<?xml version="1.0"?> +<D:lockinfo xmlns:D="DAV:"> + <D:lockscope><D:exclusive/></D:lockscope> + <D:locktype><D:write/></D:locktype> +</D:lockinfo>'; + + $request = new Request( + 'LOCK', + '/file.txt', + [], + $body + ); + $response = $this->request($request); + $this->assertEquals(201, $response->getStatus(), $response->getBodyAsString()); + + $this->assertEquals( + 1, + count($this->locksBackend->getLocks('file.txt', true)) + ); + + $request = new Request( + 'DELETE', + '/file.txt', + [ + 'If' => '(' . $response->getHeader('Lock-Token') . ')', + ] + ); + $response = $this->request($request); + $this->assertEquals(204, $response->getStatus(), $response->getBodyAsString()); + + $this->assertEquals( + 0, + count($this->locksBackend->getLocks('file.txt', true)) + ); + } + +} diff --git a/vendor/sabre/dav/tests/Sabre/DAV/Locks/PluginTest.php b/vendor/sabre/dav/tests/Sabre/DAV/Locks/PluginTest.php new file mode 100644 index 000000000..dbbf6757a --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/DAV/Locks/PluginTest.php @@ -0,0 +1,1003 @@ +<?php + +namespace Sabre\DAV\Locks; + +use Sabre\DAV; +use Sabre\HTTP; + +require_once 'Sabre/DAV/AbstractServer.php'; + +class PluginTest extends DAV\AbstractServer { + + /** + * @var Plugin + */ + protected $locksPlugin; + + function setUp() { + + parent::setUp(); + $locksBackend = new Backend\File(SABRE_TEMPDIR . '/locksdb'); + $locksPlugin = new Plugin($locksBackend); + $this->server->addPlugin($locksPlugin); + $this->locksPlugin = $locksPlugin; + + } + + function testGetInfo() { + + $this->assertArrayHasKey( + 'name', + $this->locksPlugin->getPluginInfo() + ); + + } + + function testGetFeatures() { + + $this->assertEquals([2], $this->locksPlugin->getFeatures()); + + } + + function testGetHTTPMethods() { + + $this->assertEquals(['LOCK', 'UNLOCK'], $this->locksPlugin->getHTTPMethods('')); + + } + + function testLockNoBody() { + + $request = new HTTP\Request('LOCK', '/test.txt'); + $this->server->httpRequest = $request; + $this->server->exec(); + + $this->assertEquals([ + 'X-Sabre-Version' => [DAV\Version::VERSION], + 'Content-Type' => ['application/xml; charset=utf-8'], + ], + $this->response->getHeaders() + ); + + $this->assertEquals(400, $this->response->status); + + } + + function testLock() { + + $request = new HTTP\Request('LOCK', '/test.txt'); + $request->setBody('<?xml version="1.0"?> +<D:lockinfo xmlns:D="DAV:"> + <D:lockscope><D:exclusive/></D:lockscope> + <D:locktype><D:write/></D:locktype> + <D:owner> + <D:href>http://example.org/~ejw/contact.html</D:href> + </D:owner> +</D:lockinfo>'); + + $this->server->httpRequest = $request; + $this->server->exec(); + + $this->assertEquals('application/xml; charset=utf-8', $this->response->getHeader('Content-Type')); + $this->assertTrue(preg_match('/^<opaquelocktoken:(.*)>$/', $this->response->getHeader('Lock-Token')) === 1, 'We did not get a valid Locktoken back (' . $this->response->getHeader('Lock-Token') . ')'); + + $this->assertEquals(200, $this->response->status, 'Got an incorrect status back. Response body: ' . $this->response->body); + + $body = preg_replace("/xmlns(:[A-Za-z0-9_])?=(\"|\')DAV:(\"|\')/", "xmlns\\1=\"urn:DAV\"", $this->response->body); + $xml = simplexml_load_string($body); + $xml->registerXPathNamespace('d', 'urn:DAV'); + + $elements = [ + '/d:prop', + '/d:prop/d:lockdiscovery', + '/d:prop/d:lockdiscovery/d:activelock', + '/d:prop/d:lockdiscovery/d:activelock/d:locktype', + '/d:prop/d:lockdiscovery/d:activelock/d:lockroot', + '/d:prop/d:lockdiscovery/d:activelock/d:lockroot/d:href', + '/d:prop/d:lockdiscovery/d:activelock/d:locktype/d:write', + '/d:prop/d:lockdiscovery/d:activelock/d:lockscope', + '/d:prop/d:lockdiscovery/d:activelock/d:lockscope/d:exclusive', + '/d:prop/d:lockdiscovery/d:activelock/d:depth', + '/d:prop/d:lockdiscovery/d:activelock/d:owner', + '/d:prop/d:lockdiscovery/d:activelock/d:timeout', + '/d:prop/d:lockdiscovery/d:activelock/d:locktoken', + '/d:prop/d:lockdiscovery/d:activelock/d:locktoken/d:href', + ]; + + foreach ($elements as $elem) { + $data = $xml->xpath($elem); + $this->assertEquals(1, count($data), 'We expected 1 match for the xpath expression "' . $elem . '". ' . count($data) . ' were found. Full response body: ' . $this->response->body); + } + + $depth = $xml->xpath('/d:prop/d:lockdiscovery/d:activelock/d:depth'); + $this->assertEquals('infinity', (string)$depth[0]); + + $token = $xml->xpath('/d:prop/d:lockdiscovery/d:activelock/d:locktoken/d:href'); + $this->assertEquals($this->response->getHeader('Lock-Token'), '<' . (string)$token[0] . '>', 'Token in response body didn\'t match token in response header.'); + + } + + /** + * @depends testLock + */ + function testDoubleLock() { + + $request = new HTTP\Request('LOCK', '/test.txt'); + $request->setBody('<?xml version="1.0"?> +<D:lockinfo xmlns:D="DAV:"> + <D:lockscope><D:exclusive/></D:lockscope> + <D:locktype><D:write/></D:locktype> + <D:owner> + <D:href>http://example.org/~ejw/contact.html</D:href> + </D:owner> +</D:lockinfo>'); + + $this->server->httpRequest = $request; + $this->server->exec(); + + $this->response = new HTTP\ResponseMock(); + $this->server->httpResponse = $this->response; + + $this->server->exec(); + + $this->assertEquals('application/xml; charset=utf-8', $this->response->getHeader('Content-Type')); + + $this->assertEquals(423, $this->response->status, 'Full response: ' . $this->response->body); + + } + + /** + * @depends testLock + */ + function testLockRefresh() { + + $request = new HTTP\Request('LOCK', '/test.txt'); + $request->setBody('<?xml version="1.0"?> +<D:lockinfo xmlns:D="DAV:"> + <D:lockscope><D:exclusive/></D:lockscope> + <D:locktype><D:write/></D:locktype> + <D:owner> + <D:href>http://example.org/~ejw/contact.html</D:href> + </D:owner> +</D:lockinfo>'); + + $this->server->httpRequest = $request; + $this->server->exec(); + + $lockToken = $this->response->getHeader('Lock-Token'); + + $this->response = new HTTP\ResponseMock(); + $this->server->httpResponse = $this->response; + + $request = new HTTP\Request('LOCK', '/test.txt', ['If' => '(' . $lockToken . ')']); + $request->setBody(''); + + $this->server->httpRequest = $request; + $this->server->exec(); + + $this->assertEquals('application/xml; charset=utf-8', $this->response->getHeader('Content-Type')); + + $this->assertEquals(200, $this->response->status, 'We received an incorrect status code. Full response body: ' . $this->response->getBody()); + + } + + /** + * @depends testLock + */ + function testLockRefreshBadToken() { + + $request = new HTTP\Request('LOCK', '/test.txt'); + $request->setBody('<?xml version="1.0"?> +<D:lockinfo xmlns:D="DAV:"> + <D:lockscope><D:exclusive/></D:lockscope> + <D:locktype><D:write/></D:locktype> + <D:owner> + <D:href>http://example.org/~ejw/contact.html</D:href> + </D:owner> +</D:lockinfo>'); + + $this->server->httpRequest = $request; + $this->server->exec(); + + $lockToken = $this->response->getHeader('Lock-Token'); + + $this->response = new HTTP\ResponseMock(); + $this->server->httpResponse = $this->response; + + $request = new HTTP\Request('LOCK', '/test.txt', ['If' => '(' . $lockToken . 'foobar) (<opaquelocktoken:anotherbadtoken>)']); + $request->setBody(''); + + $this->server->httpRequest = $request; + $this->server->exec(); + + $this->assertEquals('application/xml; charset=utf-8', $this->response->getHeader('Content-Type')); + + $this->assertEquals(423, $this->response->getStatus(), 'We received an incorrect status code. Full response body: ' . $this->response->getBody()); + + } + + /** + * @depends testLock + */ + function testLockNoFile() { + + $request = new HTTP\Request('LOCK', '/notfound.txt'); + $request->setBody('<?xml version="1.0"?> +<D:lockinfo xmlns:D="DAV:"> + <D:lockscope><D:exclusive/></D:lockscope> + <D:locktype><D:write/></D:locktype> + <D:owner> + <D:href>http://example.org/~ejw/contact.html</D:href> + </D:owner> +</D:lockinfo>'); + + $this->server->httpRequest = $request; + $this->server->exec(); + + $this->assertEquals('application/xml; charset=utf-8', $this->response->getHeader('Content-Type')); + $this->assertTrue(preg_match('/^<opaquelocktoken:(.*)>$/', $this->response->getHeader('Lock-Token')) === 1, 'We did not get a valid Locktoken back (' . $this->response->getHeader('Lock-Token') . ')'); + + $this->assertEquals(201, $this->response->status); + + } + + /** + * @depends testLock + */ + function testUnlockNoToken() { + + $request = new HTTP\Request('UNLOCK', '/test.txt'); + $this->server->httpRequest = $request; + $this->server->exec(); + + $this->assertEquals([ + 'X-Sabre-Version' => [DAV\Version::VERSION], + 'Content-Type' => ['application/xml; charset=utf-8'], + ], + $this->response->getHeaders() + ); + + $this->assertEquals(400, $this->response->status); + + } + + /** + * @depends testLock + */ + function testUnlockBadToken() { + + $request = new HTTP\Request('UNLOCK', '/test.txt', ['Lock-Token' => '<opaquelocktoken:blablabla>']); + $this->server->httpRequest = $request; + $this->server->exec(); + + $this->assertEquals([ + 'X-Sabre-Version' => [DAV\Version::VERSION], + 'Content-Type' => ['application/xml; charset=utf-8'], + ], + $this->response->getHeaders() + ); + + $this->assertEquals(409, $this->response->status, 'Got an incorrect status code. Full response body: ' . $this->response->body); + + } + + /** + * @depends testLock + */ + function testLockPutNoToken() { + + $request = new HTTP\Request('LOCK', '/test.txt'); + $request->setBody('<?xml version="1.0"?> +<D:lockinfo xmlns:D="DAV:"> + <D:lockscope><D:exclusive/></D:lockscope> + <D:locktype><D:write/></D:locktype> + <D:owner> + <D:href>http://example.org/~ejw/contact.html</D:href> + </D:owner> +</D:lockinfo>'); + + $this->server->httpRequest = $request; + $this->server->exec(); + + $this->assertEquals('application/xml; charset=utf-8', $this->response->getHeader('Content-Type')); + $this->assertTrue(preg_match('/^<opaquelocktoken:(.*)>$/', $this->response->getHeader('Lock-Token')) === 1, 'We did not get a valid Locktoken back (' . $this->response->getHeader('Lock-Token') . ')'); + + $this->assertEquals(200, $this->response->status); + + $request = new HTTP\Request('PUT', '/test.txt'); + $request->setBody('newbody'); + $this->server->httpRequest = $request; + $this->server->exec(); + + $this->assertEquals('application/xml; charset=utf-8', $this->response->getHeader('Content-Type')); + $this->assertTrue(preg_match('/^<opaquelocktoken:(.*)>$/', $this->response->getHeader('Lock-Token')) === 1, 'We did not get a valid Locktoken back (' . $this->response->getHeader('Lock-Token') . ')'); + + $this->assertEquals(423, $this->response->status); + + } + + /** + * @depends testLock + */ + function testUnlock() { + + $request = new HTTP\Request('LOCK', '/test.txt'); + $this->server->httpRequest = $request; + + $request->setBody('<?xml version="1.0"?> +<D:lockinfo xmlns:D="DAV:"> + <D:lockscope><D:exclusive/></D:lockscope> + <D:locktype><D:write/></D:locktype> + <D:owner> + <D:href>http://example.org/~ejw/contact.html</D:href> + </D:owner> +</D:lockinfo>'); + + $this->server->invokeMethod($request, $this->server->httpResponse); + $lockToken = $this->server->httpResponse->getHeader('Lock-Token'); + + $request = new HTTP\Request('UNLOCK', '/test.txt', ['Lock-Token' => $lockToken]); + $this->server->httpRequest = $request; + $this->server->httpResponse = new HTTP\ResponseMock(); + $this->server->invokeMethod($request, $this->server->httpResponse); + + $this->assertEquals(204, $this->server->httpResponse->status, 'Got an incorrect status code. Full response body: ' . $this->response->body); + $this->assertEquals([ + 'X-Sabre-Version' => [DAV\Version::VERSION], + 'Content-Length' => ['0'], + ], + $this->server->httpResponse->getHeaders() + ); + + + } + + /** + * @depends testLock + */ + function testUnlockWindowsBug() { + + $request = new HTTP\Request('LOCK', '/test.txt'); + $this->server->httpRequest = $request; + + $request->setBody('<?xml version="1.0"?> +<D:lockinfo xmlns:D="DAV:"> + <D:lockscope><D:exclusive/></D:lockscope> + <D:locktype><D:write/></D:locktype> + <D:owner> + <D:href>http://example.org/~ejw/contact.html</D:href> + </D:owner> +</D:lockinfo>'); + + $this->server->invokeMethod($request, $this->server->httpResponse); + $lockToken = $this->server->httpResponse->getHeader('Lock-Token'); + + // See Issue 123 + $lockToken = trim($lockToken, '<>'); + + $request = new HTTP\Request('UNLOCK', '/test.txt', ['Lock-Token' => $lockToken]); + $this->server->httpRequest = $request; + $this->server->httpResponse = new HTTP\ResponseMock(); + $this->server->invokeMethod($request, $this->server->httpResponse); + + $this->assertEquals(204, $this->server->httpResponse->status, 'Got an incorrect status code. Full response body: ' . $this->response->body); + $this->assertEquals([ + 'X-Sabre-Version' => [DAV\Version::VERSION], + 'Content-Length' => ['0'], + ], + $this->server->httpResponse->getHeaders() + ); + + + } + + /** + * @depends testLock + */ + function testLockRetainOwner() { + + $request = HTTP\Sapi::createFromServerArray([ + 'REQUEST_URI' => '/test.txt', + 'REQUEST_METHOD' => 'LOCK', + ]); + $this->server->httpRequest = $request; + + $request->setBody('<?xml version="1.0"?> +<D:lockinfo xmlns:D="DAV:"> + <D:lockscope><D:exclusive/></D:lockscope> + <D:locktype><D:write/></D:locktype> + <D:owner>Evert</D:owner> +</D:lockinfo>'); + + $this->server->invokeMethod($request, $this->server->httpResponse); + $lockToken = $this->server->httpResponse->getHeader('Lock-Token'); + + $locks = $this->locksPlugin->getLocks('test.txt'); + $this->assertEquals(1, count($locks)); + $this->assertEquals('Evert', $locks[0]->owner); + + + } + + /** + * @depends testLock + */ + function testLockPutBadToken() { + + $serverVars = [ + 'REQUEST_URI' => '/test.txt', + 'REQUEST_METHOD' => 'LOCK', + ]; + + $request = HTTP\Sapi::createFromServerArray($serverVars); + $request->setBody('<?xml version="1.0"?> +<D:lockinfo xmlns:D="DAV:"> + <D:lockscope><D:exclusive/></D:lockscope> + <D:locktype><D:write/></D:locktype> + <D:owner> + <D:href>http://example.org/~ejw/contact.html</D:href> + </D:owner> +</D:lockinfo>'); + + $this->server->httpRequest = $request; + $this->server->exec(); + + $this->assertEquals('application/xml; charset=utf-8', $this->response->getHeader('Content-Type')); + $this->assertTrue(preg_match('/^<opaquelocktoken:(.*)>$/', $this->response->getHeader('Lock-Token')) === 1, 'We did not get a valid Locktoken back (' . $this->response->getHeader('Lock-Token') . ')'); + + $this->assertEquals(200, $this->response->status); + + $serverVars = [ + 'REQUEST_URI' => '/test.txt', + 'REQUEST_METHOD' => 'PUT', + 'HTTP_IF' => '(<opaquelocktoken:token1>)', + ]; + + $request = HTTP\Sapi::createFromServerArray($serverVars); + $request->setBody('newbody'); + $this->server->httpRequest = $request; + $this->server->exec(); + + $this->assertEquals('application/xml; charset=utf-8', $this->response->getHeader('Content-Type')); + $this->assertTrue(preg_match('/^<opaquelocktoken:(.*)>$/', $this->response->getHeader('Lock-Token')) === 1, 'We did not get a valid Locktoken back (' . $this->response->getHeader('Lock-Token') . ')'); + + // $this->assertEquals('412 Precondition failed',$this->response->status); + $this->assertEquals(423, $this->response->status); + + } + + /** + * @depends testLock + */ + function testLockDeleteParent() { + + $serverVars = [ + 'REQUEST_URI' => '/dir/child.txt', + 'REQUEST_METHOD' => 'LOCK', + ]; + + $request = HTTP\Sapi::createFromServerArray($serverVars); + $request->setBody('<?xml version="1.0"?> +<D:lockinfo xmlns:D="DAV:"> + <D:lockscope><D:exclusive/></D:lockscope> + <D:locktype><D:write/></D:locktype> + <D:owner> + <D:href>http://example.org/~ejw/contact.html</D:href> + </D:owner> +</D:lockinfo>'); + + $this->server->httpRequest = $request; + $this->server->exec(); + + $this->assertEquals('application/xml; charset=utf-8', $this->response->getHeader('Content-Type')); + $this->assertTrue(preg_match('/^<opaquelocktoken:(.*)>$/', $this->response->getHeader('Lock-Token')) === 1, 'We did not get a valid Locktoken back (' . $this->response->getHeader('Lock-Token') . ')'); + + $this->assertEquals(200, $this->response->status); + + $serverVars = [ + 'REQUEST_URI' => '/dir', + 'REQUEST_METHOD' => 'DELETE', + ]; + + $request = HTTP\Sapi::createFromServerArray($serverVars); + $this->server->httpRequest = $request; + $this->server->exec(); + + $this->assertEquals(423, $this->response->status); + $this->assertEquals('application/xml; charset=utf-8', $this->response->getHeader('Content-Type')); + + } + /** + * @depends testLock + */ + function testLockDeleteSucceed() { + + $serverVars = [ + 'REQUEST_URI' => '/dir/child.txt', + 'REQUEST_METHOD' => 'LOCK', + ]; + + $request = HTTP\Sapi::createFromServerArray($serverVars); + $request->setBody('<?xml version="1.0"?> +<D:lockinfo xmlns:D="DAV:"> + <D:lockscope><D:exclusive/></D:lockscope> + <D:locktype><D:write/></D:locktype> + <D:owner> + <D:href>http://example.org/~ejw/contact.html</D:href> + </D:owner> +</D:lockinfo>'); + + $this->server->httpRequest = $request; + $this->server->exec(); + + $this->assertEquals('application/xml; charset=utf-8', $this->response->getHeader('Content-Type')); + $this->assertTrue(preg_match('/^<opaquelocktoken:(.*)>$/', $this->response->getHeader('Lock-Token')) === 1, 'We did not get a valid Locktoken back (' . $this->response->getHeader('Lock-Token') . ')'); + + $this->assertEquals(200, $this->response->status); + + $serverVars = [ + 'REQUEST_URI' => '/dir/child.txt', + 'REQUEST_METHOD' => 'DELETE', + 'HTTP_IF' => '(' . $this->response->getHeader('Lock-Token') . ')', + ]; + + $request = HTTP\Sapi::createFromServerArray($serverVars); + $this->server->httpRequest = $request; + $this->server->exec(); + + $this->assertEquals(204, $this->response->status); + $this->assertEquals('application/xml; charset=utf-8', $this->response->getHeader('Content-Type')); + + } + + /** + * @depends testLock + */ + function testLockCopyLockSource() { + + $serverVars = [ + 'REQUEST_URI' => '/dir/child.txt', + 'REQUEST_METHOD' => 'LOCK', + ]; + + $request = HTTP\Sapi::createFromServerArray($serverVars); + $request->setBody('<?xml version="1.0"?> +<D:lockinfo xmlns:D="DAV:"> + <D:lockscope><D:exclusive/></D:lockscope> + <D:locktype><D:write/></D:locktype> + <D:owner> + <D:href>http://example.org/~ejw/contact.html</D:href> + </D:owner> +</D:lockinfo>'); + + $this->server->httpRequest = $request; + $this->server->exec(); + + $this->assertEquals('application/xml; charset=utf-8', $this->response->getHeader('Content-Type')); + $this->assertTrue(preg_match('/^<opaquelocktoken:(.*)>$/', $this->response->getHeader('Lock-Token')) === 1, 'We did not get a valid Locktoken back (' . $this->response->getHeader('Lock-Token') . ')'); + + $this->assertEquals(200, $this->response->status); + + $serverVars = [ + 'REQUEST_URI' => '/dir/child.txt', + 'REQUEST_METHOD' => 'COPY', + 'HTTP_DESTINATION' => '/dir/child2.txt', + ]; + + $request = HTTP\Sapi::createFromServerArray($serverVars); + $this->server->httpRequest = $request; + $this->server->exec(); + + $this->assertEquals(201, $this->response->status, 'Copy must succeed if only the source is locked, but not the destination'); + $this->assertEquals('application/xml; charset=utf-8', $this->response->getHeader('Content-Type')); + + } + /** + * @depends testLock + */ + function testLockCopyLockDestination() { + + $serverVars = [ + 'REQUEST_URI' => '/dir/child2.txt', + 'REQUEST_METHOD' => 'LOCK', + ]; + + $request = HTTP\Sapi::createFromServerArray($serverVars); + $request->setBody('<?xml version="1.0"?> +<D:lockinfo xmlns:D="DAV:"> + <D:lockscope><D:exclusive/></D:lockscope> + <D:locktype><D:write/></D:locktype> + <D:owner> + <D:href>http://example.org/~ejw/contact.html</D:href> + </D:owner> +</D:lockinfo>'); + + $this->server->httpRequest = $request; + $this->server->exec(); + + $this->assertEquals('application/xml; charset=utf-8', $this->response->getHeader('Content-Type')); + $this->assertTrue(preg_match('/^<opaquelocktoken:(.*)>$/', $this->response->getHeader('Lock-Token')) === 1, 'We did not get a valid Locktoken back (' . $this->response->getHeader('Lock-Token') . ')'); + + $this->assertEquals(201, $this->response->status); + + $serverVars = [ + 'REQUEST_URI' => '/dir/child.txt', + 'REQUEST_METHOD' => 'COPY', + 'HTTP_DESTINATION' => '/dir/child2.txt', + ]; + + $request = HTTP\Sapi::createFromServerArray($serverVars); + $this->server->httpRequest = $request; + $this->server->exec(); + + $this->assertEquals(423, $this->response->status, 'Copy must succeed if only the source is locked, but not the destination'); + $this->assertEquals('application/xml; charset=utf-8', $this->response->getHeader('Content-Type')); + + } + + /** + * @depends testLock + */ + function testLockMoveLockSourceLocked() { + + $serverVars = [ + 'REQUEST_URI' => '/dir/child.txt', + 'REQUEST_METHOD' => 'LOCK', + ]; + + $request = HTTP\Sapi::createFromServerArray($serverVars); + $request->setBody('<?xml version="1.0"?> +<D:lockinfo xmlns:D="DAV:"> + <D:lockscope><D:exclusive/></D:lockscope> + <D:locktype><D:write/></D:locktype> + <D:owner> + <D:href>http://example.org/~ejw/contact.html</D:href> + </D:owner> +</D:lockinfo>'); + + $this->server->httpRequest = $request; + $this->server->exec(); + + $this->assertEquals('application/xml; charset=utf-8', $this->response->getHeader('Content-Type')); + $this->assertTrue(preg_match('/^<opaquelocktoken:(.*)>$/', $this->response->getHeader('Lock-Token')) === 1, 'We did not get a valid Locktoken back (' . $this->response->getHeader('Lock-Token') . ')'); + + $this->assertEquals(200, $this->response->status); + + $serverVars = [ + 'REQUEST_URI' => '/dir/child.txt', + 'REQUEST_METHOD' => 'MOVE', + 'HTTP_DESTINATION' => '/dir/child2.txt', + ]; + + $request = HTTP\Sapi::createFromServerArray($serverVars); + $this->server->httpRequest = $request; + $this->server->exec(); + + $this->assertEquals(423, $this->response->status, 'Copy must succeed if only the source is locked, but not the destination'); + $this->assertEquals('application/xml; charset=utf-8', $this->response->getHeader('Content-Type')); + + } + + /** + * @depends testLock + */ + function testLockMoveLockSourceSucceed() { + + $serverVars = [ + 'REQUEST_URI' => '/dir/child.txt', + 'REQUEST_METHOD' => 'LOCK', + ]; + + $request = HTTP\Sapi::createFromServerArray($serverVars); + $request->setBody('<?xml version="1.0"?> +<D:lockinfo xmlns:D="DAV:"> + <D:lockscope><D:exclusive/></D:lockscope> + <D:locktype><D:write/></D:locktype> + <D:owner> + <D:href>http://example.org/~ejw/contact.html</D:href> + </D:owner> +</D:lockinfo>'); + + $this->server->httpRequest = $request; + $this->server->exec(); + + $this->assertEquals('application/xml; charset=utf-8', $this->response->getHeader('Content-Type')); + $this->assertTrue(preg_match('/^<opaquelocktoken:(.*)>$/', $this->response->getHeader('Lock-Token')) === 1, 'We did not get a valid Locktoken back (' . $this->response->getHeader('Lock-Token') . ')'); + + $this->assertEquals(200, $this->response->status); + + $serverVars = [ + 'REQUEST_URI' => '/dir/child.txt', + 'REQUEST_METHOD' => 'MOVE', + 'HTTP_DESTINATION' => '/dir/child2.txt', + 'HTTP_IF' => '(' . $this->response->getHeader('Lock-Token') . ')', + ]; + + $request = HTTP\Sapi::createFromServerArray($serverVars); + $this->server->httpRequest = $request; + $this->server->exec(); + + $this->assertEquals(201, $this->response->status, 'A valid lock-token was provided for the source, so this MOVE operation must succeed. Full response body: ' . $this->response->body); + + } + + /** + * @depends testLock + */ + function testLockMoveLockDestination() { + + $serverVars = [ + 'REQUEST_URI' => '/dir/child2.txt', + 'REQUEST_METHOD' => 'LOCK', + ]; + + $request = HTTP\Sapi::createFromServerArray($serverVars); + $request->setBody('<?xml version="1.0"?> +<D:lockinfo xmlns:D="DAV:"> + <D:lockscope><D:exclusive/></D:lockscope> + <D:locktype><D:write/></D:locktype> + <D:owner> + <D:href>http://example.org/~ejw/contact.html</D:href> + </D:owner> +</D:lockinfo>'); + + $this->server->httpRequest = $request; + $this->server->exec(); + + $this->assertEquals('application/xml; charset=utf-8', $this->response->getHeader('Content-Type')); + $this->assertTrue(preg_match('/^<opaquelocktoken:(.*)>$/', $this->response->getHeader('Lock-Token')) === 1, 'We did not get a valid Locktoken back (' . $this->response->getHeader('Lock-Token') . ')'); + + $this->assertEquals(201, $this->response->status); + + $serverVars = [ + 'REQUEST_URI' => '/dir/child.txt', + 'REQUEST_METHOD' => 'MOVE', + 'HTTP_DESTINATION' => '/dir/child2.txt', + ]; + + $request = HTTP\Sapi::createFromServerArray($serverVars); + $this->server->httpRequest = $request; + $this->server->exec(); + + $this->assertEquals(423, $this->response->status, 'Copy must succeed if only the source is locked, but not the destination'); + $this->assertEquals('application/xml; charset=utf-8', $this->response->getHeader('Content-Type')); + + } + /** + * @depends testLock + */ + function testLockMoveLockParent() { + + $serverVars = [ + 'REQUEST_URI' => '/dir', + 'REQUEST_METHOD' => 'LOCK', + 'HTTP_DEPTH' => 'infinite', + ]; + + $request = HTTP\Sapi::createFromServerArray($serverVars); + $request->setBody('<?xml version="1.0"?> +<D:lockinfo xmlns:D="DAV:"> + <D:lockscope><D:exclusive/></D:lockscope> + <D:locktype><D:write/></D:locktype> + <D:owner> + <D:href>http://example.org/~ejw/contact.html</D:href> + </D:owner> +</D:lockinfo>'); + + $this->server->httpRequest = $request; + $this->server->exec(); + + $this->assertEquals('application/xml; charset=utf-8', $this->response->getHeader('Content-Type')); + $this->assertTrue(preg_match('/^<opaquelocktoken:(.*)>$/', $this->response->getHeader('Lock-Token')) === 1, 'We did not get a valid Locktoken back (' . $this->response->getHeader('Lock-Token') . ')'); + + $this->assertEquals(200, $this->response->status); + + $serverVars = [ + 'REQUEST_URI' => '/dir/child.txt', + 'REQUEST_METHOD' => 'MOVE', + 'HTTP_DESTINATION' => '/dir/child2.txt', + 'HTTP_IF' => '</dir> (' . $this->response->getHeader('Lock-Token') . ')', + ]; + + $request = HTTP\Sapi::createFromServerArray($serverVars); + $this->server->httpRequest = $request; + $this->server->exec(); + + $this->assertEquals(201, $this->response->status, 'We locked the parent of both the source and destination, but the move didn\'t succeed.'); + $this->assertEquals('application/xml; charset=utf-8', $this->response->getHeader('Content-Type')); + + } + + /** + * @depends testLock + */ + function testLockPutGoodToken() { + + $serverVars = [ + 'REQUEST_URI' => '/test.txt', + 'REQUEST_METHOD' => 'LOCK', + ]; + + $request = HTTP\Sapi::createFromServerArray($serverVars); + $request->setBody('<?xml version="1.0"?> +<D:lockinfo xmlns:D="DAV:"> + <D:lockscope><D:exclusive/></D:lockscope> + <D:locktype><D:write/></D:locktype> + <D:owner> + <D:href>http://example.org/~ejw/contact.html</D:href> + </D:owner> +</D:lockinfo>'); + + $this->server->httpRequest = $request; + $this->server->exec(); + + $this->assertEquals('application/xml; charset=utf-8', $this->response->getHeader('Content-Type')); + $this->assertTrue(preg_match('/^<opaquelocktoken:(.*)>$/', $this->response->getHeader('Lock-Token')) === 1, 'We did not get a valid Locktoken back (' . $this->response->getHeader('Lock-Token') . ')'); + + $this->assertEquals(200, $this->response->status); + + $serverVars = [ + 'REQUEST_URI' => '/test.txt', + 'REQUEST_METHOD' => 'PUT', + 'HTTP_IF' => '(' . $this->response->getHeader('Lock-Token') . ')', + ]; + + $request = HTTP\Sapi::createFromServerArray($serverVars); + $request->setBody('newbody'); + $this->server->httpRequest = $request; + $this->server->exec(); + + $this->assertEquals('application/xml; charset=utf-8', $this->response->getHeader('Content-Type')); + $this->assertTrue(preg_match('/^<opaquelocktoken:(.*)>$/', $this->response->getHeader('Lock-Token')) === 1, 'We did not get a valid Locktoken back (' . $this->response->getHeader('Lock-Token') . ')'); + + $this->assertEquals(204, $this->response->status); + + } + + /** + * @depends testLock + */ + function testLockPutUnrelatedToken() { + + $request = new HTTP\Request('LOCK', '/unrelated.txt'); + $request->setBody('<?xml version="1.0"?> +<D:lockinfo xmlns:D="DAV:"> + <D:lockscope><D:exclusive/></D:lockscope> + <D:locktype><D:write/></D:locktype> + <D:owner> + <D:href>http://example.org/~ejw/contact.html</D:href> + </D:owner> +</D:lockinfo>'); + + $this->server->httpRequest = $request; + $this->server->exec(); + + $this->assertEquals('application/xml; charset=utf-8', $this->response->getHeader('Content-Type')); + $this->assertTrue(preg_match('/^<opaquelocktoken:(.*)>$/', $this->response->getHeader('Lock-Token')) === 1, 'We did not get a valid Locktoken back (' . $this->response->getHeader('Lock-Token') . ')'); + + $this->assertEquals(201, $this->response->getStatus()); + + $request = new HTTP\Request( + 'PUT', + '/test.txt', + ['If' => '</unrelated.txt> (' . $this->response->getHeader('Lock-Token') . ')'] + ); + $request->setBody('newbody'); + $this->server->httpRequest = $request; + $this->server->exec(); + + $this->assertEquals('application/xml; charset=utf-8', $this->response->getHeader('Content-Type')); + $this->assertTrue(preg_match('/^<opaquelocktoken:(.*)>$/', $this->response->getHeader('Lock-Token')) === 1, 'We did not get a valid Locktoken back (' . $this->response->getHeader('Lock-Token') . ')'); + + $this->assertEquals(204, $this->response->status); + + } + + function testPutWithIncorrectETag() { + + $serverVars = [ + 'REQUEST_URI' => '/test.txt', + 'REQUEST_METHOD' => 'PUT', + 'HTTP_IF' => '(["etag1"])', + ]; + + $request = HTTP\Sapi::createFromServerArray($serverVars); + $request->setBody('newbody'); + $this->server->httpRequest = $request; + $this->server->exec(); + $this->assertEquals(412, $this->response->status); + + } + + /** + * @depends testPutWithIncorrectETag + */ + function testPutWithCorrectETag() { + + // We need an ETag-enabled file node. + $tree = new DAV\Tree(new DAV\FSExt\Directory(SABRE_TEMPDIR)); + $this->server->tree = $tree; + + $filename = SABRE_TEMPDIR . '/test.txt'; + $etag = sha1( + fileinode($filename) . + filesize($filename) . + filemtime($filename) + ); + $serverVars = [ + 'REQUEST_URI' => '/test.txt', + 'REQUEST_METHOD' => 'PUT', + 'HTTP_IF' => '(["' . $etag . '"])', + ]; + + $request = HTTP\Sapi::createFromServerArray($serverVars); + $request->setBody('newbody'); + $this->server->httpRequest = $request; + $this->server->exec(); + $this->assertEquals(204, $this->response->status, 'Incorrect status received. Full response body:' . $this->response->body); + + } + + function testDeleteWithETagOnCollection() { + + $serverVars = [ + 'REQUEST_URI' => '/dir', + 'REQUEST_METHOD' => 'DELETE', + 'HTTP_IF' => '(["etag1"])', + ]; + $request = HTTP\Sapi::createFromServerArray($serverVars); + + $this->server->httpRequest = $request; + $this->server->exec(); + $this->assertEquals(412, $this->response->status); + + } + + function testGetTimeoutHeader() { + + $request = HTTP\Sapi::createFromServerArray([ + 'HTTP_TIMEOUT' => 'second-100', + ]); + + $this->server->httpRequest = $request; + $this->assertEquals(100, $this->locksPlugin->getTimeoutHeader()); + + } + + function testGetTimeoutHeaderTwoItems() { + + $request = HTTP\Sapi::createFromServerArray([ + 'HTTP_TIMEOUT' => 'second-5, infinite', + ]); + + $this->server->httpRequest = $request; + $this->assertEquals(5, $this->locksPlugin->getTimeoutHeader()); + + } + + function testGetTimeoutHeaderInfinite() { + + $request = HTTP\Sapi::createFromServerArray([ + 'HTTP_TIMEOUT' => 'infinite, second-5', + ]); + + $this->server->httpRequest = $request; + $this->assertEquals(LockInfo::TIMEOUT_INFINITE, $this->locksPlugin->getTimeoutHeader()); + + } + + /** + * @expectedException Sabre\DAV\Exception\BadRequest + */ + function testGetTimeoutHeaderInvalid() { + + $request = HTTP\Sapi::createFromServerArray([ + 'HTTP_TIMEOUT' => 'yourmom', + ]); + + $this->server->httpRequest = $request; + $this->locksPlugin->getTimeoutHeader(); + + } + + +} diff --git a/vendor/sabre/dav/tests/Sabre/DAV/Mock/Collection.php b/vendor/sabre/dav/tests/Sabre/DAV/Mock/Collection.php new file mode 100644 index 000000000..fded5e474 --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/DAV/Mock/Collection.php @@ -0,0 +1,168 @@ +<?php + +namespace Sabre\DAV\Mock; + +use Sabre\DAV; + +/** + * Mock Collection. + * + * This collection quickly allows you to create trees of nodes. + * Children are specified as an array. + * + * Every key a filename, every array value is either: + * * an array, for a sub-collection + * * a string, for a file + * * An instance of \Sabre\DAV\INode. + * + * @copyright Copyright (C) fruux GmbH (https://fruux.com/) + * @author Evert Pot (http://evertpot.com/) + * @license http://sabre.io/license/ Modified BSD License + */ +class Collection extends DAV\Collection { + + protected $name; + protected $children; + protected $parent; + + /** + * Creates the object + * + * @param string $name + * @param array $children + * @param Collection $parent + * @return void + */ + function __construct($name, array $children = [], Collection $parent = null) { + + $this->name = $name; + foreach ($children as $key => $value) { + if (is_string($value)) { + $this->children[] = new File($key, $value, $this); + } elseif (is_array($value)) { + $this->children[] = new self($key, $value, $this); + } elseif ($value instanceof \Sabre\DAV\INode) { + $this->children[] = $value; + } else { + throw new \InvalidArgumentException('Unknown value passed in $children'); + } + } + $this->parent = $parent; + + } + + /** + * Returns the name of the node. + * + * This is used to generate the url. + * + * @return string + */ + function getName() { + + return $this->name; + + } + + /** + * Creates a new file in the directory + * + * Data will either be supplied as a stream resource, or in certain cases + * as a string. Keep in mind that you may have to support either. + * + * After successful creation of the file, you may choose to return the ETag + * of the new file here. + * + * The returned ETag must be surrounded by double-quotes (The quotes should + * be part of the actual string). + * + * If you cannot accurately determine the ETag, you should not return it. + * If you don't store the file exactly as-is (you're transforming it + * somehow) you should also not return an ETag. + * + * This means that if a subsequent GET to this new file does not exactly + * return the same contents of what was submitted here, you are strongly + * recommended to omit the ETag. + * + * @param string $name Name of the file + * @param resource|string $data Initial payload + * @return null|string + */ + function createFile($name, $data = null) { + + if (is_resource($data)) { + $data = stream_get_contents($data); + } + $this->children[] = new File($name, $data, $this); + return '"' . md5($data) . '"'; + + } + + /** + * Creates a new subdirectory + * + * @param string $name + * @return void + */ + function createDirectory($name) { + + $this->children[] = new self($name); + + } + + /** + * Returns an array with all the child nodes + * + * @return \Sabre\DAV\INode[] + */ + function getChildren() { + + return $this->children; + + } + + /** + * Adds an already existing node to this collection. + * + * @param \Sabre\DAV\INode $node + */ + function addNode(\Sabre\DAV\INode $node) { + + $this->children[] = $node; + + } + + /** + * Removes a childnode from this node. + * + * @param string $name + * @return void + */ + function deleteChild($name) { + + foreach ($this->children as $key => $value) { + + if ($value->getName() == $name) { + unset($this->children[$key]); + return; + } + + } + + } + + /** + * Deletes this collection and all its children,. + * + * @return void + */ + function delete() { + + foreach ($this->getChildren() as $child) { + $this->deleteChild($child->getName()); + } + $this->parent->deleteChild($this->getName()); + + } + +} diff --git a/vendor/sabre/dav/tests/Sabre/DAV/Mock/File.php b/vendor/sabre/dav/tests/Sabre/DAV/Mock/File.php new file mode 100644 index 000000000..a624b6b6b --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/DAV/Mock/File.php @@ -0,0 +1,163 @@ +<?php + +namespace Sabre\DAV\Mock; + +use Sabre\DAV; + +/** + * Mock File + * + * See the Collection in this directory for more details. + * + * @copyright Copyright (C) fruux GmbH (https://fruux.com/) + * @author Evert Pot (http://evertpot.com/) + * @license http://sabre.io/license/ Modified BSD License + */ +class File extends DAV\File { + + protected $name; + protected $contents; + protected $parent; + protected $lastModified; + + /** + * Creates the object + * + * @param string $name + * @param resource $contents + * @param Collection $parent + * @param int $lastModified + * @return void + */ + function __construct($name, $contents, Collection $parent = null, $lastModified = -1) { + + $this->name = $name; + $this->put($contents); + $this->parent = $parent; + + if ($lastModified === -1) { + $lastModified = time(); + } + + $this->lastModified = $lastModified; + + } + + /** + * Returns the name of the node. + * + * This is used to generate the url. + * + * @return string + */ + function getName() { + + return $this->name; + + } + + /** + * Changes the name of the node. + * + * @param string $name + * @return void + */ + function setName($name) { + + $this->name = $name; + + } + + /** + * Updates the data + * + * The data argument is a readable stream resource. + * + * After a successful put operation, you may choose to return an ETag. The + * etag must always be surrounded by double-quotes. These quotes must + * appear in the actual string you're returning. + * + * Clients may use the ETag from a PUT request to later on make sure that + * when they update the file, the contents haven't changed in the mean + * time. + * + * If you don't plan to store the file byte-by-byte, and you return a + * different object on a subsequent GET you are strongly recommended to not + * return an ETag, and just return null. + * + * @param resource $data + * @return string|null + */ + function put($data) { + + if (is_resource($data)) { + $data = stream_get_contents($data); + } + $this->contents = $data; + return '"' . md5($data) . '"'; + + } + + /** + * Returns the data + * + * This method may either return a string or a readable stream resource + * + * @return mixed + */ + function get() { + + return $this->contents; + + } + + /** + * Returns the ETag for a file + * + * An ETag is a unique identifier representing the current version of the file. If the file changes, the ETag MUST change. + * + * Return null if the ETag can not effectively be determined + * + * @return void + */ + function getETag() { + + return '"' . md5($this->contents) . '"'; + + } + + /** + * Returns the size of the node, in bytes + * + * @return int + */ + function getSize() { + + return strlen($this->contents); + + } + + /** + * Delete the node + * + * @return void + */ + function delete() { + + $this->parent->deleteChild($this->name); + + } + + /** + * Returns the last modification time as a unix timestamp. + * If the information is not available, return null. + * + * @return int + */ + function getLastModified() { + + return $this->lastModified; + + } + +} diff --git a/vendor/sabre/dav/tests/Sabre/DAV/Mock/PropertiesCollection.php b/vendor/sabre/dav/tests/Sabre/DAV/Mock/PropertiesCollection.php new file mode 100644 index 000000000..af3fd2d3f --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/DAV/Mock/PropertiesCollection.php @@ -0,0 +1,94 @@ +<?php + +namespace Sabre\DAV\Mock; + +use Sabre\DAV\IProperties; +use Sabre\DAV\PropPatch; + +/** + * A node specifically for testing property-related operations + * + * @copyright Copyright (C) fruux GmbH (https://fruux.com/) + * @author Evert Pot (http://evertpot.com/) + * @license http://sabre.io/license/ Modified BSD License + */ +class PropertiesCollection extends Collection implements IProperties { + + public $failMode = false; + + public $properties; + + /** + * Creates the object + * + * @param string $name + * @param array $children + * @param array $properties + * @return void + */ + function __construct($name, array $children, array $properties = []) { + + parent::__construct($name, $children, null); + $this->properties = $properties; + + } + + /** + * Updates properties on this node. + * + * This method received a PropPatch object, which contains all the + * information about the update. + * + * To update specific properties, call the 'handle' method on this object. + * Read the PropPatch documentation for more information. + * + * @param PropPatch $proppatch + * @return bool|array + */ + function propPatch(PropPatch $proppatch) { + + $proppatch->handleRemaining(function($updateProperties) { + + switch ($this->failMode) { + case 'updatepropsfalse' : return false; + case 'updatepropsarray' : + $r = []; + foreach ($updateProperties as $k => $v) $r[$k] = 402; + return $r; + case 'updatepropsobj' : + return new \STDClass(); + } + + }); + + } + + /** + * Returns a list of properties for this nodes. + * + * The properties list is a list of propertynames the client requested, + * encoded in clark-notation {xmlnamespace}tagname + * + * If the array is empty, it means 'all properties' were requested. + * + * Note that it's fine to liberally give properties back, instead of + * conforming to the list of requested properties. + * The Server class will filter out the extra. + * + * @param array $requestedProperties + * @return array + */ + function getProperties($requestedProperties) { + + $returnedProperties = []; + foreach ($requestedProperties as $requestedProperty) { + if (isset($this->properties[$requestedProperty])) { + $returnedProperties[$requestedProperty] = + $this->properties[$requestedProperty]; + } + } + return $returnedProperties; + + } + +} diff --git a/vendor/sabre/dav/tests/Sabre/DAV/Mock/SharedNode.php b/vendor/sabre/dav/tests/Sabre/DAV/Mock/SharedNode.php new file mode 100644 index 000000000..503d64070 --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/DAV/Mock/SharedNode.php @@ -0,0 +1,125 @@ +<?php + +namespace Sabre\DAV\Mock; + +use Sabre\DAV\Sharing\ISharedNode; +use Sabre\DAV\Sharing\Sharee; + +class SharedNode extends \Sabre\DAV\Node implements ISharedNode { + + protected $name; + protected $access; + protected $invites = []; + + function __construct($name, $access) { + + $this->name = $name; + $this->access = $access; + + } + + function getName() { + + return $this->name; + + } + + /** + * Returns the 'access level' for the instance of this shared resource. + * + * The value should be one of the Sabre\DAV\Sharing\Plugin::ACCESS_ + * constants. + * + * @return int + */ + function getShareAccess() { + + return $this->access; + + } + + /** + * This function must return a URI that uniquely identifies the shared + * resource. This URI should be identical across instances, and is + * also used in several other XML bodies to connect invites to + * resources. + * + * This may simply be a relative reference to the original shared instance, + * but it could also be a urn. As long as it's a valid URI and unique. + * + * @return string + */ + function getShareResourceUri() { + + return 'urn:example:bar'; + + } + + /** + * Updates the list of sharees. + * + * Every item must be a Sharee object. + * + * @param Sharee[] $sharees + * @return void + */ + function updateInvites(array $sharees) { + + foreach ($sharees as $sharee) { + + if ($sharee->access === \Sabre\DAV\Sharing\Plugin::ACCESS_NOACCESS) { + // Removal + foreach ($this->invites as $k => $invitee) { + + if ($invitee->href = $sharee->href) { + unset($this->invites[$k]); + } + + } + + } else { + foreach ($this->invites as $k => $invitee) { + + if ($invitee->href = $sharee->href) { + if (!$sharee->inviteStatus) { + $sharee->inviteStatus = $invitee->inviteStatus; + } + // Overwriting an existing invitee + $this->invites[$k] = $sharee; + continue 2; + } + + } + if (!$sharee->inviteStatus) { + $sharee->inviteStatus = \Sabre\DAV\Sharing\Plugin::INVITE_NORESPONSE; + } + // Adding a new invitee + $this->invites[] = $sharee; + } + + } + + } + + /** + * Returns the list of people whom this resource is shared with. + * + * Every item in the returned array must be a Sharee object with + * at least the following properties set: + * + * * $href + * * $shareAccess + * * $inviteStatus + * + * and optionally: + * + * * $properties + * + * @return \Sabre\DAV\Xml\Element\Sharee[] + */ + function getInvites() { + + return $this->invites; + + } +} diff --git a/vendor/sabre/dav/tests/Sabre/DAV/Mock/StreamingFile.php b/vendor/sabre/dav/tests/Sabre/DAV/Mock/StreamingFile.php new file mode 100644 index 000000000..d60a49d09 --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/DAV/Mock/StreamingFile.php @@ -0,0 +1,102 @@ +<?php + +namespace Sabre\DAV\Mock; + +/** + * Mock Streaming File File + * + * Works similar to the mock file, but this one works with streams and has no + * content-length or etags. + * + * @copyright Copyright (C) fruux GmbH (https://fruux.com/) + * @author Evert Pot (http://evertpot.com/) + * @license http://sabre.io/license/ Modified BSD License + */ +class StreamingFile extends File { + + protected $size; + + /** + * Updates the data + * + * The data argument is a readable stream resource. + * + * After a successful put operation, you may choose to return an ETag. The + * etag must always be surrounded by double-quotes. These quotes must + * appear in the actual string you're returning. + * + * Clients may use the ETag from a PUT request to later on make sure that + * when they update the file, the contents haven't changed in the mean + * time. + * + * If you don't plan to store the file byte-by-byte, and you return a + * different object on a subsequent GET you are strongly recommended to not + * return an ETag, and just return null. + * + * @param resource $data + * @return string|null + */ + function put($data) { + + if (is_string($data)) { + $stream = fopen('php://memory', 'r+'); + fwrite($stream, $data); + rewind($stream); + $data = $stream; + } + $this->contents = $data; + + } + + /** + * Returns the data + * + * This method may either return a string or a readable stream resource + * + * @return mixed + */ + function get() { + + return $this->contents; + + } + + /** + * Returns the ETag for a file + * + * An ETag is a unique identifier representing the current version of the file. If the file changes, the ETag MUST change. + * + * Return null if the ETag can not effectively be determined + * + * @return void + */ + function getETag() { + + return null; + + } + + /** + * Returns the size of the node, in bytes + * + * @return int + */ + function getSize() { + + return $this->size; + + } + + /** + * Allows testing scripts to set the resource's file size. + * + * @param int $size + * @return void + */ + function setSize($size) { + + $this->size = $size; + + } + +} diff --git a/vendor/sabre/dav/tests/Sabre/DAV/MockLogger.php b/vendor/sabre/dav/tests/Sabre/DAV/MockLogger.php new file mode 100644 index 000000000..033325693 --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/DAV/MockLogger.php @@ -0,0 +1,36 @@ +<?php + +namespace Sabre\DAV; + +use Psr\Log\AbstractLogger; + +/** + * The MockLogger is a simple PSR-3 implementation that we can use to test + * whether things get logged correctly. + * + * @copyright Copyright (C) fruux GmbH. (https://fruux.com/) + * @author Evert Pot (http://evertpot.com/) + * @license http://sabre.io/license/ Modified BSD License + */ +class MockLogger extends AbstractLogger { + + public $logs = []; + + /** + * Logs with an arbitrary level. + * + * @param mixed $level + * @param string $message + * @param array $context + * @return null + */ + function log($level, $message, array $context = []) { + + $this->logs[] = [ + $level, + $message, + $context + ]; + + } +} diff --git a/vendor/sabre/dav/tests/Sabre/DAV/Mount/PluginTest.php b/vendor/sabre/dav/tests/Sabre/DAV/Mount/PluginTest.php new file mode 100644 index 000000000..3213fcb1b --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/DAV/Mount/PluginTest.php @@ -0,0 +1,58 @@ +<?php + +namespace Sabre\DAV\Mount; + +use Sabre\DAV; +use Sabre\HTTP; + +require_once 'Sabre/DAV/AbstractServer.php'; + +class PluginTest extends DAV\AbstractServer { + + function setUp() { + + parent::setUp(); + $this->server->addPlugin(new Plugin()); + + } + + function testPassThrough() { + + $serverVars = [ + 'REQUEST_URI' => '/', + 'REQUEST_METHOD' => 'GET', + ]; + + $request = HTTP\Sapi::createFromServerArray($serverVars); + $this->server->httpRequest = ($request); + $this->server->exec(); + + $this->assertEquals(501, $this->response->status, 'We expected GET to not be implemented for Directories. Response body: ' . $this->response->body); + + } + + function testMountResponse() { + + $serverVars = [ + 'REQUEST_URI' => '/?mount', + 'REQUEST_METHOD' => 'GET', + 'QUERY_STRING' => 'mount', + 'HTTP_HOST' => 'example.org', + ]; + + $request = HTTP\Sapi::createFromServerArray($serverVars); + $this->server->httpRequest = ($request); + $this->server->exec(); + + $this->assertEquals(200, $this->response->status); + + $xml = simplexml_load_string($this->response->body); + $this->assertInstanceOf('SimpleXMLElement', $xml, 'Response was not a valid xml document. The list of errors:' . print_r(libxml_get_errors(), true) . '. xml body: ' . $this->response->body . '. What type we got: ' . gettype($xml) . ' class, if object: ' . get_class($xml)); + + $xml->registerXPathNamespace('dm', 'http://purl.org/NET/webdav/mount'); + $url = $xml->xpath('//dm:url'); + $this->assertEquals('http://example.org/', (string)$url[0]); + + } + +} diff --git a/vendor/sabre/dav/tests/Sabre/DAV/ObjectTreeTest.php b/vendor/sabre/dav/tests/Sabre/DAV/ObjectTreeTest.php new file mode 100644 index 000000000..15289ce52 --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/DAV/ObjectTreeTest.php @@ -0,0 +1,100 @@ +<?php + +namespace Sabre\DAV; + +require_once 'Sabre/TestUtil.php'; + +class ObjectTreeTest extends \PHPUnit_Framework_TestCase { + + protected $tree; + + function setup() { + + \Sabre\TestUtil::clearTempDir(); + mkdir(SABRE_TEMPDIR . '/root'); + mkdir(SABRE_TEMPDIR . '/root/subdir'); + file_put_contents(SABRE_TEMPDIR . '/root/file.txt', 'contents'); + file_put_contents(SABRE_TEMPDIR . '/root/subdir/subfile.txt', 'subcontents'); + $rootNode = new FSExt\Directory(SABRE_TEMPDIR . '/root'); + $this->tree = new Tree($rootNode); + + } + + function teardown() { + + \Sabre\TestUtil::clearTempDir(); + + } + + function testGetRootNode() { + + $root = $this->tree->getNodeForPath(''); + $this->assertInstanceOf('Sabre\\DAV\\FSExt\\Directory', $root); + + } + + function testGetSubDir() { + + $root = $this->tree->getNodeForPath('subdir'); + $this->assertInstanceOf('Sabre\\DAV\\FSExt\\Directory', $root); + + } + + function testCopyFile() { + + $this->tree->copy('file.txt', 'file2.txt'); + $this->assertTrue(file_exists(SABRE_TEMPDIR . '/root/file2.txt')); + $this->assertEquals('contents', file_get_contents(SABRE_TEMPDIR . '/root/file2.txt')); + + } + + /** + * @depends testCopyFile + */ + function testCopyDirectory() { + + $this->tree->copy('subdir', 'subdir2'); + $this->assertTrue(file_exists(SABRE_TEMPDIR . '/root/subdir2')); + $this->assertTrue(file_exists(SABRE_TEMPDIR . '/root/subdir2/subfile.txt')); + $this->assertEquals('subcontents', file_get_contents(SABRE_TEMPDIR . '/root/subdir2/subfile.txt')); + + } + + /** + * @depends testCopyFile + */ + function testMoveFile() { + + $this->tree->move('file.txt', 'file2.txt'); + $this->assertTrue(file_exists(SABRE_TEMPDIR . '/root/file2.txt')); + $this->assertFalse(file_exists(SABRE_TEMPDIR . '/root/file.txt')); + $this->assertEquals('contents', file_get_contents(SABRE_TEMPDIR . '/root/file2.txt')); + + } + + /** + * @depends testMoveFile + */ + function testMoveFileNewParent() { + + $this->tree->move('file.txt', 'subdir/file2.txt'); + $this->assertTrue(file_exists(SABRE_TEMPDIR . '/root/subdir/file2.txt')); + $this->assertFalse(file_exists(SABRE_TEMPDIR . '/root/file.txt')); + $this->assertEquals('contents', file_get_contents(SABRE_TEMPDIR . '/root/subdir/file2.txt')); + + } + + /** + * @depends testCopyDirectory + */ + function testMoveDirectory() { + + $this->tree->move('subdir', 'subdir2'); + $this->assertTrue(file_exists(SABRE_TEMPDIR . '/root/subdir2')); + $this->assertTrue(file_exists(SABRE_TEMPDIR . '/root/subdir2/subfile.txt')); + $this->assertFalse(file_exists(SABRE_TEMPDIR . '/root/subdir')); + $this->assertEquals('subcontents', file_get_contents(SABRE_TEMPDIR . '/root/subdir2/subfile.txt')); + + } + +} diff --git a/vendor/sabre/dav/tests/Sabre/DAV/PSR3Test.php b/vendor/sabre/dav/tests/Sabre/DAV/PSR3Test.php new file mode 100644 index 000000000..d30fde128 --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/DAV/PSR3Test.php @@ -0,0 +1,87 @@ +<?php + +namespace Sabre\DAV; + +class PSR3Test extends \PHPUnit_Framework_TestCase { + + function testIsLoggerAware() { + + $server = new Server(); + $this->assertInstanceOf( + 'Psr\Log\LoggerAwareInterface', + $server + ); + + } + + function testGetNullLoggerByDefault() { + + $server = new Server(); + $this->assertInstanceOf( + 'Psr\Log\NullLogger', + $server->getLogger() + ); + + } + + function testSetLogger() { + + $server = new Server(); + $logger = new MockLogger(); + + $server->setLogger($logger); + + $this->assertEquals( + $logger, + $server->getLogger() + ); + + } + + /** + * Start the server, trigger an exception and see if the logger captured + * it. + */ + function testLogException() { + + $server = new Server(); + $logger = new MockLogger(); + + $server->setLogger($logger); + + // Creating a fake environment to execute http requests in. + $request = new \Sabre\HTTP\Request( + 'GET', + '/not-found', + [] + ); + $response = new \Sabre\HTTP\Response(); + + $server->httpRequest = $request; + $server->httpResponse = $response; + $server->sapi = new \Sabre\HTTP\SapiMock(); + + // Executing the request. + $server->exec(); + + // The request should have triggered a 404 status. + $this->assertEquals(404, $response->getStatus()); + + // We should also see this in the PSR-3 log. + $this->assertEquals(1, count($logger->logs)); + + $logItem = $logger->logs[0]; + + $this->assertEquals( + \Psr\Log\LogLevel::INFO, + $logItem[0] + ); + + $this->assertInstanceOf( + 'Exception', + $logItem[2]['exception'] + ); + + } + +} diff --git a/vendor/sabre/dav/tests/Sabre/DAV/PartialUpdate/FileMock.php b/vendor/sabre/dav/tests/Sabre/DAV/PartialUpdate/FileMock.php new file mode 100644 index 000000000..eff1e7d67 --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/DAV/PartialUpdate/FileMock.php @@ -0,0 +1,122 @@ +<?php + +namespace Sabre\DAV\PartialUpdate; + +use Sabre\DAV; + +class FileMock implements IPatchSupport { + + protected $data = ''; + + function put($str) { + + if (is_resource($str)) { + $str = stream_get_contents($str); + } + $this->data = $str; + + } + + /** + * Updates the file based on a range specification. + * + * The first argument is the data, which is either a readable stream + * resource or a string. + * + * The second argument is the type of update we're doing. + * This is either: + * * 1. append + * * 2. update based on a start byte + * * 3. update based on an end byte + *; + * The third argument is the start or end byte. + * + * After a successful put operation, you may choose to return an ETag. The + * etag must always be surrounded by double-quotes. These quotes must + * appear in the actual string you're returning. + * + * Clients may use the ETag from a PUT request to later on make sure that + * when they update the file, the contents haven't changed in the mean + * time. + * + * @param resource|string $data + * @param int $rangeType + * @param int $offset + * @return string|null + */ + function patch($data, $rangeType, $offset = null) { + + if (is_resource($data)) { + $data = stream_get_contents($data); + } + + switch ($rangeType) { + + case 1 : + $this->data .= $data; + break; + case 3 : + // Turn the offset into an offset-offset. + $offset = strlen($this->data) - $offset; + // No break is intentional + case 2 : + $this->data = + substr($this->data, 0, $offset) . + $data . + substr($this->data, $offset + strlen($data)); + break; + + } + + } + + function get() { + + return $this->data; + + } + + function getContentType() { + + return 'text/plain'; + + } + + function getSize() { + + return strlen($this->data); + + } + + function getETag() { + + return '"' . $this->data . '"'; + + } + + function delete() { + + throw new DAV\Exception\MethodNotAllowed(); + + } + + function setName($name) { + + throw new DAV\Exception\MethodNotAllowed(); + + } + + function getName() { + + return 'partial'; + + } + + function getLastModified() { + + return null; + + } + + +} diff --git a/vendor/sabre/dav/tests/Sabre/DAV/PartialUpdate/PluginTest.php b/vendor/sabre/dav/tests/Sabre/DAV/PartialUpdate/PluginTest.php new file mode 100644 index 000000000..5bd696416 --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/DAV/PartialUpdate/PluginTest.php @@ -0,0 +1,135 @@ +<?php + +namespace Sabre\DAV\PartialUpdate; + +use Sabre\DAV; +use Sabre\HTTP; + +require_once 'Sabre/DAV/PartialUpdate/FileMock.php'; + +class PluginTest extends \Sabre\DAVServerTest { + + protected $node; + protected $plugin; + + function setUp() { + + $this->node = new FileMock(); + $this->tree[] = $this->node; + + parent::setUp(); + + $this->plugin = new Plugin(); + $this->server->addPlugin($this->plugin); + + + + } + + function testInit() { + + $this->assertEquals('partialupdate', $this->plugin->getPluginName()); + $this->assertEquals(['sabredav-partialupdate'], $this->plugin->getFeatures()); + $this->assertEquals([ + 'PATCH' + ], $this->plugin->getHTTPMethods('partial')); + $this->assertEquals([ + ], $this->plugin->getHTTPMethods('')); + + } + + function testPatchNoRange() { + + $this->node->put('aaaaaaaa'); + $request = HTTP\Sapi::createFromServerArray([ + 'REQUEST_METHOD' => 'PATCH', + 'REQUEST_URI' => '/partial', + ]); + $response = $this->request($request); + + $this->assertEquals(400, $response->status, 'Full response body:' . $response->body); + + } + + function testPatchNotSupported() { + + $this->node->put('aaaaaaaa'); + $request = new HTTP\Request('PATCH', '/', ['X-Update-Range' => '3-4']); + $request->setBody( + 'bbb' + ); + $response = $this->request($request); + + $this->assertEquals(405, $response->status, 'Full response body:' . $response->body); + + } + + function testPatchNoContentType() { + + $this->node->put('aaaaaaaa'); + $request = new HTTP\Request('PATCH', '/partial', ['X-Update-Range' => 'bytes=3-4']); + $request->setBody( + 'bbb' + ); + $response = $this->request($request); + + $this->assertEquals(415, $response->status, 'Full response body:' . $response->body); + + } + + function testPatchBadRange() { + + $this->node->put('aaaaaaaa'); + $request = new HTTP\Request('PATCH', '/partial', ['X-Update-Range' => 'bytes=3-4', 'Content-Type' => 'application/x-sabredav-partialupdate', 'Content-Length' => '3']); + $request->setBody( + 'bbb' + ); + $response = $this->request($request); + + $this->assertEquals(416, $response->status, 'Full response body:' . $response->body); + + } + + function testPatchNoLength() { + + $this->node->put('aaaaaaaa'); + $request = new HTTP\Request('PATCH', '/partial', ['X-Update-Range' => 'bytes=3-5', 'Content-Type' => 'application/x-sabredav-partialupdate']); + $request->setBody( + 'bbb' + ); + $response = $this->request($request); + + $this->assertEquals(411, $response->status, 'Full response body:' . $response->body); + + } + + function testPatchSuccess() { + + $this->node->put('aaaaaaaa'); + $request = new HTTP\Request('PATCH', '/partial', ['X-Update-Range' => 'bytes=3-5', 'Content-Type' => 'application/x-sabredav-partialupdate', 'Content-Length' => 3]); + $request->setBody( + 'bbb' + ); + $response = $this->request($request); + + $this->assertEquals(204, $response->status, 'Full response body:' . $response->body); + $this->assertEquals('aaabbbaa', $this->node->get()); + + } + + function testPatchNoEndRange() { + + $this->node->put('aaaaa'); + $request = new HTTP\Request('PATCH', '/partial', ['X-Update-Range' => 'bytes=3-', 'Content-Type' => 'application/x-sabredav-partialupdate', 'Content-Length' => '3']); + $request->setBody( + 'bbb' + ); + + $response = $this->request($request); + + $this->assertEquals(204, $response->getStatus(), 'Full response body:' . $response->getBodyAsString()); + $this->assertEquals('aaabbb', $this->node->get()); + + } + +} diff --git a/vendor/sabre/dav/tests/Sabre/DAV/PartialUpdate/SpecificationTest.php b/vendor/sabre/dav/tests/Sabre/DAV/PartialUpdate/SpecificationTest.php new file mode 100644 index 000000000..2c6274173 --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/DAV/PartialUpdate/SpecificationTest.php @@ -0,0 +1,94 @@ +<?php + +namespace Sabre\DAV\PartialUpdate; + +use Sabre\DAV\FSExt\File; +use Sabre\DAV\Server; +use Sabre\HTTP; + +/** + * This test is an end-to-end sabredav test that goes through all + * the cases in the specification. + * + * See: http://sabre.io/dav/http-patch/ + */ +class SpecificationTest extends \PHPUnit_Framework_TestCase { + + protected $server; + + function setUp() { + + $tree = [ + new File(SABRE_TEMPDIR . '/foobar.txt') + ]; + $server = new Server($tree); + $server->debugExceptions = true; + $server->addPlugin(new Plugin()); + + $tree[0]->put('1234567890'); + + $this->server = $server; + + } + + function tearDown() { + + \Sabre\TestUtil::clearTempDir(); + + } + + /** + * @param string $headerValue + * @param string $httpStatus + * @param string $endResult + * @param int $contentLength + * + * @dataProvider data + */ + function testUpdateRange($headerValue, $httpStatus, $endResult, $contentLength = 4) { + + $headers = [ + 'Content-Type' => 'application/x-sabredav-partialupdate', + 'X-Update-Range' => $headerValue, + ]; + + if ($contentLength) { + $headers['Content-Length'] = (string)$contentLength; + } + + $request = new HTTP\Request('PATCH', '/foobar.txt', $headers, '----'); + + $request->setBody('----'); + $this->server->httpRequest = $request; + $this->server->httpResponse = new HTTP\ResponseMock(); + $this->server->sapi = new HTTP\SapiMock(); + $this->server->exec(); + + $this->assertEquals($httpStatus, $this->server->httpResponse->status, 'Incorrect http status received: ' . $this->server->httpResponse->body); + if (!is_null($endResult)) { + $this->assertEquals($endResult, file_get_contents(SABRE_TEMPDIR . '/foobar.txt')); + } + + } + + function data() { + + return [ + // Problems + ['foo', 400, null], + ['bytes=0-3', 411, null, 0], + ['bytes=4-1', 416, null], + + ['bytes=0-3', 204, '----567890'], + ['bytes=1-4', 204, '1----67890'], + ['bytes=0-', 204, '----567890'], + ['bytes=-4', 204, '123456----'], + ['bytes=-2', 204, '12345678----'], + ['bytes=2-', 204, '12----7890'], + ['append', 204, '1234567890----'], + + ]; + + } + +} diff --git a/vendor/sabre/dav/tests/Sabre/DAV/PropFindTest.php b/vendor/sabre/dav/tests/Sabre/DAV/PropFindTest.php new file mode 100644 index 000000000..ec1d616cb --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/DAV/PropFindTest.php @@ -0,0 +1,76 @@ +<?php + +namespace Sabre\DAV; + +class PropFindTest extends \PHPUnit_Framework_TestCase { + + function testHandle() { + + $propFind = new PropFind('foo', ['{DAV:}displayname']); + $propFind->handle('{DAV:}displayname', 'foobar'); + + $this->assertEquals([ + 200 => ['{DAV:}displayname' => 'foobar'], + 404 => [], + ], $propFind->getResultForMultiStatus()); + + } + + function testHandleCallBack() { + + $propFind = new PropFind('foo', ['{DAV:}displayname']); + $propFind->handle('{DAV:}displayname', function() { return 'foobar'; }); + + $this->assertEquals([ + 200 => ['{DAV:}displayname' => 'foobar'], + 404 => [], + ], $propFind->getResultForMultiStatus()); + + } + + function testAllPropDefaults() { + + $propFind = new PropFind('foo', ['{DAV:}displayname'], 0, PropFind::ALLPROPS); + + $this->assertEquals([ + 200 => [], + ], $propFind->getResultForMultiStatus()); + + } + + function testSet() { + + $propFind = new PropFind('foo', ['{DAV:}displayname']); + $propFind->set('{DAV:}displayname', 'bar'); + + $this->assertEquals([ + 200 => ['{DAV:}displayname' => 'bar'], + 404 => [], + ], $propFind->getResultForMultiStatus()); + + } + + function testSetAllpropCustom() { + + $propFind = new PropFind('foo', ['{DAV:}displayname'], 0, PropFind::ALLPROPS); + $propFind->set('{DAV:}customproperty', 'bar'); + + $this->assertEquals([ + 200 => ['{DAV:}customproperty' => 'bar'], + ], $propFind->getResultForMultiStatus()); + + } + + function testSetUnset() { + + $propFind = new PropFind('foo', ['{DAV:}displayname']); + $propFind->set('{DAV:}displayname', 'bar'); + $propFind->set('{DAV:}displayname', null); + + $this->assertEquals([ + 200 => [], + 404 => ['{DAV:}displayname' => null], + ], $propFind->getResultForMultiStatus()); + + } +} diff --git a/vendor/sabre/dav/tests/Sabre/DAV/PropPatchTest.php b/vendor/sabre/dav/tests/Sabre/DAV/PropPatchTest.php new file mode 100644 index 000000000..72dbf5345 --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/DAV/PropPatchTest.php @@ -0,0 +1,351 @@ +<?php + +namespace Sabre\DAV; + +class PropPatchTest extends \PHPUnit_Framework_TestCase { + + protected $propPatch; + + function setUp() { + + $this->propPatch = new PropPatch([ + '{DAV:}displayname' => 'foo', + ]); + $this->assertEquals(['{DAV:}displayname' => 'foo'], $this->propPatch->getMutations()); + + } + + function testHandleSingleSuccess() { + + $hasRan = false; + + $this->propPatch->handle('{DAV:}displayname', function($value) use (&$hasRan) { + $hasRan = true; + $this->assertEquals('foo', $value); + return true; + }); + + $this->assertTrue($this->propPatch->commit()); + $result = $this->propPatch->getResult(); + $this->assertEquals(['{DAV:}displayname' => 200], $result); + + $this->assertTrue($hasRan); + + } + + function testHandleSingleFail() { + + $hasRan = false; + + $this->propPatch->handle('{DAV:}displayname', function($value) use (&$hasRan) { + $hasRan = true; + $this->assertEquals('foo', $value); + return false; + }); + + $this->assertFalse($this->propPatch->commit()); + $result = $this->propPatch->getResult(); + $this->assertEquals(['{DAV:}displayname' => 403], $result); + + $this->assertTrue($hasRan); + + } + + function testHandleSingleCustomResult() { + + $hasRan = false; + + $this->propPatch->handle('{DAV:}displayname', function($value) use (&$hasRan) { + $hasRan = true; + $this->assertEquals('foo', $value); + return 201; + }); + + $this->assertTrue($this->propPatch->commit()); + $result = $this->propPatch->getResult(); + $this->assertEquals(['{DAV:}displayname' => 201], $result); + + $this->assertTrue($hasRan); + + } + + function testHandleSingleDeleteSuccess() { + + $hasRan = false; + + $this->propPatch = new PropPatch(['{DAV:}displayname' => null]); + $this->propPatch->handle('{DAV:}displayname', function($value) use (&$hasRan) { + $hasRan = true; + $this->assertNull($value); + return true; + }); + + $this->assertTrue($this->propPatch->commit()); + $result = $this->propPatch->getResult(); + $this->assertEquals(['{DAV:}displayname' => 204], $result); + + $this->assertTrue($hasRan); + + } + + + function testHandleNothing() { + + $hasRan = false; + + $this->propPatch->handle('{DAV:}foobar', function($value) use (&$hasRan) { + $hasRan = true; + }); + + $this->assertFalse($hasRan); + + } + + /** + * @depends testHandleSingleSuccess + */ + function testHandleRemaining() { + + $hasRan = false; + + $this->propPatch->handleRemaining(function($mutations) use (&$hasRan) { + $hasRan = true; + $this->assertEquals(['{DAV:}displayname' => 'foo'], $mutations); + return true; + }); + + $this->assertTrue($this->propPatch->commit()); + $result = $this->propPatch->getResult(); + $this->assertEquals(['{DAV:}displayname' => 200], $result); + + $this->assertTrue($hasRan); + + } + function testHandleRemainingNothingToDo() { + + $hasRan = false; + + $this->propPatch->handle('{DAV:}displayname', function() {}); + $this->propPatch->handleRemaining(function($mutations) use (&$hasRan) { + $hasRan = true; + }); + + $this->assertFalse($hasRan); + + } + + function testSetResultCode() { + + $this->propPatch->setResultCode('{DAV:}displayname', 201); + $this->assertTrue($this->propPatch->commit()); + $result = $this->propPatch->getResult(); + $this->assertEquals(['{DAV:}displayname' => 201], $result); + + } + + function testSetResultCodeFail() { + + $this->propPatch->setResultCode('{DAV:}displayname', 402); + $this->assertFalse($this->propPatch->commit()); + $result = $this->propPatch->getResult(); + $this->assertEquals(['{DAV:}displayname' => 402], $result); + + } + + function testSetRemainingResultCode() { + + $this->propPatch->setRemainingResultCode(204); + $this->assertTrue($this->propPatch->commit()); + $result = $this->propPatch->getResult(); + $this->assertEquals(['{DAV:}displayname' => 204], $result); + + } + + function testCommitNoHandler() { + + $this->assertFalse($this->propPatch->commit()); + $result = $this->propPatch->getResult(); + $this->assertEquals(['{DAV:}displayname' => 403], $result); + + } + + function testHandlerNotCalled() { + + $hasRan = false; + + $this->propPatch->setResultCode('{DAV:}displayname', 402); + $this->propPatch->handle('{DAV:}displayname', function($value) use (&$hasRan) { + $hasRan = true; + }); + + $this->propPatch->commit(); + + // The handler is not supposed to have ran + $this->assertFalse($hasRan); + + } + + function testDependencyFail() { + + $propPatch = new PropPatch([ + '{DAV:}a' => 'foo', + '{DAV:}b' => 'bar', + ]); + + $calledA = false; + $calledB = false; + + $propPatch->handle('{DAV:}a', function() use (&$calledA) { + $calledA = true; + return false; + }); + $propPatch->handle('{DAV:}b', function() use (&$calledB) { + $calledB = true; + return false; + }); + + $result = $propPatch->commit(); + $this->assertTrue($calledA); + $this->assertFalse($calledB); + + $this->assertFalse($result); + + $this->assertEquals([ + '{DAV:}a' => 403, + '{DAV:}b' => 424, + ], $propPatch->getResult()); + + } + + /** + * @expectedException \UnexpectedValueException + */ + function testHandleSingleBrokenResult() { + + $propPatch = new PropPatch([ + '{DAV:}a' => 'foo', + ]); + + $propPatch->handle('{DAV:}a', function() { + return []; + }); + $propPatch->commit(); + + } + + function testHandleMultiValueSuccess() { + + $propPatch = new PropPatch([ + '{DAV:}a' => 'foo', + '{DAV:}b' => 'bar', + '{DAV:}c' => null, + ]); + + $calledA = false; + + $propPatch->handle(['{DAV:}a', '{DAV:}b', '{DAV:}c'], function($properties) use (&$calledA) { + $calledA = true; + $this->assertEquals([ + '{DAV:}a' => 'foo', + '{DAV:}b' => 'bar', + '{DAV:}c' => null, + ], $properties); + return true; + }); + $result = $propPatch->commit(); + $this->assertTrue($calledA); + $this->assertTrue($result); + + $this->assertEquals([ + '{DAV:}a' => 200, + '{DAV:}b' => 200, + '{DAV:}c' => 204, + ], $propPatch->getResult()); + + } + + + function testHandleMultiValueFail() { + + $propPatch = new PropPatch([ + '{DAV:}a' => 'foo', + '{DAV:}b' => 'bar', + '{DAV:}c' => null, + ]); + + $calledA = false; + + $propPatch->handle(['{DAV:}a', '{DAV:}b', '{DAV:}c'], function($properties) use (&$calledA) { + $calledA = true; + $this->assertEquals([ + '{DAV:}a' => 'foo', + '{DAV:}b' => 'bar', + '{DAV:}c' => null, + ], $properties); + return false; + }); + $result = $propPatch->commit(); + $this->assertTrue($calledA); + $this->assertFalse($result); + + $this->assertEquals([ + '{DAV:}a' => 403, + '{DAV:}b' => 403, + '{DAV:}c' => 403, + ], $propPatch->getResult()); + + } + + function testHandleMultiValueCustomResult() { + + $propPatch = new PropPatch([ + '{DAV:}a' => 'foo', + '{DAV:}b' => 'bar', + '{DAV:}c' => null, + ]); + + $calledA = false; + + $propPatch->handle(['{DAV:}a', '{DAV:}b', '{DAV:}c'], function($properties) use (&$calledA) { + $calledA = true; + $this->assertEquals([ + '{DAV:}a' => 'foo', + '{DAV:}b' => 'bar', + '{DAV:}c' => null, + ], $properties); + + return [ + '{DAV:}a' => 201, + '{DAV:}b' => 204, + ]; + }); + $result = $propPatch->commit(); + $this->assertTrue($calledA); + $this->assertFalse($result); + + $this->assertEquals([ + '{DAV:}a' => 201, + '{DAV:}b' => 204, + '{DAV:}c' => 500, + ], $propPatch->getResult()); + + } + + /** + * @expectedException \UnexpectedValueException + */ + function testHandleMultiValueBroken() { + + $propPatch = new PropPatch([ + '{DAV:}a' => 'foo', + '{DAV:}b' => 'bar', + '{DAV:}c' => null, + ]); + + $propPatch->handle(['{DAV:}a', '{DAV:}b', '{DAV:}c'], function($properties) { + return 'hi'; + }); + $propPatch->commit(); + + } +} diff --git a/vendor/sabre/dav/tests/Sabre/DAV/PropertyStorage/Backend/AbstractPDOTest.php b/vendor/sabre/dav/tests/Sabre/DAV/PropertyStorage/Backend/AbstractPDOTest.php new file mode 100644 index 000000000..a2b9987b7 --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/DAV/PropertyStorage/Backend/AbstractPDOTest.php @@ -0,0 +1,193 @@ +<?php + +namespace Sabre\DAV\PropertyStorage\Backend; + +use Sabre\DAV\PropFind; +use Sabre\DAV\PropPatch; +use Sabre\DAV\Xml\Property\Complex; +use Sabre\DAV\Xml\Property\Href; + +abstract class AbstractPDOTest extends \PHPUnit_Framework_TestCase { + + use \Sabre\DAV\DbTestHelperTrait; + + function getBackend() { + + $this->dropTables('propertystorage'); + $this->createSchema('propertystorage'); + + $pdo = $this->getPDO(); + + $pdo->exec("INSERT INTO propertystorage (path, name, valuetype, value) VALUES ('dir', '{DAV:}displayname', 1, 'Directory')"); + + return new PDO($this->getPDO()); + + } + + function testPropFind() { + + $backend = $this->getBackend(); + + $propFind = new PropFind('dir', ['{DAV:}displayname']); + $backend->propFind('dir', $propFind); + + $this->assertEquals('Directory', $propFind->get('{DAV:}displayname')); + + } + + function testPropFindNothingToDo() { + + $backend = $this->getBackend(); + + $propFind = new PropFind('dir', ['{DAV:}displayname']); + $propFind->set('{DAV:}displayname', 'foo'); + $backend->propFind('dir', $propFind); + + $this->assertEquals('foo', $propFind->get('{DAV:}displayname')); + + } + + /** + * @depends testPropFind + */ + function testPropPatchUpdate() { + + $backend = $this->getBackend(); + + $propPatch = new PropPatch(['{DAV:}displayname' => 'bar']); + $backend->propPatch('dir', $propPatch); + $propPatch->commit(); + + $propFind = new PropFind('dir', ['{DAV:}displayname']); + $backend->propFind('dir', $propFind); + + $this->assertEquals('bar', $propFind->get('{DAV:}displayname')); + + } + + /** + * @depends testPropPatchUpdate + */ + function testPropPatchComplex() { + + $backend = $this->getBackend(); + + $complex = new Complex('<foo xmlns="DAV:">somevalue</foo>'); + + $propPatch = new PropPatch(['{DAV:}complex' => $complex]); + $backend->propPatch('dir', $propPatch); + $propPatch->commit(); + + $propFind = new PropFind('dir', ['{DAV:}complex']); + $backend->propFind('dir', $propFind); + + $this->assertEquals($complex, $propFind->get('{DAV:}complex')); + + } + + + /** + * @depends testPropPatchComplex + */ + function testPropPatchCustom() { + + $backend = $this->getBackend(); + + $custom = new Href('/foo/bar/'); + + $propPatch = new PropPatch(['{DAV:}custom' => $custom]); + $backend->propPatch('dir', $propPatch); + $propPatch->commit(); + + $propFind = new PropFind('dir', ['{DAV:}custom']); + $backend->propFind('dir', $propFind); + + $this->assertEquals($custom, $propFind->get('{DAV:}custom')); + + } + + /** + * @depends testPropFind + */ + function testPropPatchRemove() { + + $backend = $this->getBackend(); + + $propPatch = new PropPatch(['{DAV:}displayname' => null]); + $backend->propPatch('dir', $propPatch); + $propPatch->commit(); + + $propFind = new PropFind('dir', ['{DAV:}displayname']); + $backend->propFind('dir', $propFind); + + $this->assertEquals(null, $propFind->get('{DAV:}displayname')); + + } + + /** + * @depends testPropFind + */ + function testDelete() { + + $backend = $this->getBackend(); + $backend->delete('dir'); + + $propFind = new PropFind('dir', ['{DAV:}displayname']); + $backend->propFind('dir', $propFind); + + $this->assertEquals(null, $propFind->get('{DAV:}displayname')); + + } + + /** + * @depends testPropFind + */ + function testMove() { + + $backend = $this->getBackend(); + // Creating a new child property. + $propPatch = new PropPatch(['{DAV:}displayname' => 'child']); + $backend->propPatch('dir/child', $propPatch); + $propPatch->commit(); + + $backend->move('dir', 'dir2'); + + // Old 'dir' + $propFind = new PropFind('dir', ['{DAV:}displayname']); + $backend->propFind('dir', $propFind); + $this->assertEquals(null, $propFind->get('{DAV:}displayname')); + + // Old 'dir/child' + $propFind = new PropFind('dir/child', ['{DAV:}displayname']); + $backend->propFind('dir/child', $propFind); + $this->assertEquals(null, $propFind->get('{DAV:}displayname')); + + // New 'dir2' + $propFind = new PropFind('dir2', ['{DAV:}displayname']); + $backend->propFind('dir2', $propFind); + $this->assertEquals('Directory', $propFind->get('{DAV:}displayname')); + + // New 'dir2/child' + $propFind = new PropFind('dir2/child', ['{DAV:}displayname']); + $backend->propFind('dir2/child', $propFind); + $this->assertEquals('child', $propFind->get('{DAV:}displayname')); + } + + /** + * @depends testPropFind + */ + function testDeepDelete() { + + $backend = $this->getBackend(); + $propPatch = new PropPatch(['{DAV:}displayname' => 'child']); + $backend->propPatch('dir/child', $propPatch); + $propPatch->commit(); + $backend->delete('dir'); + + $propFind = new PropFind('dir/child', ['{DAV:}displayname']); + $backend->propFind('dir/child', $propFind); + + $this->assertEquals(null, $propFind->get('{DAV:}displayname')); + + } +} diff --git a/vendor/sabre/dav/tests/Sabre/DAV/PropertyStorage/Backend/Mock.php b/vendor/sabre/dav/tests/Sabre/DAV/PropertyStorage/Backend/Mock.php new file mode 100644 index 000000000..cf4c88fb8 --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/DAV/PropertyStorage/Backend/Mock.php @@ -0,0 +1,117 @@ +<?php + +namespace Sabre\DAV\PropertyStorage\Backend; + +use Sabre\DAV\PropFind; +use Sabre\DAV\PropPatch; + +class Mock implements BackendInterface { + + public $data = []; + + /** + * Fetches properties for a path. + * + * This method received a PropFind object, which contains all the + * information about the properties that need to be fetched. + * + * Usually you would just want to call 'get404Properties' on this object, + * as this will give you the _exact_ list of properties that need to be + * fetched, and haven't yet. + * + * @param string $path + * @param PropFind $propFind + * @return void + */ + function propFind($path, PropFind $propFind) { + + if (!isset($this->data[$path])) { + return; + } + + foreach ($this->data[$path] as $name => $value) { + $propFind->set($name, $value); + } + + } + + /** + * Updates properties for a path + * + * This method received a PropPatch object, which contains all the + * information about the update. + * + * Usually you would want to call 'handleRemaining' on this object, to get; + * a list of all properties that need to be stored. + * + * @param string $path + * @param PropPatch $propPatch + * @return void + */ + function propPatch($path, PropPatch $propPatch) { + + if (!isset($this->data[$path])) { + $this->data[$path] = []; + } + $propPatch->handleRemaining(function($properties) use ($path) { + + foreach ($properties as $propName => $propValue) { + + if (is_null($propValue)) { + unset($this->data[$path][$propName]); + } else { + $this->data[$path][$propName] = $propValue; + } + return true; + + } + + }); + + } + + /** + * This method is called after a node is deleted. + * + * This allows a backend to clean up all associated properties. + * + * @param string $path + * @return void + */ + function delete($path) { + + unset($this->data[$path]); + + } + + /** + * This method is called after a successful MOVE + * + * This should be used to migrate all properties from one path to another. + * Note that entire collections may be moved, so ensure that all properties + * for children are also moved along. + * + * @param string $source + * @param string $destination + * @return void + */ + function move($source, $destination) { + + foreach ($this->data as $path => $props) { + + if ($path === $source) { + $this->data[$destination] = $props; + unset($this->data[$path]); + continue; + } + + if (strpos($path, $source . '/') === 0) { + $this->data[$destination . substr($path, strlen($source) + 1)] = $props; + unset($this->data[$path]); + } + + } + + } + +} diff --git a/vendor/sabre/dav/tests/Sabre/DAV/PropertyStorage/Backend/PDOMysqlTest.php b/vendor/sabre/dav/tests/Sabre/DAV/PropertyStorage/Backend/PDOMysqlTest.php new file mode 100644 index 000000000..b92b034df --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/DAV/PropertyStorage/Backend/PDOMysqlTest.php @@ -0,0 +1,9 @@ +<?php + +namespace Sabre\DAV\PropertyStorage\Backend; + +class PDOMysqlTest extends AbstractPDOTest { + + public $driver = 'mysql'; + +} diff --git a/vendor/sabre/dav/tests/Sabre/DAV/PropertyStorage/Backend/PDOPgSqlTest.php b/vendor/sabre/dav/tests/Sabre/DAV/PropertyStorage/Backend/PDOPgSqlTest.php new file mode 100644 index 000000000..616c2e67a --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/DAV/PropertyStorage/Backend/PDOPgSqlTest.php @@ -0,0 +1,9 @@ +<?php + +namespace Sabre\DAV\PropertyStorage\Backend; + +class PDOPgSqlTest extends AbstractPDOTest { + + public $driver = 'pgsql'; + +} diff --git a/vendor/sabre/dav/tests/Sabre/DAV/PropertyStorage/Backend/PDOSqliteTest.php b/vendor/sabre/dav/tests/Sabre/DAV/PropertyStorage/Backend/PDOSqliteTest.php new file mode 100644 index 000000000..20a6a09e5 --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/DAV/PropertyStorage/Backend/PDOSqliteTest.php @@ -0,0 +1,9 @@ +<?php + +namespace Sabre\DAV\PropertyStorage\Backend; + +class PDOSqliteTest extends AbstractPDOTest { + + public $driver = 'sqlite'; + +} diff --git a/vendor/sabre/dav/tests/Sabre/DAV/PropertyStorage/PluginTest.php b/vendor/sabre/dav/tests/Sabre/DAV/PropertyStorage/PluginTest.php new file mode 100644 index 000000000..130f1490f --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/DAV/PropertyStorage/PluginTest.php @@ -0,0 +1,117 @@ +<?php + +namespace Sabre\DAV\PropertyStorage; + +class PluginTest extends \Sabre\DAVServerTest { + + protected $backend; + protected $plugin; + + protected $setupFiles = true; + + function setUp() { + + parent::setUp(); + $this->backend = new Backend\Mock(); + $this->plugin = new Plugin( + $this->backend + ); + + $this->server->addPlugin($this->plugin); + + } + + function testGetInfo() { + + $this->assertArrayHasKey( + 'name', + $this->plugin->getPluginInfo() + ); + + } + + function testSetProperty() { + + $this->server->updateProperties('', ['{DAV:}displayname' => 'hi']); + $this->assertEquals([ + '' => [ + '{DAV:}displayname' => 'hi', + ] + ], $this->backend->data); + + } + + /** + * @depends testSetProperty + */ + function testGetProperty() { + + $this->testSetProperty(); + $result = $this->server->getProperties('', ['{DAV:}displayname']); + + $this->assertEquals([ + '{DAV:}displayname' => 'hi', + ], $result); + + } + + /** + * @depends testSetProperty + */ + function testDeleteProperty() { + + $this->testSetProperty(); + $this->server->emit('afterUnbind', ['']); + $this->assertEquals([], $this->backend->data); + + } + + function testMove() { + + $this->server->tree->getNodeForPath('files')->createFile('source'); + $this->server->updateProperties('files/source', ['{DAV:}displayname' => 'hi']); + + $request = new \Sabre\HTTP\Request('MOVE', '/files/source', ['Destination' => '/files/dest']); + $this->assertHTTPStatus(201, $request); + + $result = $this->server->getProperties('/files/dest', ['{DAV:}displayname']); + + $this->assertEquals([ + '{DAV:}displayname' => 'hi', + ], $result); + + $this->server->tree->getNodeForPath('files')->createFile('source'); + $result = $this->server->getProperties('/files/source', ['{DAV:}displayname']); + + $this->assertEquals([], $result); + + } + + /** + * @depends testDeleteProperty + */ + function testSetPropertyInFilteredPath() { + + $this->plugin->pathFilter = function($path) { + + return false; + + }; + + $this->server->updateProperties('', ['{DAV:}displayname' => 'hi']); + $this->assertEquals([], $this->backend->data); + + } + + /** + * @depends testSetPropertyInFilteredPath + */ + function testGetPropertyInFilteredPath() { + + $this->testSetPropertyInFilteredPath(); + $result = $this->server->getProperties('', ['{DAV:}displayname']); + + $this->assertEquals([], $result); + } + +} diff --git a/vendor/sabre/dav/tests/Sabre/DAV/ServerEventsTest.php b/vendor/sabre/dav/tests/Sabre/DAV/ServerEventsTest.php new file mode 100644 index 000000000..42759647a --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/DAV/ServerEventsTest.php @@ -0,0 +1,126 @@ +<?php + +namespace Sabre\DAV; + +use Sabre\HTTP; + +require_once 'Sabre/DAV/AbstractServer.php'; + +class ServerEventsTest extends AbstractServer { + + private $tempPath; + + private $exception; + + function testAfterBind() { + + $this->server->on('afterBind', [$this, 'afterBindHandler']); + $newPath = 'afterBind'; + + $this->tempPath = ''; + $this->server->createFile($newPath, 'body'); + $this->assertEquals($newPath, $this->tempPath); + + } + + function afterBindHandler($path) { + + $this->tempPath = $path; + + } + + function testAfterResponse() { + + $mock = $this->getMockBuilder('stdClass') + ->setMethods(['afterResponseCallback']) + ->getMock(); + $mock->expects($this->once())->method('afterResponseCallback'); + + $this->server->on('afterResponse', [$mock, 'afterResponseCallback']); + + $this->server->httpRequest = HTTP\Sapi::createFromServerArray([ + 'REQUEST_METHOD' => 'GET', + 'REQUEST_URI' => '/test.txt', + ]); + + $this->server->exec(); + + } + + function testBeforeBindCancel() { + + $this->server->on('beforeBind', [$this, 'beforeBindCancelHandler']); + $this->assertFalse($this->server->createFile('bla', 'body')); + + // Also testing put() + $req = HTTP\Sapi::createFromServerArray([ + 'REQUEST_METHOD' => 'PUT', + 'REQUEST_URI' => '/barbar', + ]); + + $this->server->httpRequest = $req; + $this->server->exec(); + + $this->assertEquals(500, $this->server->httpResponse->getStatus()); + + } + + function beforeBindCancelHandler($path) { + + return false; + + } + + function testException() { + + $this->server->on('exception', [$this, 'exceptionHandler']); + + $req = HTTP\Sapi::createFromServerArray([ + 'REQUEST_METHOD' => 'GET', + 'REQUEST_URI' => '/not/exisitng', + ]); + $this->server->httpRequest = $req; + $this->server->exec(); + + $this->assertInstanceOf('Sabre\\DAV\\Exception\\NotFound', $this->exception); + + } + + function exceptionHandler(Exception $exception) { + + $this->exception = $exception; + + } + + function testMethod() { + + $k = 1; + $this->server->on('method', function($request, $response) use (&$k) { + + $k += 1; + + return false; + + }); + $this->server->on('method', function($request, $response) use (&$k) { + + $k += 2; + + return false; + + }); + + try { + $this->server->invokeMethod( + new HTTP\Request('BLABLA', '/'), + new HTTP\Response(), + false + ); + } catch (Exception $e) {} + + // Fun fact, PHP 7.1 changes the order when sorting-by-callback. + $this->assertTrue($k >= 2 && $k <= 3); + + } + +} diff --git a/vendor/sabre/dav/tests/Sabre/DAV/ServerMKCOLTest.php b/vendor/sabre/dav/tests/Sabre/DAV/ServerMKCOLTest.php new file mode 100644 index 000000000..557eddbbc --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/DAV/ServerMKCOLTest.php @@ -0,0 +1,366 @@ +<?php + +namespace Sabre\DAV; + +use Sabre\HTTP; + +class ServerMKCOLTest extends AbstractServer { + + function testMkcol() { + + $serverVars = [ + 'REQUEST_URI' => '/testcol', + 'REQUEST_METHOD' => 'MKCOL', + ]; + + $request = HTTP\Sapi::createFromServerArray($serverVars); + $request->setBody(""); + $this->server->httpRequest = ($request); + $this->server->exec(); + + $this->assertEquals([ + 'X-Sabre-Version' => [Version::VERSION], + 'Content-Length' => ['0'], + ], $this->response->getHeaders()); + + $this->assertEquals(201, $this->response->status); + $this->assertEquals('', $this->response->body); + $this->assertTrue(is_dir($this->tempDir . '/testcol')); + + } + + /** + * @depends testMkcol + */ + function testMKCOLUnknownBody() { + + $serverVars = [ + 'REQUEST_URI' => '/testcol', + 'REQUEST_METHOD' => 'MKCOL', + ]; + + $request = HTTP\Sapi::createFromServerArray($serverVars); + $request->setBody("Hello"); + $this->server->httpRequest = ($request); + $this->server->exec(); + + $this->assertEquals([ + 'X-Sabre-Version' => [Version::VERSION], + 'Content-Type' => ['application/xml; charset=utf-8'], + ], $this->response->getHeaders()); + + $this->assertEquals(415, $this->response->status); + + } + + /** + * @depends testMkcol + */ + function testMKCOLBrokenXML() { + + $serverVars = [ + 'REQUEST_URI' => '/testcol', + 'REQUEST_METHOD' => 'MKCOL', + 'HTTP_CONTENT_TYPE' => 'application/xml', + ]; + + $request = HTTP\Sapi::createFromServerArray($serverVars); + $request->setBody("Hello"); + $this->server->httpRequest = ($request); + $this->server->exec(); + + $this->assertEquals([ + 'X-Sabre-Version' => [Version::VERSION], + 'Content-Type' => ['application/xml; charset=utf-8'], + ], $this->response->getHeaders()); + + $this->assertEquals(400, $this->response->getStatus(), $this->response->getBodyAsString()); + + } + + /** + * @depends testMkcol + */ + function testMKCOLUnknownXML() { + + $serverVars = [ + 'REQUEST_URI' => '/testcol', + 'REQUEST_METHOD' => 'MKCOL', + 'HTTP_CONTENT_TYPE' => 'application/xml', + ]; + + $request = HTTP\Sapi::createFromServerArray($serverVars); + $request->setBody('<?xml version="1.0"?><html></html>'); + $this->server->httpRequest = ($request); + $this->server->exec(); + + $this->assertEquals([ + 'X-Sabre-Version' => [Version::VERSION], + 'Content-Type' => ['application/xml; charset=utf-8'], + ], $this->response->getHeaders()); + + $this->assertEquals(400, $this->response->getStatus()); + + } + + /** + * @depends testMkcol + */ + function testMKCOLNoResourceType() { + + $serverVars = [ + 'REQUEST_URI' => '/testcol', + 'REQUEST_METHOD' => 'MKCOL', + 'HTTP_CONTENT_TYPE' => 'application/xml', + ]; + + $request = HTTP\Sapi::createFromServerArray($serverVars); + $request->setBody('<?xml version="1.0"?> +<mkcol xmlns="DAV:"> + <set> + <prop> + <displayname>Evert</displayname> + </prop> + </set> +</mkcol>'); + $this->server->httpRequest = ($request); + $this->server->exec(); + + $this->assertEquals([ + 'X-Sabre-Version' => [Version::VERSION], + 'Content-Type' => ['application/xml; charset=utf-8'], + ], $this->response->getHeaders()); + + $this->assertEquals(400, $this->response->status, 'Wrong statuscode received. Full response body: ' . $this->response->body); + + } + + /** + * @depends testMkcol + */ + function testMKCOLIncorrectResourceType() { + + $serverVars = [ + 'REQUEST_URI' => '/testcol', + 'REQUEST_METHOD' => 'MKCOL', + 'HTTP_CONTENT_TYPE' => 'application/xml', + ]; + + $request = HTTP\Sapi::createFromServerArray($serverVars); + $request->setBody('<?xml version="1.0"?> +<mkcol xmlns="DAV:"> + <set> + <prop> + <resourcetype><collection /><blabla /></resourcetype> + </prop> + </set> +</mkcol>'); + $this->server->httpRequest = ($request); + $this->server->exec(); + + $this->assertEquals([ + 'X-Sabre-Version' => [Version::VERSION], + 'Content-Type' => ['application/xml; charset=utf-8'], + ], $this->response->getHeaders()); + + $this->assertEquals(403, $this->response->status, 'Wrong statuscode received. Full response body: ' . $this->response->body); + + } + + /** + * @depends testMKCOLIncorrectResourceType + */ + function testMKCOLSuccess() { + + $serverVars = [ + 'REQUEST_URI' => '/testcol', + 'REQUEST_METHOD' => 'MKCOL', + 'HTTP_CONTENT_TYPE' => 'application/xml', + ]; + + $request = HTTP\Sapi::createFromServerArray($serverVars); + $request->setBody('<?xml version="1.0"?> +<mkcol xmlns="DAV:"> + <set> + <prop> + <resourcetype><collection /></resourcetype> + </prop> + </set> +</mkcol>'); + $this->server->httpRequest = ($request); + $this->server->exec(); + + $this->assertEquals([ + 'X-Sabre-Version' => [Version::VERSION], + 'Content-Length' => ['0'], + ], $this->response->getHeaders()); + + $this->assertEquals(201, $this->response->status, 'Wrong statuscode received. Full response body: ' . $this->response->body); + + } + + /** + * @depends testMKCOLIncorrectResourceType + */ + function testMKCOLWhiteSpaceResourceType() { + + $serverVars = [ + 'REQUEST_URI' => '/testcol', + 'REQUEST_METHOD' => 'MKCOL', + 'HTTP_CONTENT_TYPE' => 'application/xml', + ]; + + $request = HTTP\Sapi::createFromServerArray($serverVars); + $request->setBody('<?xml version="1.0"?> +<mkcol xmlns="DAV:"> + <set> + <prop> + <resourcetype> + <collection /> + </resourcetype> + </prop> + </set> +</mkcol>'); + $this->server->httpRequest = ($request); + $this->server->exec(); + + $this->assertEquals([ + 'X-Sabre-Version' => [Version::VERSION], + 'Content-Length' => ['0'], + ], $this->response->getHeaders()); + + $this->assertEquals(201, $this->response->status, 'Wrong statuscode received. Full response body: ' . $this->response->body); + + } + + /** + * @depends testMKCOLIncorrectResourceType + */ + function testMKCOLNoParent() { + + $serverVars = [ + 'REQUEST_URI' => '/testnoparent/409me', + 'REQUEST_METHOD' => 'MKCOL', + ]; + + $request = HTTP\Sapi::createFromServerArray($serverVars); + $request->setBody(''); + + $this->server->httpRequest = ($request); + $this->server->exec(); + + $this->assertEquals([ + 'X-Sabre-Version' => [Version::VERSION], + 'Content-Type' => ['application/xml; charset=utf-8'], + ], $this->response->getHeaders()); + + $this->assertEquals(409, $this->response->status, 'Wrong statuscode received. Full response body: ' . $this->response->body); + + } + + /** + * @depends testMKCOLIncorrectResourceType + */ + function testMKCOLParentIsNoCollection() { + + $serverVars = [ + 'REQUEST_URI' => '/test.txt/409me', + 'REQUEST_METHOD' => 'MKCOL', + ]; + + $request = HTTP\Sapi::createFromServerArray($serverVars); + $request->setBody(''); + + $this->server->httpRequest = ($request); + $this->server->exec(); + + $this->assertEquals([ + 'X-Sabre-Version' => [Version::VERSION], + 'Content-Type' => ['application/xml; charset=utf-8'], + ], $this->response->getHeaders()); + + $this->assertEquals(409, $this->response->status, 'Wrong statuscode received. Full response body: ' . $this->response->body); + + } + + /** + * @depends testMKCOLIncorrectResourceType + */ + function testMKCOLAlreadyExists() { + + $serverVars = [ + 'REQUEST_URI' => '/test.txt', + 'REQUEST_METHOD' => 'MKCOL', + ]; + + $request = HTTP\Sapi::createFromServerArray($serverVars); + $request->setBody(''); + + $this->server->httpRequest = ($request); + $this->server->exec(); + + $this->assertEquals([ + 'X-Sabre-Version' => [Version::VERSION], + 'Content-Type' => ['application/xml; charset=utf-8'], + 'Allow' => ['OPTIONS, GET, HEAD, DELETE, PROPFIND, PUT, PROPPATCH, COPY, MOVE, REPORT'], + ], $this->response->getHeaders()); + + $this->assertEquals(405, $this->response->status, 'Wrong statuscode received. Full response body: ' . $this->response->body); + + } + + /** + * @depends testMKCOLSuccess + * @depends testMKCOLAlreadyExists + */ + function testMKCOLAndProps() { + + $request = new HTTP\Request( + 'MKCOL', + '/testcol', + ['Content-Type' => 'application/xml'] + ); + $request->setBody('<?xml version="1.0"?> +<mkcol xmlns="DAV:"> + <set> + <prop> + <resourcetype><collection /></resourcetype> + <displayname>my new collection</displayname> + </prop> + </set> +</mkcol>'); + $this->server->httpRequest = ($request); + $this->server->exec(); + + $this->assertEquals(207, $this->response->status, 'Wrong statuscode received. Full response body: ' . $this->response->body); + + $this->assertEquals([ + 'X-Sabre-Version' => [Version::VERSION], + 'Content-Type' => ['application/xml; charset=utf-8'], + ], $this->response->getHeaders()); + + $responseBody = $this->response->getBodyAsString(); + + $expected = <<<XML +<?xml version="1.0"?> +<d:multistatus xmlns:d="DAV:" xmlns:s="http://sabredav.org/ns"> + <d:response> + <d:href>/testcol</d:href> + <d:propstat> + <d:prop> + <d:displayname /> + </d:prop> + <d:status>HTTP/1.1 403 Forbidden</d:status> + </d:propstat> + </d:response> +</d:multistatus> +XML; + + $this->assertXmlStringEqualsXmlString( + $expected, + $responseBody + ); + + } + +} diff --git a/vendor/sabre/dav/tests/Sabre/DAV/ServerPluginTest.php b/vendor/sabre/dav/tests/Sabre/DAV/ServerPluginTest.php new file mode 100644 index 000000000..fa67102cc --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/DAV/ServerPluginTest.php @@ -0,0 +1,108 @@ +<?php + +namespace Sabre\DAV; + +use Sabre\HTTP; + +require_once 'Sabre/DAV/AbstractServer.php'; +require_once 'Sabre/DAV/TestPlugin.php'; + +class ServerPluginTest extends AbstractServer { + + /** + * @var Sabre\DAV\TestPlugin + */ + protected $testPlugin; + + function setUp() { + + parent::setUp(); + + $testPlugin = new TestPlugin(); + $this->server->addPlugin($testPlugin); + $this->testPlugin = $testPlugin; + + } + + /** + */ + function testBaseClass() { + + $p = new ServerPluginMock(); + $this->assertEquals([], $p->getFeatures()); + $this->assertEquals([], $p->getHTTPMethods('')); + $this->assertEquals( + [ + 'name' => 'Sabre\DAV\ServerPluginMock', + 'description' => null, + 'link' => null + ], $p->getPluginInfo() + ); + + } + + function testOptions() { + + $serverVars = [ + 'REQUEST_URI' => '/', + 'REQUEST_METHOD' => 'OPTIONS', + ]; + + $request = HTTP\Sapi::createFromServerArray($serverVars); + $this->server->httpRequest = ($request); + $this->server->exec(); + + $this->assertEquals([ + 'DAV' => ['1, 3, extended-mkcol, drinking'], + 'MS-Author-Via' => ['DAV'], + 'Allow' => ['OPTIONS, GET, HEAD, DELETE, PROPFIND, PUT, PROPPATCH, COPY, MOVE, REPORT, BEER, WINE'], + 'Accept-Ranges' => ['bytes'], + 'Content-Length' => ['0'], + 'X-Sabre-Version' => [Version::VERSION], + ], $this->response->getHeaders()); + + $this->assertEquals(200, $this->response->status); + $this->assertEquals('', $this->response->body); + $this->assertEquals('OPTIONS', $this->testPlugin->beforeMethod); + + + } + + function testGetPlugin() { + + $this->assertEquals($this->testPlugin, $this->server->getPlugin(get_class($this->testPlugin))); + + } + + function testUnknownPlugin() { + + $this->assertNull($this->server->getPlugin('SomeRandomClassName')); + + } + + function testGetSupportedReportSet() { + + $this->assertEquals([], $this->testPlugin->getSupportedReportSet('/')); + + } + + function testGetPlugins() { + + $this->assertEquals( + [ + get_class($this->testPlugin) => $this->testPlugin, + 'core' => $this->server->getPlugin('core'), + ], + $this->server->getPlugins() + ); + + } + + +} + +class ServerPluginMock extends ServerPlugin { + + function initialize(Server $s) { } + +} diff --git a/vendor/sabre/dav/tests/Sabre/DAV/ServerPreconditionTest.php b/vendor/sabre/dav/tests/Sabre/DAV/ServerPreconditionTest.php new file mode 100644 index 000000000..203cf26d9 --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/DAV/ServerPreconditionTest.php @@ -0,0 +1,344 @@ +<?php + +namespace Sabre\DAV; + +use Sabre\HTTP; + +require_once 'Sabre/HTTP/ResponseMock.php'; + +class ServerPreconditionsTest extends \PHPUnit_Framework_TestCase { + + /** + * @expectedException Sabre\DAV\Exception\PreconditionFailed + */ + function testIfMatchNoNode() { + + $root = new SimpleCollection('root', [new ServerPreconditionsNode()]); + $server = new Server($root); + $httpRequest = new HTTP\Request('GET', '/bar', ['If-Match' => '*']); + $httpResponse = new HTTP\Response(); + $server->checkPreconditions($httpRequest, $httpResponse); + + } + + /** + */ + function testIfMatchHasNode() { + + $root = new SimpleCollection('root', [new ServerPreconditionsNode()]); + $server = new Server($root); + $httpRequest = new HTTP\Request('GET', '/foo', ['If-Match' => '*']); + $httpResponse = new HTTP\Response(); + $this->assertTrue($server->checkPreconditions($httpRequest, $httpResponse)); + + } + + /** + * @expectedException Sabre\DAV\Exception\PreconditionFailed + */ + function testIfMatchWrongEtag() { + + $root = new SimpleCollection('root', [new ServerPreconditionsNode()]); + $server = new Server($root); + $httpRequest = new HTTP\Request('GET', '/foo', ['If-Match' => '1234']); + $httpResponse = new HTTP\Response(); + $server->checkPreconditions($httpRequest, $httpResponse); + + } + + /** + */ + function testIfMatchCorrectEtag() { + + $root = new SimpleCollection('root', [new ServerPreconditionsNode()]); + $server = new Server($root); + $httpRequest = new HTTP\Request('GET', '/foo', ['If-Match' => '"abc123"']); + $httpResponse = new HTTP\Response(); + $this->assertTrue($server->checkPreconditions($httpRequest, $httpResponse)); + + } + + /** + * Evolution sometimes uses \" instead of " for If-Match headers. + * + * @depends testIfMatchCorrectEtag + */ + function testIfMatchEvolutionEtag() { + + $root = new SimpleCollection('root', [new ServerPreconditionsNode()]); + $server = new Server($root); + $httpRequest = new HTTP\Request('GET', '/foo', ['If-Match' => '\\"abc123\\"']); + $httpResponse = new HTTP\Response(); + $this->assertTrue($server->checkPreconditions($httpRequest, $httpResponse)); + + } + + /** + */ + function testIfMatchMultiple() { + + $root = new SimpleCollection('root', [new ServerPreconditionsNode()]); + $server = new Server($root); + $httpRequest = new HTTP\Request('GET', '/foo', ['If-Match' => '"hellothere", "abc123"']); + $httpResponse = new HTTP\Response(); + $this->assertTrue($server->checkPreconditions($httpRequest, $httpResponse)); + + } + + /** + */ + function testIfNoneMatchNoNode() { + + $root = new SimpleCollection('root', [new ServerPreconditionsNode()]); + $server = new Server($root); + $httpRequest = new HTTP\Request('GET', '/bar', ['If-None-Match' => '*']); + $httpResponse = new HTTP\Response(); + $this->assertTrue($server->checkPreconditions($httpRequest, $httpResponse)); + + } + + /** + * @expectedException Sabre\DAV\Exception\PreconditionFailed + */ + function testIfNoneMatchHasNode() { + + $root = new SimpleCollection('root', [new ServerPreconditionsNode()]); + $server = new Server($root); + $httpRequest = new HTTP\Request('POST', '/foo', ['If-None-Match' => '*']); + $httpResponse = new HTTP\Response(); + $server->checkPreconditions($httpRequest, $httpResponse); + + } + + /** + */ + function testIfNoneMatchWrongEtag() { + + $root = new SimpleCollection('root', [new ServerPreconditionsNode()]); + $server = new Server($root); + $httpRequest = new HTTP\Request('POST', '/foo', ['If-None-Match' => '"1234"']); + $httpResponse = new HTTP\Response(); + $this->assertTrue($server->checkPreconditions($httpRequest, $httpResponse)); + + } + + /** + */ + function testIfNoneMatchWrongEtagMultiple() { + + $root = new SimpleCollection('root', [new ServerPreconditionsNode()]); + $server = new Server($root); + $httpRequest = new HTTP\Request('POST', '/foo', ['If-None-Match' => '"1234", "5678"']); + $httpResponse = new HTTP\Response(); + $this->assertTrue($server->checkPreconditions($httpRequest, $httpResponse)); + + } + + /** + * @expectedException Sabre\DAV\Exception\PreconditionFailed + */ + function testIfNoneMatchCorrectEtag() { + + $root = new SimpleCollection('root', [new ServerPreconditionsNode()]); + $server = new Server($root); + $httpRequest = new HTTP\Request('POST', '/foo', ['If-None-Match' => '"abc123"']); + $httpResponse = new HTTP\Response(); + $server->checkPreconditions($httpRequest, $httpResponse); + + } + + /** + * @expectedException Sabre\DAV\Exception\PreconditionFailed + */ + function testIfNoneMatchCorrectEtagMultiple() { + + $root = new SimpleCollection('root', [new ServerPreconditionsNode()]); + $server = new Server($root); + $httpRequest = new HTTP\Request('POST', '/foo', ['If-None-Match' => '"1234, "abc123"']); + $httpResponse = new HTTP\Response(); + $server->checkPreconditions($httpRequest, $httpResponse); + + } + + /** + */ + function testIfNoneMatchCorrectEtagAsGet() { + + $root = new SimpleCollection('root', [new ServerPreconditionsNode()]); + $server = new Server($root); + $httpRequest = new HTTP\Request('GET', '/foo', ['If-None-Match' => '"abc123"']); + $server->httpResponse = new HTTP\ResponseMock(); + + $this->assertFalse($server->checkPreconditions($httpRequest, $server->httpResponse)); + $this->assertEquals(304, $server->httpResponse->getStatus()); + $this->assertEquals(['ETag' => ['"abc123"']], $server->httpResponse->getHeaders()); + + } + + /** + * This was a test written for issue #515. + */ + function testNoneMatchCorrectEtagEnsureSapiSent() { + + $root = new SimpleCollection('root', [new ServerPreconditionsNode()]); + $server = new Server($root); + $server->sapi = new HTTP\SapiMock(); + HTTP\SapiMock::$sent = 0; + $httpRequest = new HTTP\Request('GET', '/foo', ['If-None-Match' => '"abc123"']); + $server->httpRequest = $httpRequest; + $server->httpResponse = new HTTP\ResponseMock(); + + $server->exec(); + + $this->assertFalse($server->checkPreconditions($httpRequest, $server->httpResponse)); + $this->assertEquals(304, $server->httpResponse->getStatus()); + $this->assertEquals([ + 'ETag' => ['"abc123"'], + 'X-Sabre-Version' => [Version::VERSION], + ], $server->httpResponse->getHeaders()); + $this->assertEquals(1, HTTP\SapiMock::$sent); + + } + + /** + */ + function testIfModifiedSinceUnModified() { + + $root = new SimpleCollection('root', [new ServerPreconditionsNode()]); + $server = new Server($root); + $httpRequest = HTTP\Sapi::createFromServerArray([ + 'HTTP_IF_MODIFIED_SINCE' => 'Sun, 06 Nov 1994 08:49:37 GMT', + 'REQUEST_URI' => '/foo' + ]); + $server->httpResponse = new HTTP\ResponseMock(); + $this->assertFalse($server->checkPreconditions($httpRequest, $server->httpResponse)); + + $this->assertEquals(304, $server->httpResponse->status); + $this->assertEquals([ + 'Last-Modified' => ['Sat, 06 Apr 1985 23:30:00 GMT'], + ], $server->httpResponse->getHeaders()); + + } + + + /** + */ + function testIfModifiedSinceModified() { + + $root = new SimpleCollection('root', [new ServerPreconditionsNode()]); + $server = new Server($root); + $httpRequest = HTTP\Sapi::createFromServerArray([ + 'HTTP_IF_MODIFIED_SINCE' => 'Tue, 06 Nov 1984 08:49:37 GMT', + 'REQUEST_URI' => '/foo' + ]); + + $httpResponse = new HTTP\ResponseMock(); + $this->assertTrue($server->checkPreconditions($httpRequest, $httpResponse)); + + } + + /** + */ + function testIfModifiedSinceInvalidDate() { + + $root = new SimpleCollection('root', [new ServerPreconditionsNode()]); + $server = new Server($root); + $httpRequest = HTTP\Sapi::createFromServerArray([ + 'HTTP_IF_MODIFIED_SINCE' => 'Your mother', + 'REQUEST_URI' => '/foo' + ]); + $httpResponse = new HTTP\ResponseMock(); + + // Invalid dates must be ignored, so this should return true + $this->assertTrue($server->checkPreconditions($httpRequest, $httpResponse)); + + } + + /** + */ + function testIfModifiedSinceInvalidDate2() { + + $root = new SimpleCollection('root', [new ServerPreconditionsNode()]); + $server = new Server($root); + $httpRequest = HTTP\Sapi::createFromServerArray([ + 'HTTP_IF_MODIFIED_SINCE' => 'Sun, 06 Nov 1994 08:49:37 EST', + 'REQUEST_URI' => '/foo' + ]); + $httpResponse = new HTTP\ResponseMock(); + $this->assertTrue($server->checkPreconditions($httpRequest, $httpResponse)); + + } + + + /** + */ + function testIfUnmodifiedSinceUnModified() { + + $root = new SimpleCollection('root', [new ServerPreconditionsNode()]); + $server = new Server($root); + $httpRequest = HTTP\Sapi::createFromServerArray([ + 'HTTP_IF_UNMODIFIED_SINCE' => 'Sun, 06 Nov 1994 08:49:37 GMT', + 'REQUEST_URI' => '/foo' + ]); + $httpResponse = new HTTP\Response(); + $this->assertTrue($server->checkPreconditions($httpRequest, $httpResponse)); + + } + + + /** + * @expectedException Sabre\DAV\Exception\PreconditionFailed + */ + function testIfUnmodifiedSinceModified() { + + $root = new SimpleCollection('root', [new ServerPreconditionsNode()]); + $server = new Server($root); + $httpRequest = HTTP\Sapi::createFromServerArray([ + 'HTTP_IF_UNMODIFIED_SINCE' => 'Tue, 06 Nov 1984 08:49:37 GMT', + 'REQUEST_URI' => '/foo' + ]); + $httpResponse = new HTTP\ResponseMock(); + $server->checkPreconditions($httpRequest, $httpResponse); + + } + + /** + */ + function testIfUnmodifiedSinceInvalidDate() { + + $root = new SimpleCollection('root', [new ServerPreconditionsNode()]); + $server = new Server($root); + $httpRequest = HTTP\Sapi::createFromServerArray([ + 'HTTP_IF_UNMODIFIED_SINCE' => 'Sun, 06 Nov 1984 08:49:37 CET', + 'REQUEST_URI' => '/foo' + ]); + $httpResponse = new HTTP\ResponseMock(); + $this->assertTrue($server->checkPreconditions($httpRequest, $httpResponse)); + + } + + +} + +class ServerPreconditionsNode extends File { + + function getETag() { + + return '"abc123"'; + + } + + function getLastModified() { + + /* my birthday & time, I believe */ + return strtotime('1985-04-07 01:30 +02:00'); + + } + + function getName() { + + return 'foo'; + + } + +} diff --git a/vendor/sabre/dav/tests/Sabre/DAV/ServerPropsInfiniteDepthTest.php b/vendor/sabre/dav/tests/Sabre/DAV/ServerPropsInfiniteDepthTest.php new file mode 100644 index 000000000..f51765169 --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/DAV/ServerPropsInfiniteDepthTest.php @@ -0,0 +1,217 @@ +<?php + +namespace Sabre\DAV; + +use Sabre\HTTP; + +require_once 'Sabre/DAV/AbstractServer.php'; + +class ServerPropsInfiniteDepthTest extends AbstractServer { + + protected function getRootNode() { + + return new FSExt\Directory(SABRE_TEMPDIR); + + } + + function setUp() { + + if (file_exists(SABRE_TEMPDIR . '../.sabredav')) unlink(SABRE_TEMPDIR . '../.sabredav'); + parent::setUp(); + file_put_contents(SABRE_TEMPDIR . '/test2.txt', 'Test contents2'); + mkdir(SABRE_TEMPDIR . '/col'); + mkdir(SABRE_TEMPDIR . '/col/col'); + file_put_contents(SABRE_TEMPDIR . 'col/col/test.txt', 'Test contents'); + $this->server->addPlugin(new Locks\Plugin(new Locks\Backend\File(SABRE_TEMPDIR . '/.locksdb'))); + $this->server->enablePropfindDepthInfinity = true; + + } + + function tearDown() { + + parent::tearDown(); + if (file_exists(SABRE_TEMPDIR . '../.locksdb')) unlink(SABRE_TEMPDIR . '../.locksdb'); + + } + + private function sendRequest($body) { + + $request = new HTTP\Request('PROPFIND', '/', ['Depth' => 'infinity']); + $request->setBody($body); + + $this->server->httpRequest = $request; + $this->server->exec(); + + } + + function testPropFindEmptyBody() { + + $this->sendRequest(""); + + $this->assertEquals(207, $this->response->status, 'Incorrect status received. Full response body: ' . $this->response->getBodyAsString()); + + $this->assertEquals([ + 'X-Sabre-Version' => [Version::VERSION], + 'Content-Type' => ['application/xml; charset=utf-8'], + 'DAV' => ['1, 3, extended-mkcol, 2'], + 'Vary' => ['Brief,Prefer'], + ], + $this->response->getHeaders() + ); + + $body = preg_replace("/xmlns(:[A-Za-z0-9_])?=(\"|\')DAV:(\"|\')/", "xmlns\\1=\"urn:DAV\"", $this->response->body); + $xml = simplexml_load_string($body); + $xml->registerXPathNamespace('d', 'urn:DAV'); + + list($data) = $xml->xpath('/d:multistatus/d:response/d:href'); + $this->assertEquals('/', (string)$data, 'href element should have been /'); + + $data = $xml->xpath('/d:multistatus/d:response/d:propstat/d:prop/d:resourcetype'); + // 8 resources are to be returned: /, col, col/col, col/col/test.txt, dir, dir/child.txt, test.txt and test2.txt + $this->assertEquals(8, count($data)); + + } + + function testSupportedLocks() { + + $xml = '<?xml version="1.0"?> +<d:propfind xmlns:d="DAV:"> + <d:prop> + <d:supportedlock /> + </d:prop> +</d:propfind>'; + + $this->sendRequest($xml); + + $body = $this->response->getBodyAsString(); + $this->assertEquals(207, $this->response->getStatus(), $body); + + $body = preg_replace("/xmlns(:[A-Za-z0-9_])?=(\"|\')DAV:(\"|\')/", "xmlns\\1=\"urn:DAV\"", $body); + $xml = simplexml_load_string($body); + $xml->registerXPathNamespace('d', 'urn:DAV'); + + $data = $xml->xpath('/d:multistatus/d:response/d:propstat/d:prop/d:supportedlock/d:lockentry'); + $this->assertEquals(16, count($data), 'We expected sixteen \'d:lockentry\' tags'); + + $data = $xml->xpath('/d:multistatus/d:response/d:propstat/d:prop/d:supportedlock/d:lockentry/d:lockscope'); + $this->assertEquals(16, count($data), 'We expected sixteen \'d:lockscope\' tags'); + + $data = $xml->xpath('/d:multistatus/d:response/d:propstat/d:prop/d:supportedlock/d:lockentry/d:locktype'); + $this->assertEquals(16, count($data), 'We expected sixteen \'d:locktype\' tags'); + + $data = $xml->xpath('/d:multistatus/d:response/d:propstat/d:prop/d:supportedlock/d:lockentry/d:lockscope/d:shared'); + $this->assertEquals(8, count($data), 'We expected eight \'d:shared\' tags'); + + $data = $xml->xpath('/d:multistatus/d:response/d:propstat/d:prop/d:supportedlock/d:lockentry/d:lockscope/d:exclusive'); + $this->assertEquals(8, count($data), 'We expected eight \'d:exclusive\' tags'); + + $data = $xml->xpath('/d:multistatus/d:response/d:propstat/d:prop/d:supportedlock/d:lockentry/d:locktype/d:write'); + $this->assertEquals(16, count($data), 'We expected sixteen \'d:write\' tags'); + } + + function testLockDiscovery() { + + $xml = '<?xml version="1.0"?> +<d:propfind xmlns:d="DAV:"> + <d:prop> + <d:lockdiscovery /> + </d:prop> +</d:propfind>'; + + $this->sendRequest($xml); + + $body = preg_replace("/xmlns(:[A-Za-z0-9_])?=(\"|\')DAV:(\"|\')/", "xmlns\\1=\"urn:DAV\"", $this->response->body); + $xml = simplexml_load_string($body); + $xml->registerXPathNamespace('d', 'urn:DAV'); + + $data = $xml->xpath('/d:multistatus/d:response/d:propstat/d:prop/d:lockdiscovery'); + $this->assertEquals(8, count($data), 'We expected eight \'d:lockdiscovery\' tags'); + + } + + function testUnknownProperty() { + + $xml = '<?xml version="1.0"?> +<d:propfind xmlns:d="DAV:"> + <d:prop> + <d:macaroni /> + </d:prop> +</d:propfind>'; + + $this->sendRequest($xml); + $body = preg_replace("/xmlns(:[A-Za-z0-9_])?=(\"|\')DAV:(\"|\')/", "xmlns\\1=\"urn:DAV\"", $this->response->body); + $xml = simplexml_load_string($body); + $xml->registerXPathNamespace('d', 'urn:DAV'); + $pathTests = [ + '/d:multistatus', + '/d:multistatus/d:response', + '/d:multistatus/d:response/d:propstat', + '/d:multistatus/d:response/d:propstat/d:status', + '/d:multistatus/d:response/d:propstat/d:prop', + '/d:multistatus/d:response/d:propstat/d:prop/d:macaroni', + ]; + foreach ($pathTests as $test) { + $this->assertTrue(count($xml->xpath($test)) == true, 'We expected the ' . $test . ' element to appear in the response, we got: ' . $body); + } + + $val = $xml->xpath('/d:multistatus/d:response/d:propstat/d:status'); + $this->assertEquals(8, count($val), $body); + $this->assertEquals('HTTP/1.1 404 Not Found', (string)$val[0]); + + } + + function testFilesThatAreSiblingsOfDirectoriesShouldBeReportedAsFiles() { + + $xml = '<?xml version="1.0"?> +<d:propfind xmlns:d="DAV:"> + <d:prop> + <d:resourcetype /> + </d:prop> +</d:propfind>'; + + $this->sendRequest($xml); + $body = preg_replace("/xmlns(:[A-Za-z0-9_])?=(\"|\')DAV:(\"|\')/", "xmlns\\1=\"urn:DAV\"", $this->response->body); + $xml = simplexml_load_string($body); + $xml->registerXPathNamespace('d', 'urn:DAV'); + $pathTests = [ + '/d:multistatus', + '/d:multistatus/d:response', + '/d:multistatus/d:response/d:href', + '/d:multistatus/d:response/d:propstat', + '/d:multistatus/d:response/d:propstat/d:status', + '/d:multistatus/d:response/d:propstat/d:prop', + '/d:multistatus/d:response/d:propstat/d:prop/d:resourcetype', + ]; + + $hrefPaths = []; + + foreach ($pathTests as $test) { + $this->assertTrue(count($xml->xpath($test)) == true, 'We expected the ' . $test . ' element to appear in the response, we got: ' . $body); + + if ($test === '/d:multistatus/d:response/d:href') { + foreach ($xml->xpath($test) as $thing) { + /** @var \SimpleXMLElement $thing */ + $hrefPaths[] = strip_tags($thing->asXML()); + } + } elseif ($test === '/d:multistatus/d:response/d:propstat/d:prop/d:resourcetype') { + $count = 0; + foreach ($xml->xpath($test) as $thing) { + /** @var \SimpleXMLElement $thing */ + if (substr($hrefPaths[$count], -4) !== '.txt') { + $this->assertEquals('<d:resourcetype><d:collection/></d:resourcetype>', $thing->asXML(), 'Path ' . $hrefPaths[$count] . ' is not reported as a directory'); + } else { + $this->assertEquals('<d:resourcetype/>', $thing->asXML(), 'Path ' . $hrefPaths[$count] . ' is not reported as a file'); + } + + $count++; + } + } + } + + $val = $xml->xpath('/d:multistatus/d:response/d:propstat/d:status'); + $this->assertEquals(8, count($val), $body); + $this->assertEquals('HTTP/1.1 200 OK', (string)$val[0]); + + } + +} diff --git a/vendor/sabre/dav/tests/Sabre/DAV/ServerPropsTest.php b/vendor/sabre/dav/tests/Sabre/DAV/ServerPropsTest.php new file mode 100644 index 000000000..253200be7 --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/DAV/ServerPropsTest.php @@ -0,0 +1,201 @@ +<?php + +namespace Sabre\DAV; + +use Sabre\HTTP; + +require_once 'Sabre/HTTP/ResponseMock.php'; +require_once 'Sabre/DAV/AbstractServer.php'; + +class ServerPropsTest extends AbstractServer { + + protected function getRootNode() { + + return new FSExt\Directory(SABRE_TEMPDIR); + + } + + function setUp() { + + if (file_exists(SABRE_TEMPDIR . '../.sabredav')) unlink(SABRE_TEMPDIR . '../.sabredav'); + parent::setUp(); + file_put_contents(SABRE_TEMPDIR . '/test2.txt', 'Test contents2'); + mkdir(SABRE_TEMPDIR . '/col'); + file_put_contents(SABRE_TEMPDIR . 'col/test.txt', 'Test contents'); + $this->server->addPlugin(new Locks\Plugin(new Locks\Backend\File(SABRE_TEMPDIR . '/.locksdb'))); + + } + + function tearDown() { + + parent::tearDown(); + if (file_exists(SABRE_TEMPDIR . '../.locksdb')) unlink(SABRE_TEMPDIR . '../.locksdb'); + + } + + private function sendRequest($body, $path = '/', $headers = ['Depth' => '0']) { + + $request = new HTTP\Request('PROPFIND', $path, $headers, $body); + + $this->server->httpRequest = $request; + $this->server->exec(); + + } + + function testPropFindEmptyBody() { + + $this->sendRequest(""); + $this->assertEquals(207, $this->response->status); + + $this->assertEquals([ + 'X-Sabre-Version' => [Version::VERSION], + 'Content-Type' => ['application/xml; charset=utf-8'], + 'DAV' => ['1, 3, extended-mkcol, 2'], + 'Vary' => ['Brief,Prefer'], + ], + $this->response->getHeaders() + ); + + $body = preg_replace("/xmlns(:[A-Za-z0-9_])?=(\"|\')DAV:(\"|\')/", "xmlns\\1=\"urn:DAV\"", $this->response->body); + $xml = simplexml_load_string($body); + $xml->registerXPathNamespace('d', 'urn:DAV'); + + list($data) = $xml->xpath('/d:multistatus/d:response/d:href'); + $this->assertEquals('/', (string)$data, 'href element should have been /'); + + $data = $xml->xpath('/d:multistatus/d:response/d:propstat/d:prop/d:resourcetype'); + $this->assertEquals(1, count($data)); + + } + + function testPropFindEmptyBodyFile() { + + $this->sendRequest("", '/test2.txt', []); + $this->assertEquals(207, $this->response->status); + + $this->assertEquals([ + 'X-Sabre-Version' => [Version::VERSION], + 'Content-Type' => ['application/xml; charset=utf-8'], + 'DAV' => ['1, 3, extended-mkcol, 2'], + 'Vary' => ['Brief,Prefer'], + ], + $this->response->getHeaders() + ); + + $body = preg_replace("/xmlns(:[A-Za-z0-9_])?=(\"|\')DAV:(\"|\')/", "xmlns\\1=\"urn:DAV\"", $this->response->body); + $xml = simplexml_load_string($body); + $xml->registerXPathNamespace('d', 'urn:DAV'); + + list($data) = $xml->xpath('/d:multistatus/d:response/d:href'); + $this->assertEquals('/test2.txt', (string)$data, 'href element should have been /test2.txt'); + + $data = $xml->xpath('/d:multistatus/d:response/d:propstat/d:prop/d:getcontentlength'); + $this->assertEquals(1, count($data)); + + } + + function testSupportedLocks() { + + $xml = '<?xml version="1.0"?> +<d:propfind xmlns:d="DAV:"> + <d:prop> + <d:supportedlock /> + </d:prop> +</d:propfind>'; + + $this->sendRequest($xml); + + $body = preg_replace("/xmlns(:[A-Za-z0-9_])?=(\"|\')DAV:(\"|\')/", "xmlns\\1=\"urn:DAV\"", $this->response->body); + $xml = simplexml_load_string($body); + $xml->registerXPathNamespace('d', 'urn:DAV'); + + $data = $xml->xpath('/d:multistatus/d:response/d:propstat/d:prop/d:supportedlock/d:lockentry'); + $this->assertEquals(2, count($data), 'We expected two \'d:lockentry\' tags'); + + $data = $xml->xpath('/d:multistatus/d:response/d:propstat/d:prop/d:supportedlock/d:lockentry/d:lockscope'); + $this->assertEquals(2, count($data), 'We expected two \'d:lockscope\' tags'); + + $data = $xml->xpath('/d:multistatus/d:response/d:propstat/d:prop/d:supportedlock/d:lockentry/d:locktype'); + $this->assertEquals(2, count($data), 'We expected two \'d:locktype\' tags'); + + $data = $xml->xpath('/d:multistatus/d:response/d:propstat/d:prop/d:supportedlock/d:lockentry/d:lockscope/d:shared'); + $this->assertEquals(1, count($data), 'We expected a \'d:shared\' tag'); + + $data = $xml->xpath('/d:multistatus/d:response/d:propstat/d:prop/d:supportedlock/d:lockentry/d:lockscope/d:exclusive'); + $this->assertEquals(1, count($data), 'We expected a \'d:exclusive\' tag'); + + $data = $xml->xpath('/d:multistatus/d:response/d:propstat/d:prop/d:supportedlock/d:lockentry/d:locktype/d:write'); + $this->assertEquals(2, count($data), 'We expected two \'d:write\' tags'); + } + + function testLockDiscovery() { + + $xml = '<?xml version="1.0"?> +<d:propfind xmlns:d="DAV:"> + <d:prop> + <d:lockdiscovery /> + </d:prop> +</d:propfind>'; + + $this->sendRequest($xml); + + $body = preg_replace("/xmlns(:[A-Za-z0-9_])?=(\"|\')DAV:(\"|\')/", "xmlns\\1=\"urn:DAV\"", $this->response->body); + $xml = simplexml_load_string($body); + $xml->registerXPathNamespace('d', 'urn:DAV'); + + $data = $xml->xpath('/d:multistatus/d:response/d:propstat/d:prop/d:lockdiscovery'); + $this->assertEquals(1, count($data), 'We expected a \'d:lockdiscovery\' tag'); + + } + + function testUnknownProperty() { + + $xml = '<?xml version="1.0"?> +<d:propfind xmlns:d="DAV:"> + <d:prop> + <d:macaroni /> + </d:prop> +</d:propfind>'; + + $this->sendRequest($xml); + $body = preg_replace("/xmlns(:[A-Za-z0-9_])?=(\"|\')DAV:(\"|\')/", "xmlns\\1=\"urn:DAV\"", $this->response->body); + $xml = simplexml_load_string($body); + $xml->registerXPathNamespace('d', 'urn:DAV'); + $pathTests = [ + '/d:multistatus', + '/d:multistatus/d:response', + '/d:multistatus/d:response/d:propstat', + '/d:multistatus/d:response/d:propstat/d:status', + '/d:multistatus/d:response/d:propstat/d:prop', + '/d:multistatus/d:response/d:propstat/d:prop/d:macaroni', + ]; + foreach ($pathTests as $test) { + $this->assertTrue(count($xml->xpath($test)) == true, 'We expected the ' . $test . ' element to appear in the response, we got: ' . $body); + } + + $val = $xml->xpath('/d:multistatus/d:response/d:propstat/d:status'); + $this->assertEquals(1, count($val), $body); + $this->assertEquals('HTTP/1.1 404 Not Found', (string)$val[0]); + + } + + function testParsePropPatchRequest() { + + $body = '<?xml version="1.0"?> +<d:propertyupdate xmlns:d="DAV:" xmlns:s="http://sabredav.org/NS/test"> + <d:set><d:prop><s:someprop>somevalue</s:someprop></d:prop></d:set> + <d:remove><d:prop><s:someprop2 /></d:prop></d:remove> + <d:set><d:prop><s:someprop3>removeme</s:someprop3></d:prop></d:set> + <d:remove><d:prop><s:someprop3 /></d:prop></d:remove> +</d:propertyupdate>'; + + $result = $this->server->xml->parse($body); + $this->assertEquals([ + '{http://sabredav.org/NS/test}someprop' => 'somevalue', + '{http://sabredav.org/NS/test}someprop2' => null, + '{http://sabredav.org/NS/test}someprop3' => null, + ], $result->properties); + + } + +} diff --git a/vendor/sabre/dav/tests/Sabre/DAV/ServerRangeTest.php b/vendor/sabre/dav/tests/Sabre/DAV/ServerRangeTest.php new file mode 100644 index 000000000..81224d687 --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/DAV/ServerRangeTest.php @@ -0,0 +1,262 @@ +<?php + +namespace Sabre\DAV; + +use DateTime; +use Sabre\HTTP; + +/** + * This file tests HTTP requests that use the Range: header. + * + * @copyright Copyright (C) fruux GmbH. (https://fruux.com/) + * @author Evert Pot (http://evertpot.com/) + * @license http://sabre.io/license/ Modified BSD License + */ +class ServerRangeTest extends \Sabre\DAVServerTest { + + protected $setupFiles = true; + + /** + * We need this string a lot + */ + protected $lastModified; + + function setUp() { + + parent::setUp(); + $this->server->createFile('files/test.txt', 'Test contents'); + + $this->lastModified = HTTP\Util::toHTTPDate( + new DateTime('@' . $this->server->tree->getNodeForPath('files/test.txt')->getLastModified()) + ); + + $stream = popen('echo "Test contents"', 'r'); + $streamingFile = new Mock\StreamingFile( + 'no-seeking.txt', + $stream + ); + $streamingFile->setSize(12); + $this->server->tree->getNodeForPath('files')->addNode($streamingFile); + + } + + function testRange() { + + $request = new HTTP\Request('GET', '/files/test.txt', ['Range' => 'bytes=2-5']); + $response = $this->request($request); + + $this->assertEquals([ + 'X-Sabre-Version' => [Version::VERSION], + 'Content-Type' => ['application/octet-stream'], + 'Content-Length' => [4], + 'Content-Range' => ['bytes 2-5/13'], + 'ETag' => ['"' . md5('Test contents') . '"'], + 'Last-Modified' => [$this->lastModified], + ], + $response->getHeaders() + ); + $this->assertEquals(206, $response->getStatus()); + $this->assertEquals('st c', $response->getBodyAsString()); + + } + + /** + * @depends testRange + */ + function testStartRange() { + + $request = new HTTP\Request('GET', '/files/test.txt', ['Range' => 'bytes=2-']); + $response = $this->request($request); + + $this->assertEquals([ + 'X-Sabre-Version' => [Version::VERSION], + 'Content-Type' => ['application/octet-stream'], + 'Content-Length' => [11], + 'Content-Range' => ['bytes 2-12/13'], + 'ETag' => ['"' . md5('Test contents') . '"'], + 'Last-Modified' => [$this->lastModified], + ], + $response->getHeaders() + ); + + $this->assertEquals(206, $response->getStatus()); + $this->assertEquals('st contents', $response->getBodyAsString()); + + } + + /** + * @depends testRange + */ + function testEndRange() { + + $request = new HTTP\Request('GET', '/files/test.txt', ['Range' => 'bytes=-8']); + $response = $this->request($request); + + $this->assertEquals([ + 'X-Sabre-Version' => [Version::VERSION], + 'Content-Type' => ['application/octet-stream'], + 'Content-Length' => [8], + 'Content-Range' => ['bytes 5-12/13'], + 'ETag' => ['"' . md5('Test contents') . '"'], + 'Last-Modified' => [$this->lastModified], + ], + $response->getHeaders() + ); + + $this->assertEquals(206, $response->getStatus()); + $this->assertEquals('contents', $response->getBodyAsString()); + + } + + /** + * @depends testRange + */ + function testTooHighRange() { + + $request = new HTTP\Request('GET', '/files/test.txt', ['Range' => 'bytes=100-200']); + $response = $this->request($request); + + $this->assertEquals(416, $response->getStatus()); + + } + + /** + * @depends testRange + */ + function testCrazyRange() { + + $request = new HTTP\Request('GET', '/files/test.txt', ['Range' => 'bytes=8-4']); + $response = $this->request($request); + + $this->assertEquals(416, $response->getStatus()); + + } + + function testNonSeekableStream() { + + $request = new HTTP\Request('GET', '/files/no-seeking.txt', ['Range' => 'bytes=2-5']); + $response = $this->request($request); + + $this->assertEquals(206, $response->getStatus(), $response); + $this->assertEquals([ + 'X-Sabre-Version' => [Version::VERSION], + 'Content-Type' => ['application/octet-stream'], + 'Content-Length' => [4], + 'Content-Range' => ['bytes 2-5/12'], + // 'ETag' => ['"' . md5('Test contents') . '"'], + 'Last-Modified' => [$this->lastModified], + ], + $response->getHeaders() + ); + + $this->assertEquals('st c', $response->getBodyAsString()); + + } + + /** + * @depends testRange + */ + function testIfRangeEtag() { + + $request = new HTTP\Request('GET', '/files/test.txt', [ + 'Range' => 'bytes=2-5', + 'If-Range' => '"' . md5('Test contents') . '"', + ]); + $response = $this->request($request); + + $this->assertEquals([ + 'X-Sabre-Version' => [Version::VERSION], + 'Content-Type' => ['application/octet-stream'], + 'Content-Length' => [4], + 'Content-Range' => ['bytes 2-5/13'], + 'ETag' => ['"' . md5('Test contents') . '"'], + 'Last-Modified' => [$this->lastModified], + ], + $response->getHeaders() + ); + + $this->assertEquals(206, $response->getStatus()); + $this->assertEquals('st c', $response->getBodyAsString()); + + } + + /** + * @depends testIfRangeEtag + */ + function testIfRangeEtagIncorrect() { + + $request = new HTTP\Request('GET', '/files/test.txt', [ + 'Range' => 'bytes=2-5', + 'If-Range' => '"foobar"', + ]); + $response = $this->request($request); + + $this->assertEquals([ + 'X-Sabre-Version' => [Version::VERSION], + 'Content-Type' => ['application/octet-stream'], + 'Content-Length' => [13], + 'ETag' => ['"' . md5('Test contents') . '"'], + 'Last-Modified' => [$this->lastModified], + ], + $response->getHeaders() + ); + + $this->assertEquals(200, $response->getStatus()); + $this->assertEquals('Test contents', $response->getBodyAsString()); + + } + + /** + * @depends testIfRangeEtag + */ + function testIfRangeModificationDate() { + + $request = new HTTP\Request('GET', '/files/test.txt', [ + 'Range' => 'bytes=2-5', + 'If-Range' => 'tomorrow', + ]); + $response = $this->request($request); + + $this->assertEquals([ + 'X-Sabre-Version' => [Version::VERSION], + 'Content-Type' => ['application/octet-stream'], + 'Content-Length' => [4], + 'Content-Range' => ['bytes 2-5/13'], + 'ETag' => ['"' . md5('Test contents') . '"'], + 'Last-Modified' => [$this->lastModified], + ], + $response->getHeaders() + ); + + $this->assertEquals(206, $response->getStatus()); + $this->assertEquals('st c', $response->getBodyAsString()); + + } + + /** + * @depends testIfRangeModificationDate + */ + function testIfRangeModificationDateModified() { + + $request = new HTTP\Request('GET', '/files/test.txt', [ + 'Range' => 'bytes=2-5', + 'If-Range' => '-2 years', + ]); + $response = $this->request($request); + + $this->assertEquals([ + 'X-Sabre-Version' => [Version::VERSION], + 'Content-Type' => ['application/octet-stream'], + 'Content-Length' => [13], + 'ETag' => ['"' . md5('Test contents') . '"'], + 'Last-Modified' => [$this->lastModified], + ], + $response->getHeaders() + ); + + $this->assertEquals(200, $response->getStatus()); + $this->assertEquals('Test contents', $response->getBodyAsString()); + + } + +} diff --git a/vendor/sabre/dav/tests/Sabre/DAV/ServerSimpleTest.php b/vendor/sabre/dav/tests/Sabre/DAV/ServerSimpleTest.php new file mode 100644 index 000000000..043179a00 --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/DAV/ServerSimpleTest.php @@ -0,0 +1,475 @@ +<?php + +namespace Sabre\DAV; + +use Sabre\HTTP; + +class ServerSimpleTest extends AbstractServer{ + + function testConstructArray() { + + $nodes = [ + new SimpleCollection('hello') + ]; + + $server = new Server($nodes); + $this->assertEquals($nodes[0], $server->tree->getNodeForPath('hello')); + + } + + /** + * @expectedException Sabre\DAV\Exception + */ + function testConstructIncorrectObj() { + + $nodes = [ + new SimpleCollection('hello'), + new \STDClass(), + ]; + + $server = new Server($nodes); + + } + + /** + * @expectedException Sabre\DAV\Exception + */ + function testConstructInvalidArg() { + + $server = new Server(1); + + } + + function testOptions() { + + $request = new HTTP\Request('OPTIONS', '/'); + $this->server->httpRequest = $request; + $this->server->exec(); + + $this->assertEquals([ + 'DAV' => ['1, 3, extended-mkcol'], + 'MS-Author-Via' => ['DAV'], + 'Allow' => ['OPTIONS, GET, HEAD, DELETE, PROPFIND, PUT, PROPPATCH, COPY, MOVE, REPORT'], + 'Accept-Ranges' => ['bytes'], + 'Content-Length' => ['0'], + 'X-Sabre-Version' => [Version::VERSION], + ], $this->response->getHeaders()); + + $this->assertEquals(200, $this->response->status); + $this->assertEquals('', $this->response->body); + + } + + function testOptionsUnmapped() { + + $request = new HTTP\Request('OPTIONS', '/unmapped'); + $this->server->httpRequest = $request; + + $this->server->exec(); + + $this->assertEquals([ + 'DAV' => ['1, 3, extended-mkcol'], + 'MS-Author-Via' => ['DAV'], + 'Allow' => ['OPTIONS, GET, HEAD, DELETE, PROPFIND, PUT, PROPPATCH, COPY, MOVE, REPORT, MKCOL'], + 'Accept-Ranges' => ['bytes'], + 'Content-Length' => ['0'], + 'X-Sabre-Version' => [Version::VERSION], + ], $this->response->getHeaders()); + + $this->assertEquals(200, $this->response->status); + $this->assertEquals('', $this->response->body); + + } + + function testNonExistantMethod() { + + $serverVars = [ + 'REQUEST_URI' => '/', + 'REQUEST_METHOD' => 'BLABLA', + ]; + + $request = HTTP\Sapi::createFromServerArray($serverVars); + $this->server->httpRequest = ($request); + $this->server->exec(); + + $this->assertEquals([ + 'X-Sabre-Version' => [Version::VERSION], + 'Content-Type' => ['application/xml; charset=utf-8'], + ], $this->response->getHeaders()); + + $this->assertEquals(501, $this->response->status); + + + } + + function testBaseUri() { + + $serverVars = [ + 'REQUEST_URI' => '/blabla/test.txt', + 'REQUEST_METHOD' => 'GET', + ]; + $filename = $this->tempDir . '/test.txt'; + + $request = HTTP\Sapi::createFromServerArray($serverVars); + $this->server->setBaseUri('/blabla/'); + $this->assertEquals('/blabla/', $this->server->getBaseUri()); + $this->server->httpRequest = ($request); + $this->server->exec(); + + $this->assertEquals([ + 'X-Sabre-Version' => [Version::VERSION], + 'Content-Type' => ['application/octet-stream'], + 'Content-Length' => [13], + 'Last-Modified' => [HTTP\Util::toHTTPDate(new \DateTime('@' . filemtime($filename)))], + 'ETag' => ['"' . sha1(fileinode($filename) . filesize($filename) . filemtime($filename)) . '"'], + ], + $this->response->getHeaders() + ); + + $this->assertEquals(200, $this->response->status); + $this->assertEquals('Test contents', stream_get_contents($this->response->body)); + + } + + function testBaseUriAddSlash() { + + $tests = [ + '/' => '/', + '/foo' => '/foo/', + '/foo/' => '/foo/', + '/foo/bar' => '/foo/bar/', + '/foo/bar/' => '/foo/bar/', + ]; + + foreach ($tests as $test => $result) { + $this->server->setBaseUri($test); + + $this->assertEquals($result, $this->server->getBaseUri()); + + } + + } + + function testCalculateUri() { + + $uris = [ + 'http://www.example.org/root/somepath', + '/root/somepath', + '/root/somepath/', + ]; + + $this->server->setBaseUri('/root/'); + + foreach ($uris as $uri) { + + $this->assertEquals('somepath', $this->server->calculateUri($uri)); + + } + + $this->server->setBaseUri('/root'); + + foreach ($uris as $uri) { + + $this->assertEquals('somepath', $this->server->calculateUri($uri)); + + } + + $this->assertEquals('', $this->server->calculateUri('/root')); + + } + + function testCalculateUriSpecialChars() { + + $uris = [ + 'http://www.example.org/root/%C3%A0fo%C3%B3', + '/root/%C3%A0fo%C3%B3', + '/root/%C3%A0fo%C3%B3/' + ]; + + $this->server->setBaseUri('/root/'); + + foreach ($uris as $uri) { + + $this->assertEquals("\xc3\xa0fo\xc3\xb3", $this->server->calculateUri($uri)); + + } + + $this->server->setBaseUri('/root'); + + foreach ($uris as $uri) { + + $this->assertEquals("\xc3\xa0fo\xc3\xb3", $this->server->calculateUri($uri)); + + } + + $this->server->setBaseUri('/'); + + foreach ($uris as $uri) { + + $this->assertEquals("root/\xc3\xa0fo\xc3\xb3", $this->server->calculateUri($uri)); + + } + + } + + /** + * @expectedException \Sabre\DAV\Exception\Forbidden + */ + function testCalculateUriBreakout() { + + $uri = '/path1/'; + + $this->server->setBaseUri('/path2/'); + $this->server->calculateUri($uri); + + } + + /** + */ + function testGuessBaseUri() { + + $serverVars = [ + 'REQUEST_URI' => '/index.php/root', + 'PATH_INFO' => '/root', + ]; + + $httpRequest = HTTP\Sapi::createFromServerArray($serverVars); + $server = new Server(); + $server->httpRequest = $httpRequest; + + $this->assertEquals('/index.php/', $server->guessBaseUri()); + + } + + /** + * @depends testGuessBaseUri + */ + function testGuessBaseUriPercentEncoding() { + + $serverVars = [ + 'REQUEST_URI' => '/index.php/dir/path2/path%20with%20spaces', + 'PATH_INFO' => '/dir/path2/path with spaces', + ]; + + $httpRequest = HTTP\Sapi::createFromServerArray($serverVars); + $server = new Server(); + $server->httpRequest = $httpRequest; + + $this->assertEquals('/index.php/', $server->guessBaseUri()); + + } + + /** + * @depends testGuessBaseUri + */ + /* + function testGuessBaseUriPercentEncoding2() { + + $this->markTestIncomplete('This behaviour is not yet implemented'); + $serverVars = [ + 'REQUEST_URI' => '/some%20directory+mixed/index.php/dir/path2/path%20with%20spaces', + 'PATH_INFO' => '/dir/path2/path with spaces', + ]; + + $httpRequest = HTTP\Sapi::createFromServerArray($serverVars); + $server = new Server(); + $server->httpRequest = $httpRequest; + + $this->assertEquals('/some%20directory+mixed/index.php/', $server->guessBaseUri()); + + }*/ + + function testGuessBaseUri2() { + + $serverVars = [ + 'REQUEST_URI' => '/index.php/root/', + 'PATH_INFO' => '/root/', + ]; + + $httpRequest = HTTP\Sapi::createFromServerArray($serverVars); + $server = new Server(); + $server->httpRequest = $httpRequest; + + $this->assertEquals('/index.php/', $server->guessBaseUri()); + + } + + function testGuessBaseUriNoPathInfo() { + + $serverVars = [ + 'REQUEST_URI' => '/index.php/root', + ]; + + $httpRequest = HTTP\Sapi::createFromServerArray($serverVars); + $server = new Server(); + $server->httpRequest = $httpRequest; + + $this->assertEquals('/', $server->guessBaseUri()); + + } + + function testGuessBaseUriNoPathInfo2() { + + $serverVars = [ + 'REQUEST_URI' => '/a/b/c/test.php', + ]; + + $httpRequest = HTTP\Sapi::createFromServerArray($serverVars); + $server = new Server(); + $server->httpRequest = $httpRequest; + + $this->assertEquals('/', $server->guessBaseUri()); + + } + + + /** + * @depends testGuessBaseUri + */ + function testGuessBaseUriQueryString() { + + $serverVars = [ + 'REQUEST_URI' => '/index.php/root?query_string=blabla', + 'PATH_INFO' => '/root', + ]; + + $httpRequest = HTTP\Sapi::createFromServerArray($serverVars); + $server = new Server(); + $server->httpRequest = $httpRequest; + + $this->assertEquals('/index.php/', $server->guessBaseUri()); + + } + + /** + * @depends testGuessBaseUri + * @expectedException \Sabre\DAV\Exception + */ + function testGuessBaseUriBadConfig() { + + $serverVars = [ + 'REQUEST_URI' => '/index.php/root/heyyy', + 'PATH_INFO' => '/root', + ]; + + $httpRequest = HTTP\Sapi::createFromServerArray($serverVars); + $server = new Server(); + $server->httpRequest = $httpRequest; + + $server->guessBaseUri(); + + } + + function testTriggerException() { + + $serverVars = [ + 'REQUEST_URI' => '/', + 'REQUEST_METHOD' => 'FOO', + ]; + + $httpRequest = HTTP\Sapi::createFromServerArray($serverVars); + $this->server->httpRequest = $httpRequest; + $this->server->on('beforeMethod', [$this, 'exceptionTrigger']); + $this->server->exec(); + + $this->assertEquals([ + 'Content-Type' => ['application/xml; charset=utf-8'], + ], $this->response->getHeaders()); + + $this->assertEquals(500, $this->response->status); + + } + + function exceptionTrigger($request, $response) { + + throw new Exception('Hola'); + + } + + function testReportNotFound() { + + $serverVars = [ + 'REQUEST_URI' => '/', + 'REQUEST_METHOD' => 'REPORT', + ]; + + $request = HTTP\Sapi::createFromServerArray($serverVars); + $this->server->httpRequest = ($request); + $this->server->httpRequest->setBody('<?xml version="1.0"?><bla:myreport xmlns:bla="http://www.rooftopsolutions.nl/NS"></bla:myreport>'); + $this->server->exec(); + + $this->assertEquals([ + 'X-Sabre-Version' => [Version::VERSION], + 'Content-Type' => ['application/xml; charset=utf-8'], + ], + $this->response->getHeaders() + ); + + $this->assertEquals(415, $this->response->status, 'We got an incorrect status back. Full response body follows: ' . $this->response->body); + + } + + function testReportIntercepted() { + + $serverVars = [ + 'REQUEST_URI' => '/', + 'REQUEST_METHOD' => 'REPORT', + ]; + + $request = HTTP\Sapi::createFromServerArray($serverVars); + $this->server->httpRequest = ($request); + $this->server->httpRequest->setBody('<?xml version="1.0"?><bla:myreport xmlns:bla="http://www.rooftopsolutions.nl/NS"></bla:myreport>'); + $this->server->on('report', [$this, 'reportHandler']); + $this->server->exec(); + + $this->assertEquals([ + 'X-Sabre-Version' => [Version::VERSION], + 'testheader' => ['testvalue'], + ], + $this->response->getHeaders() + ); + + $this->assertEquals(418, $this->response->status, 'We got an incorrect status back. Full response body follows: ' . $this->response->body); + + } + + function reportHandler($reportName, $result, $path) { + + if ($reportName == '{http://www.rooftopsolutions.nl/NS}myreport') { + $this->server->httpResponse->setStatus(418); + $this->server->httpResponse->setHeader('testheader', 'testvalue'); + return false; + } + else return; + + } + + function testGetPropertiesForChildren() { + + $result = $this->server->getPropertiesForChildren('', [ + '{DAV:}getcontentlength', + ]); + + $expected = [ + 'test.txt' => ['{DAV:}getcontentlength' => 13], + 'dir/' => [], + ]; + + $this->assertEquals($expected, $result); + + } + + /** + * There are certain cases where no HTTP status may be set. We need to + * intercept these and set it to a default error message. + */ + function testNoHTTPStatusSet() { + + $this->server->on('method:GET', function() { return false; }, 1); + $this->server->httpRequest = new HTTP\Request('GET', '/'); + $this->server->exec(); + $this->assertEquals(500, $this->response->getStatus()); + + } + +} diff --git a/vendor/sabre/dav/tests/Sabre/DAV/ServerUpdatePropertiesTest.php b/vendor/sabre/dav/tests/Sabre/DAV/ServerUpdatePropertiesTest.php new file mode 100644 index 000000000..383f8e657 --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/DAV/ServerUpdatePropertiesTest.php @@ -0,0 +1,102 @@ +<?php + +namespace Sabre\DAV; + +class ServerUpdatePropertiesTest extends \PHPUnit_Framework_TestCase { + + function testUpdatePropertiesFail() { + + $tree = [ + new SimpleCollection('foo'), + ]; + $server = new Server($tree); + + $result = $server->updateProperties('foo', [ + '{DAV:}foo' => 'bar' + ]); + + $expected = [ + '{DAV:}foo' => 403, + ]; + $this->assertEquals($expected, $result); + + } + + function testUpdatePropertiesProtected() { + + $tree = [ + new SimpleCollection('foo'), + ]; + $server = new Server($tree); + + $server->on('propPatch', function($path, PropPatch $propPatch) { + $propPatch->handleRemaining(function() { return true; }); + }); + $result = $server->updateProperties('foo', [ + '{DAV:}getetag' => 'bla', + '{DAV:}foo' => 'bar' + ]); + + $expected = [ + '{DAV:}getetag' => 403, + '{DAV:}foo' => 424, + ]; + $this->assertEquals($expected, $result); + + } + + function testUpdatePropertiesEventFail() { + + $tree = [ + new SimpleCollection('foo'), + ]; + $server = new Server($tree); + $server->on('propPatch', function($path, PropPatch $propPatch) { + $propPatch->setResultCode('{DAV:}foo', 404); + $propPatch->handleRemaining(function() { return true; }); + }); + + $result = $server->updateProperties('foo', [ + '{DAV:}foo' => 'bar', + '{DAV:}foo2' => 'bla', + ]); + + $expected = [ + '{DAV:}foo' => 404, + '{DAV:}foo2' => 424, + ]; + $this->assertEquals($expected, $result); + + } + + function testUpdatePropertiesEventSuccess() { + + $tree = [ + new SimpleCollection('foo'), + ]; + $server = new Server($tree); + $server->on('propPatch', function($path, PropPatch $propPatch) { + + $propPatch->handle(['{DAV:}foo', '{DAV:}foo2'], function() { + return [ + '{DAV:}foo' => 200, + '{DAV:}foo2' => 201, + ]; + }); + + }); + + $result = $server->updateProperties('foo', [ + '{DAV:}foo' => 'bar', + '{DAV:}foo2' => 'bla', + ]); + + $expected = [ + '{DAV:}foo' => 200, + '{DAV:}foo2' => 201, + ]; + $this->assertEquals($expected, $result); + + } + +} diff --git a/vendor/sabre/dav/tests/Sabre/DAV/Sharing/PluginTest.php b/vendor/sabre/dav/tests/Sabre/DAV/Sharing/PluginTest.php new file mode 100644 index 000000000..6aa09cac0 --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/DAV/Sharing/PluginTest.php @@ -0,0 +1,190 @@ +<?php + +namespace Sabre\DAV\Sharing; + +use Sabre\DAV\Mock; +use Sabre\DAV\Xml\Property; + +class PluginTest extends \Sabre\DAVServerTest { + + protected $setupSharing = true; + protected $setupACL = true; + protected $autoLogin = 'admin'; + + function setUpTree() { + + $this->tree[] = new Mock\SharedNode( + 'shareable', + Plugin::ACCESS_READWRITE + ); + + } + + function testFeatures() { + + $this->assertEquals( + ['resource-sharing'], + $this->sharingPlugin->getFeatures() + ); + + } + + function testProperties() { + + $result = $this->server->getPropertiesForPath( + 'shareable', + ['{DAV:}share-access'] + ); + + $expected = [ + [ + 200 => [ + '{DAV:}share-access' => new Property\ShareAccess(Plugin::ACCESS_READWRITE) + ], + 404 => [], + 'href' => 'shareable', + ] + ]; + + $this->assertEquals( + $expected, + $result + ); + + } + + function testGetPluginInfo() { + + $result = $this->sharingPlugin->getPluginInfo(); + $this->assertInternalType('array', $result); + $this->assertEquals('sharing', $result['name']); + + } + + function testHtmlActionsPanel() { + + $node = new \Sabre\DAV\Mock\Collection('foo'); + $html = ''; + + $this->assertNull( + $this->sharingPlugin->htmlActionsPanel($node, $html, 'foo/bar') + ); + + $this->assertEquals( + '', + $html + ); + + $node = new \Sabre\DAV\Mock\SharedNode('foo', \Sabre\DAV\Sharing\Plugin::ACCESS_SHAREDOWNER); + $html = ''; + + $this->assertNull( + $this->sharingPlugin->htmlActionsPanel($node, $html, 'shareable') + ); + $this->assertContains( + 'Share this resource', + $html + ); + + } + + function testBrowserPostActionUnknownAction() { + + $this->assertNull($this->sharingPlugin->browserPostAction( + 'shareable', + 'foo', + [] + )); + + } + + function testBrowserPostActionSuccess() { + + $this->assertFalse($this->sharingPlugin->browserPostAction( + 'shareable', + 'share', + [ + 'access' => 'read', + 'href' => 'mailto:foo@example.org', + ] + )); + + $expected = [ + new \Sabre\DAV\Xml\Element\Sharee([ + 'href' => 'mailto:foo@example.org', + 'access' => \Sabre\DAV\Sharing\Plugin::ACCESS_READ, + 'inviteStatus' => \Sabre\DAV\Sharing\Plugin::INVITE_NORESPONSE, + ]) + ]; + $this->assertEquals( + $expected, + $this->tree[0]->getInvites() + ); + + } + + /** + * @expectedException \Sabre\DAV\Exception\BadRequest + */ + function testBrowserPostActionNoHref() { + + $this->sharingPlugin->browserPostAction( + 'shareable', + 'share', + [ + 'access' => 'read', + ] + ); + + } + + /** + * @expectedException \Sabre\DAV\Exception\BadRequest + */ + function testBrowserPostActionNoAccess() { + + $this->sharingPlugin->browserPostAction( + 'shareable', + 'share', + [ + 'href' => 'mailto:foo@example.org', + ] + ); + + } + + + /** + * @expectedException \Sabre\DAV\Exception\BadRequest + */ + function testBrowserPostActionBadAccess() { + + $this->sharingPlugin->browserPostAction( + 'shareable', + 'share', + [ + 'href' => 'mailto:foo@example.org', + 'access' => 'bleed', + ] + ); + + } + + /** + * @expectedException \Sabre\DAV\Exception\Forbidden + */ + function testBrowserPostActionAccessDenied() { + + $this->aclPlugin->setDefaultAcl([]); + $this->sharingPlugin->browserPostAction( + 'shareable', + 'share', + [ + 'access' => 'read', + 'href' => 'mailto:foo@example.org', + ] + ); + + } + +} diff --git a/vendor/sabre/dav/tests/Sabre/DAV/Sharing/ShareResourceTest.php b/vendor/sabre/dav/tests/Sabre/DAV/Sharing/ShareResourceTest.php new file mode 100644 index 000000000..959811166 --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/DAV/Sharing/ShareResourceTest.php @@ -0,0 +1,210 @@ +<?php + +namespace Sabre\DAV\Sharing; + +use Sabre\DAV\Mock; +use Sabre\DAV\Xml\Element\Sharee; +use Sabre\HTTP\Request; + +class ShareResourceTest extends \Sabre\DAVServerTest { + + protected $setupSharing = true; + protected $sharingNodeMock; + + function setUpTree() { + + $this->tree[] = $this->sharingNodeMock = new Mock\SharedNode( + 'shareable', + Plugin::ACCESS_SHAREDOWNER + ); + + } + + function testShareResource() { + + $body = <<<XML +<?xml version="1.0" encoding="utf-8" ?> +<D:share-resource xmlns:D="DAV:"> + <D:sharee> + <D:href>mailto:eric@example.com</D:href> + <D:prop> + <D:displayname>Eric York</D:displayname> + </D:prop> + <D:comment>Shared workspace</D:comment> + <D:share-access> + <D:read-write /> + </D:share-access> + </D:sharee> +</D:share-resource> +XML; + $request = new Request('POST', '/shareable', ['Content-Type' => 'application/davsharing+xml; charset="utf-8"'], $body); + + $response = $this->request($request); + $this->assertEquals(200, $response->getStatus(), (string)$response->getBodyAsString()); + + $expected = [ + new Sharee([ + 'href' => 'mailto:eric@example.com', + 'properties' => [ + '{DAV:}displayname' => 'Eric York', + ], + 'access' => Plugin::ACCESS_READWRITE, + 'comment' => 'Shared workspace', + 'inviteStatus' => \Sabre\DAV\Sharing\Plugin::INVITE_NORESPONSE, + ]) + ]; + + $this->assertEquals( + $expected, + $this->sharingNodeMock->getInvites() + ); + + } + + /** + * @depends testShareResource + */ + function testShareResourceRemoveAccess() { + + // First we just want to execute all the actions from the first + // test. + $this->testShareResource(); + + $body = <<<XML +<?xml version="1.0" encoding="utf-8" ?> +<D:share-resource xmlns:D="DAV:"> + <D:sharee> + <D:href>mailto:eric@example.com</D:href> + <D:share-access> + <D:no-access /> + </D:share-access> + </D:sharee> +</D:share-resource> +XML; + $request = new Request('POST', '/shareable', ['Content-Type' => 'application/davsharing+xml; charset="utf-8"'], $body); + + $response = $this->request($request); + $this->assertEquals(200, $response->getStatus(), (string)$response->getBodyAsString()); + + $expected = []; + + $this->assertEquals( + $expected, + $this->sharingNodeMock->getInvites() + ); + + + } + + /** + * @depends testShareResource + */ + function testShareResourceInviteProperty() { + + // First we just want to execute all the actions from the first + // test. + $this->testShareResource(); + + $body = <<<XML +<?xml version="1.0" encoding="utf-8" ?> +<D:propfind xmlns:D="DAV:"> + <D:prop> + <D:invite /> + <D:share-access /> + <D:share-resource-uri /> + </D:prop> +</D:propfind> +XML; + $request = new Request('PROPFIND', '/shareable', ['Content-Type' => 'application/xml'], $body); + $response = $this->request($request); + + $this->assertEquals(207, $response->getStatus()); + + $expected = <<<XML +<?xml version="1.0" encoding="utf-8" ?> +<d:multistatus xmlns:d="DAV:" xmlns:s="http://sabredav.org/ns"> + <d:response> + <d:href>/shareable</d:href> + <d:propstat> + <d:prop> + <d:invite> + <d:sharee> + <d:href>mailto:eric@example.com</d:href> + <d:prop> + <d:displayname>Eric York</d:displayname> + </d:prop> + <d:share-access><d:read-write /></d:share-access> + <d:invite-noresponse /> + </d:sharee> + </d:invite> + <d:share-access><d:shared-owner /></d:share-access> + <d:share-resource-uri><d:href>urn:example:bar</d:href></d:share-resource-uri> + </d:prop> + <d:status>HTTP/1.1 200 OK</d:status> + </d:propstat> + </d:response> +</d:multistatus> +XML; + + $this->assertXmlStringEqualsXmlString($expected, $response->getBodyAsString()); + + } + + function testShareResourceNotFound() { + + $body = <<<XML +<?xml version="1.0" encoding="utf-8" ?> +<D:share-resource xmlns:D="DAV:"> + <D:sharee> + <D:href>mailto:eric@example.com</D:href> + <D:prop> + <D:displayname>Eric York</D:displayname> + </D:prop> + <D:comment>Shared workspace</D:comment> + <D:share-access> + <D:read-write /> + </D:share-access> + </D:sharee> +</D:share-resource> +XML; + $request = new Request('POST', '/not-found', ['Content-Type' => 'application/davsharing+xml; charset="utf-8"'], $body); + + $response = $this->request($request, 404); + + } + + function testShareResourceNotISharedNode() { + + $body = <<<XML +<?xml version="1.0" encoding="utf-8" ?> +<D:share-resource xmlns:D="DAV:"> + <D:sharee> + <D:href>mailto:eric@example.com</D:href> + <D:prop> + <D:displayname>Eric York</D:displayname> + </D:prop> + <D:comment>Shared workspace</D:comment> + <D:share-access> + <D:read-write /> + </D:share-access> + </D:sharee> +</D:share-resource> +XML; + $request = new Request('POST', '/', ['Content-Type' => 'application/davsharing+xml; charset="utf-8"'], $body); + + $response = $this->request($request, 403); + + } + + function testShareResourceUnknownDoc() { + + $body = <<<XML +<?xml version="1.0" encoding="utf-8" ?> +<D:blablabla xmlns:D="DAV:" /> +XML; + $request = new Request('POST', '/shareable', ['Content-Type' => 'application/davsharing+xml; charset="utf-8"'], $body); + $response = $this->request($request, 400); + + } + +} diff --git a/vendor/sabre/dav/tests/Sabre/DAV/SimpleFileTest.php b/vendor/sabre/dav/tests/Sabre/DAV/SimpleFileTest.php new file mode 100644 index 000000000..15ccfaf9e --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/DAV/SimpleFileTest.php @@ -0,0 +1,19 @@ +<?php + +namespace Sabre\DAV; + +class SimpleFileTest extends \PHPUnit_Framework_TestCase { + + function testAll() { + + $file = new SimpleFile('filename.txt', 'contents', 'text/plain'); + + $this->assertEquals('filename.txt', $file->getName()); + $this->assertEquals('contents', $file->get()); + $this->assertEquals(8, $file->getSize()); + $this->assertEquals('"' . sha1('contents') . '"', $file->getETag()); + $this->assertEquals('text/plain', $file->getContentType()); + + } + +} diff --git a/vendor/sabre/dav/tests/Sabre/DAV/StringUtilTest.php b/vendor/sabre/dav/tests/Sabre/DAV/StringUtilTest.php new file mode 100644 index 000000000..e98fe9048 --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/DAV/StringUtilTest.php @@ -0,0 +1,129 @@ +<?php + +namespace Sabre\DAV; + +class StringUtilTest extends \PHPUnit_Framework_TestCase { + + /** + * @param string $haystack + * @param string $needle + * @param string $collation + * @param string $matchType + * @param string $result + * @throws Exception\BadRequest + * + * @dataProvider dataset + */ + function testTextMatch($haystack, $needle, $collation, $matchType, $result) { + + $this->assertEquals($result, StringUtil::textMatch($haystack, $needle, $collation, $matchType)); + + } + + function dataset() { + + return [ + ['FOOBAR', 'FOO', 'i;octet', 'contains', true], + ['FOOBAR', 'foo', 'i;octet', 'contains', false], + ['FÖÖBAR', 'FÖÖ', 'i;octet', 'contains', true], + ['FÖÖBAR', 'föö', 'i;octet', 'contains', false], + ['FOOBAR', 'FOOBAR', 'i;octet', 'equals', true], + ['FOOBAR', 'fooBAR', 'i;octet', 'equals', false], + ['FOOBAR', 'FOO', 'i;octet', 'starts-with', true], + ['FOOBAR', 'foo', 'i;octet', 'starts-with', false], + ['FOOBAR', 'BAR', 'i;octet', 'starts-with', false], + ['FOOBAR', 'bar', 'i;octet', 'starts-with', false], + ['FOOBAR', 'FOO', 'i;octet', 'ends-with', false], + ['FOOBAR', 'foo', 'i;octet', 'ends-with', false], + ['FOOBAR', 'BAR', 'i;octet', 'ends-with', true], + ['FOOBAR', 'bar', 'i;octet', 'ends-with', false], + + ['FOOBAR', 'FOO', 'i;ascii-casemap', 'contains', true], + ['FOOBAR', 'foo', 'i;ascii-casemap', 'contains', true], + ['FÖÖBAR', 'FÖÖ', 'i;ascii-casemap', 'contains', true], + ['FÖÖBAR', 'föö', 'i;ascii-casemap', 'contains', false], + ['FOOBAR', 'FOOBAR', 'i;ascii-casemap', 'equals', true], + ['FOOBAR', 'fooBAR', 'i;ascii-casemap', 'equals', true], + ['FOOBAR', 'FOO', 'i;ascii-casemap', 'starts-with', true], + ['FOOBAR', 'foo', 'i;ascii-casemap', 'starts-with', true], + ['FOOBAR', 'BAR', 'i;ascii-casemap', 'starts-with', false], + ['FOOBAR', 'bar', 'i;ascii-casemap', 'starts-with', false], + ['FOOBAR', 'FOO', 'i;ascii-casemap', 'ends-with', false], + ['FOOBAR', 'foo', 'i;ascii-casemap', 'ends-with', false], + ['FOOBAR', 'BAR', 'i;ascii-casemap', 'ends-with', true], + ['FOOBAR', 'bar', 'i;ascii-casemap', 'ends-with', true], + + ['FOOBAR', 'FOO', 'i;unicode-casemap', 'contains', true], + ['FOOBAR', 'foo', 'i;unicode-casemap', 'contains', true], + ['FÖÖBAR', 'FÖÖ', 'i;unicode-casemap', 'contains', true], + ['FÖÖBAR', 'föö', 'i;unicode-casemap', 'contains', true], + ['FOOBAR', 'FOOBAR', 'i;unicode-casemap', 'equals', true], + ['FOOBAR', 'fooBAR', 'i;unicode-casemap', 'equals', true], + ['FOOBAR', 'FOO', 'i;unicode-casemap', 'starts-with', true], + ['FOOBAR', 'foo', 'i;unicode-casemap', 'starts-with', true], + ['FOOBAR', 'BAR', 'i;unicode-casemap', 'starts-with', false], + ['FOOBAR', 'bar', 'i;unicode-casemap', 'starts-with', false], + ['FOOBAR', 'FOO', 'i;unicode-casemap', 'ends-with', false], + ['FOOBAR', 'foo', 'i;unicode-casemap', 'ends-with', false], + ['FOOBAR', 'BAR', 'i;unicode-casemap', 'ends-with', true], + ['FOOBAR', 'bar', 'i;unicode-casemap', 'ends-with', true], + ]; + + } + + /** + * @expectedException Sabre\DAV\Exception\BadRequest + */ + function testBadCollation() { + + StringUtil::textMatch('foobar', 'foo', 'blabla', 'contains'); + + } + + + /** + * @expectedException Sabre\DAV\Exception\BadRequest + */ + function testBadMatchType() { + + StringUtil::textMatch('foobar', 'foo', 'i;octet', 'booh'); + + } + + function testEnsureUTF8_ascii() { + + $inputString = "harkema"; + $outputString = "harkema"; + + $this->assertEquals( + $outputString, + StringUtil::ensureUTF8($inputString) + ); + + } + + function testEnsureUTF8_latin1() { + + $inputString = "m\xfcnster"; + $outputString = "münster"; + + $this->assertEquals( + $outputString, + StringUtil::ensureUTF8($inputString) + ); + + } + + function testEnsureUTF8_utf8() { + + $inputString = "m\xc3\xbcnster"; + $outputString = "münster"; + + $this->assertEquals( + $outputString, + StringUtil::ensureUTF8($inputString) + ); + + } + +} diff --git a/vendor/sabre/dav/tests/Sabre/DAV/Sync/MockSyncCollection.php b/vendor/sabre/dav/tests/Sabre/DAV/Sync/MockSyncCollection.php new file mode 100644 index 000000000..aac1dee48 --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/DAV/Sync/MockSyncCollection.php @@ -0,0 +1,169 @@ +<?php + +namespace Sabre\DAV\Sync; + +use Sabre\DAV; + +/** + * This mocks a ISyncCollection, for unittesting. + * + * This object behaves the same as SimpleCollection. Call addChange to update + * the 'changelog' that this class uses for the collection. + * + * @copyright Copyright (C) fruux GmbH (https://fruux.com/) + * @author Evert Pot (http://evertpot.com/) + * @license http://sabre.io/license/ Modified BSD License + */ +class MockSyncCollection extends DAV\SimpleCollection implements ISyncCollection { + + public $changeLog = []; + + public $token = null; + + /** + * This method returns the current sync-token for this collection. + * This can be any string. + * + * If null is returned from this function, the plugin assumes there's no + * sync information available. + * + * @return string|null + */ + function getSyncToken() { + + // Will be 'null' in the first round, and will increment ever after. + return $this->token; + + } + + function addChange(array $added, array $modified, array $deleted) { + + $this->token++; + $this->changeLog[$this->token] = [ + 'added' => $added, + 'modified' => $modified, + 'deleted' => $deleted, + ]; + + } + + /** + * The getChanges method returns all the changes that have happened, since + * the specified syncToken and the current collection. + * + * This function should return an array, such as the following: + * + * array( + * 'syncToken' => 'The current synctoken', + * 'modified' => array( + * 'new.txt', + * ), + * 'deleted' => array( + * 'foo.php.bak', + * 'old.txt' + * ) + * ); + * + * The syncToken property should reflect the *current* syncToken of the + * collection, as reported getSyncToken(). This is needed here too, to + * ensure the operation is atomic. + * + * If the syncToken is specified as null, this is an initial sync, and all + * members should be reported. + * + * The modified property is an array of nodenames that have changed since + * the last token. + * + * The deleted property is an array with nodenames, that have been deleted + * from collection. + * + * The second argument is basically the 'depth' of the report. If it's 1, + * you only have to report changes that happened only directly in immediate + * descendants. If it's 2, it should also include changes from the nodes + * below the child collections. (grandchildren) + * + * The third (optional) argument allows a client to specify how many + * results should be returned at most. If the limit is not specified, it + * should be treated as infinite. + * + * If the limit (infinite or not) is higher than you're willing to return, + * you should throw a Sabre\DAV\Exception\TooMuchMatches() exception. + * + * If the syncToken is expired (due to data cleanup) or unknown, you must + * return null. + * + * The limit is 'suggestive'. You are free to ignore it. + * + * @param string $syncToken + * @param int $syncLevel + * @param int $limit + * @return array + */ + function getChanges($syncToken, $syncLevel, $limit = null) { + + // This is an initial sync + if (is_null($syncToken)) { + return [ + 'added' => array_map( + function($item) { + return $item->getName(); + }, $this->getChildren() + ), + 'modified' => [], + 'deleted' => [], + 'syncToken' => $this->getSyncToken(), + ]; + } + + if (!is_int($syncToken) && !ctype_digit($syncToken)) { + + return null; + + } + if (is_null($this->token)) return null; + + $added = []; + $modified = []; + $deleted = []; + + foreach ($this->changeLog as $token => $change) { + + if ($token > $syncToken) { + + $added = array_merge($added, $change['added']); + $modified = array_merge($modified, $change['modified']); + $deleted = array_merge($deleted, $change['deleted']); + + if ($limit) { + // If there's a limit, we may need to cut things off. + // This alghorithm is weird and stupid, but it works. + $left = $limit - (count($modified) + count($deleted)); + if ($left > 0) continue; + if ($left === 0) break; + if ($left < 0) { + $modified = array_slice($modified, 0, $left); + } + $left = $limit - (count($modified) + count($deleted)); + if ($left === 0) break; + if ($left < 0) { + $deleted = array_slice($deleted, 0, $left); + } + break; + + } + + } + + } + + return [ + 'syncToken' => $this->token, + 'added' => $added, + 'modified' => $modified, + 'deleted' => $deleted, + ]; + + } + + +} diff --git a/vendor/sabre/dav/tests/Sabre/DAV/Sync/PluginTest.php b/vendor/sabre/dav/tests/Sabre/DAV/Sync/PluginTest.php new file mode 100644 index 000000000..6bcec8b75 --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/DAV/Sync/PluginTest.php @@ -0,0 +1,523 @@ +<?php + +namespace Sabre\DAV\Sync; + +use Sabre\DAV; +use Sabre\HTTP; + +require_once __DIR__ . '/MockSyncCollection.php'; + +class PluginTest extends \Sabre\DAVServerTest { + + protected $collection; + + function setUp() { + + parent::setUp(); + $this->server->addPlugin(new Plugin()); + + } + + function testGetInfo() { + + $this->assertArrayHasKey( + 'name', + (new Plugin())->getPluginInfo() + ); + + } + + function setUpTree() { + + $this->collection = + new MockSyncCollection('coll', [ + new DAV\SimpleFile('file1.txt', 'foo'), + new DAV\SimpleFile('file2.txt', 'bar'), + ]); + $this->tree = [ + $this->collection, + new DAV\SimpleCollection('normalcoll', []) + ]; + + } + + function testSupportedReportSet() { + + $result = $this->server->getProperties('/coll', ['{DAV:}supported-report-set']); + $this->assertFalse($result['{DAV:}supported-report-set']->has('{DAV:}sync-collection')); + + // Making a change + $this->collection->addChange(['file1.txt'], [], []); + + $result = $this->server->getProperties('/coll', ['{DAV:}supported-report-set']); + $this->assertTrue($result['{DAV:}supported-report-set']->has('{DAV:}sync-collection')); + + } + + function testGetSyncToken() { + + $result = $this->server->getProperties('/coll', ['{DAV:}sync-token']); + $this->assertFalse(isset($result['{DAV:}sync-token'])); + + // Making a change + $this->collection->addChange(['file1.txt'], [], []); + + $result = $this->server->getProperties('/coll', ['{DAV:}sync-token']); + $this->assertTrue(isset($result['{DAV:}sync-token'])); + + // non-sync-enabled collection + $this->collection->addChange(['file1.txt'], [], []); + + $result = $this->server->getProperties('/normalcoll', ['{DAV:}sync-token']); + $this->assertFalse(isset($result['{DAV:}sync-token'])); + } + + function testSyncInitialSyncCollection() { + + // Making a change + $this->collection->addChange(['file1.txt'], [], []); + + $request = new HTTP\Request('REPORT', '/coll/', ['Content-Type' => 'application/xml']); + + $body = <<<BLA +<?xml version="1.0" encoding="utf-8" ?> +<D:sync-collection xmlns:D="DAV:"> + <D:sync-token/> + <D:sync-level>1</D:sync-level> + <D:prop> + <D:getcontentlength/> + </D:prop> +</D:sync-collection> +BLA; + + $request->setBody($body); + + $response = $this->request($request); + + $this->assertEquals(207, $response->status, 'Full response body:' . $response->body); + + $multiStatus = $this->server->xml->parse($response->getBodyAsString()); + + // Checking the sync-token + $this->assertEquals( + 'http://sabre.io/ns/sync/1', + $multiStatus->getSyncToken() + ); + + $responses = $multiStatus->getResponses(); + $this->assertEquals(2, count($responses), 'We expected exactly 2 {DAV:}response'); + + $response = $responses[0]; + + $this->assertNull($response->getHttpStatus()); + $this->assertEquals('/coll/file1.txt', $response->getHref()); + $this->assertEquals([ + 200 => [ + '{DAV:}getcontentlength' => 3, + ] + ], $response->getResponseProperties()); + + $response = $responses[1]; + + $this->assertNull($response->getHttpStatus()); + $this->assertEquals('/coll/file2.txt', $response->getHref()); + $this->assertEquals([ + 200 => [ + '{DAV:}getcontentlength' => 3, + ] + ], $response->getResponseProperties()); + + } + + function testSubsequentSyncSyncCollection() { + + // Making a change + $this->collection->addChange(['file1.txt'], [], []); + // Making another change + $this->collection->addChange([], ['file2.txt'], ['file3.txt']); + + $request = HTTP\Sapi::createFromServerArray([ + 'REQUEST_METHOD' => 'REPORT', + 'REQUEST_URI' => '/coll/', + 'CONTENT_TYPE' => 'application/xml', + ]); + + $body = <<<BLA +<?xml version="1.0" encoding="utf-8" ?> +<D:sync-collection xmlns:D="DAV:"> + <D:sync-token>http://sabre.io/ns/sync/1</D:sync-token> + <D:sync-level>infinite</D:sync-level> + <D:prop> + <D:getcontentlength/> + </D:prop> +</D:sync-collection> +BLA; + + $request->setBody($body); + + $response = $this->request($request); + + $this->assertEquals(207, $response->status, 'Full response body:' . $response->body); + + $multiStatus = $this->server->xml->parse($response->getBodyAsString()); + + // Checking the sync-token + $this->assertEquals( + 'http://sabre.io/ns/sync/2', + $multiStatus->getSyncToken() + ); + + $responses = $multiStatus->getResponses(); + $this->assertEquals(2, count($responses), 'We expected exactly 2 {DAV:}response'); + + $response = $responses[0]; + + $this->assertNull($response->getHttpStatus()); + $this->assertEquals('/coll/file2.txt', $response->getHref()); + $this->assertEquals([ + 200 => [ + '{DAV:}getcontentlength' => 3, + ] + ], $response->getResponseProperties()); + + $response = $responses[1]; + + $this->assertEquals('404', $response->getHttpStatus()); + $this->assertEquals('/coll/file3.txt', $response->getHref()); + $this->assertEquals([], $response->getResponseProperties()); + + } + + function testSubsequentSyncSyncCollectionLimit() { + + // Making a change + $this->collection->addChange(['file1.txt'], [], []); + // Making another change + $this->collection->addChange([], ['file2.txt'], ['file3.txt']); + + $request = HTTP\Sapi::createFromServerArray([ + 'REQUEST_METHOD' => 'REPORT', + 'REQUEST_URI' => '/coll/', + 'CONTENT_TYPE' => 'application/xml', + ]); + + $body = <<<BLA +<?xml version="1.0" encoding="utf-8" ?> +<D:sync-collection xmlns:D="DAV:"> + <D:sync-token>http://sabre.io/ns/sync/1</D:sync-token> + <D:sync-level>infinite</D:sync-level> + <D:prop> + <D:getcontentlength/> + </D:prop> + <D:limit><D:nresults>1</D:nresults></D:limit> +</D:sync-collection> +BLA; + + $request->setBody($body); + + $response = $this->request($request); + + $this->assertEquals(207, $response->status, 'Full response body:' . $response->body); + + $multiStatus = $this->server->xml->parse( + $response->getBodyAsString() + ); + + // Checking the sync-token + $this->assertEquals( + 'http://sabre.io/ns/sync/2', + $multiStatus->getSyncToken() + ); + + $responses = $multiStatus->getResponses(); + $this->assertEquals(1, count($responses), 'We expected exactly 1 {DAV:}response'); + + $response = $responses[0]; + + $this->assertEquals('404', $response->getHttpStatus()); + $this->assertEquals('/coll/file3.txt', $response->getHref()); + $this->assertEquals([], $response->getResponseProperties()); + + } + + function testSubsequentSyncSyncCollectionDepthFallBack() { + + // Making a change + $this->collection->addChange(['file1.txt'], [], []); + // Making another change + $this->collection->addChange([], ['file2.txt'], ['file3.txt']); + + $request = HTTP\Sapi::createFromServerArray([ + 'REQUEST_METHOD' => 'REPORT', + 'REQUEST_URI' => '/coll/', + 'CONTENT_TYPE' => 'application/xml', + 'HTTP_DEPTH' => "1", + ]); + + $body = <<<BLA +<?xml version="1.0" encoding="utf-8" ?> +<D:sync-collection xmlns:D="DAV:"> + <D:sync-token>http://sabre.io/ns/sync/1</D:sync-token> + <D:prop> + <D:getcontentlength/> + </D:prop> +</D:sync-collection> +BLA; + + $request->setBody($body); + + $response = $this->request($request); + + $this->assertEquals(207, $response->status, 'Full response body:' . $response->body); + + $multiStatus = $this->server->xml->parse( + $response->getBodyAsString() + ); + + // Checking the sync-token + $this->assertEquals( + 'http://sabre.io/ns/sync/2', + $multiStatus->getSyncToken() + ); + + $responses = $multiStatus->getResponses(); + $this->assertEquals(2, count($responses), 'We expected exactly 2 {DAV:}response'); + + $response = $responses[0]; + + $this->assertNull($response->getHttpStatus()); + $this->assertEquals('/coll/file2.txt', $response->getHref()); + $this->assertEquals([ + 200 => [ + '{DAV:}getcontentlength' => 3, + ] + ], $response->getResponseProperties()); + + $response = $responses[1]; + + $this->assertEquals('404', $response->getHttpStatus()); + $this->assertEquals('/coll/file3.txt', $response->getHref()); + $this->assertEquals([], $response->getResponseProperties()); + + } + + function testSyncNoSyncInfo() { + + $request = HTTP\Sapi::createFromServerArray([ + 'REQUEST_METHOD' => 'REPORT', + 'REQUEST_URI' => '/coll/', + 'CONTENT_TYPE' => 'application/xml', + ]); + + $body = <<<BLA +<?xml version="1.0" encoding="utf-8" ?> +<D:sync-collection xmlns:D="DAV:"> + <D:sync-token/> + <D:sync-level>1</D:sync-level> + <D:prop> + <D:getcontentlength/> + </D:prop> +</D:sync-collection> +BLA; + + $request->setBody($body); + + $response = $this->request($request); + + // The default state has no sync-token, so this report should not yet + // be supported. + $this->assertEquals(415, $response->status, 'Full response body:' . $response->body); + + } + + function testSyncNoSyncCollection() { + + $request = HTTP\Sapi::createFromServerArray([ + 'REQUEST_METHOD' => 'REPORT', + 'REQUEST_URI' => '/normalcoll/', + 'CONTENT_TYPE' => 'application/xml', + ]); + + $body = <<<BLA +<?xml version="1.0" encoding="utf-8" ?> +<D:sync-collection xmlns:D="DAV:"> + <D:sync-token/> + <D:sync-level>1</D:sync-level> + <D:prop> + <D:getcontentlength/> + </D:prop> +</D:sync-collection> +BLA; + + $request->setBody($body); + + $response = $this->request($request); + + // The default state has no sync-token, so this report should not yet + // be supported. + $this->assertEquals(415, $response->status, 'Full response body:' . $response->body); + + } + + function testSyncInvalidToken() { + + $this->collection->addChange(['file1.txt'], [], []); + $request = HTTP\Sapi::createFromServerArray([ + 'REQUEST_METHOD' => 'REPORT', + 'REQUEST_URI' => '/coll/', + 'CONTENT_TYPE' => 'application/xml', + ]); + + $body = <<<BLA +<?xml version="1.0" encoding="utf-8" ?> +<D:sync-collection xmlns:D="DAV:"> + <D:sync-token>http://sabre.io/ns/sync/invalid</D:sync-token> + <D:sync-level>1</D:sync-level> + <D:prop> + <D:getcontentlength/> + </D:prop> +</D:sync-collection> +BLA; + + $request->setBody($body); + + $response = $this->request($request); + + // The default state has no sync-token, so this report should not yet + // be supported. + $this->assertEquals(403, $response->status, 'Full response body:' . $response->body); + + } + function testSyncInvalidTokenNoPrefix() { + + $this->collection->addChange(['file1.txt'], [], []); + $request = HTTP\Sapi::createFromServerArray([ + 'REQUEST_METHOD' => 'REPORT', + 'REQUEST_URI' => '/coll/', + 'CONTENT_TYPE' => 'application/xml', + ]); + + $body = <<<BLA +<?xml version="1.0" encoding="utf-8" ?> +<D:sync-collection xmlns:D="DAV:"> + <D:sync-token>invalid</D:sync-token> + <D:sync-level>1</D:sync-level> + <D:prop> + <D:getcontentlength/> + </D:prop> +</D:sync-collection> +BLA; + + $request->setBody($body); + + $response = $this->request($request); + + // The default state has no sync-token, so this report should not yet + // be supported. + $this->assertEquals(403, $response->status, 'Full response body:' . $response->body); + + } + + function testSyncNoSyncToken() { + + $request = HTTP\Sapi::createFromServerArray([ + 'REQUEST_METHOD' => 'REPORT', + 'REQUEST_URI' => '/coll/', + 'CONTENT_TYPE' => 'application/xml', + ]); + + $body = <<<BLA +<?xml version="1.0" encoding="utf-8" ?> +<D:sync-collection xmlns:D="DAV:"> + <D:sync-level>1</D:sync-level> + <D:prop> + <D:getcontentlength/> + </D:prop> +</D:sync-collection> +BLA; + + $request->setBody($body); + + $response = $this->request($request); + + // The default state has no sync-token, so this report should not yet + // be supported. + $this->assertEquals(400, $response->status, 'Full response body:' . $response->body); + + } + + function testSyncNoProp() { + + $this->collection->addChange(['file1.txt'], [], []); + $request = HTTP\Sapi::createFromServerArray([ + 'REQUEST_METHOD' => 'REPORT', + 'REQUEST_URI' => '/coll/', + 'CONTENT_TYPE' => 'application/xml', + ]); + + $body = <<<BLA +<?xml version="1.0" encoding="utf-8" ?> +<D:sync-collection xmlns:D="DAV:"> + <D:sync-token /> + <D:sync-level>1</D:sync-level> +</D:sync-collection> +BLA; + + $request->setBody($body); + + $response = $this->request($request); + + // The default state has no sync-token, so this report should not yet + // be supported. + $this->assertEquals(400, $response->status, 'Full response body:' . $response->body); + + } + + function testIfConditions() { + + $this->collection->addChange(['file1.txt'], [], []); + $request = HTTP\Sapi::createFromServerArray([ + 'REQUEST_METHOD' => 'DELETE', + 'REQUEST_URI' => '/coll/file1.txt', + 'HTTP_IF' => '</coll> (<http://sabre.io/ns/sync/1>)', + ]); + $response = $this->request($request); + + // If a 403 is thrown this works correctly. The file in questions + // doesn't allow itself to be deleted. + // If the If conditions failed, it would have been a 412 instead. + $this->assertEquals(403, $response->status); + + } + + function testIfConditionsNot() { + + $this->collection->addChange(['file1.txt'], [], []); + $request = HTTP\Sapi::createFromServerArray([ + 'REQUEST_METHOD' => 'DELETE', + 'REQUEST_URI' => '/coll/file1.txt', + 'HTTP_IF' => '</coll> (Not <http://sabre.io/ns/sync/2>)', + ]); + $response = $this->request($request); + + // If a 403 is thrown this works correctly. The file in questions + // doesn't allow itself to be deleted. + // If the If conditions failed, it would have been a 412 instead. + $this->assertEquals(403, $response->status); + + } + + function testIfConditionsNoSyncToken() { + + $this->collection->addChange(['file1.txt'], [], []); + $request = HTTP\Sapi::createFromServerArray([ + 'REQUEST_METHOD' => 'DELETE', + 'REQUEST_URI' => '/coll/file1.txt', + 'HTTP_IF' => '</coll> (<opaquelocktoken:foo>)', + ]); + $response = $this->request($request); + + $this->assertEquals(412, $response->status); + + } +} diff --git a/vendor/sabre/dav/tests/Sabre/DAV/SyncTokenPropertyTest.php b/vendor/sabre/dav/tests/Sabre/DAV/SyncTokenPropertyTest.php new file mode 100644 index 000000000..ff139f78c --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/DAV/SyncTokenPropertyTest.php @@ -0,0 +1,106 @@ +<?php + +namespace Sabre\DAV; + +class SyncTokenPropertyTest extends \Sabre\DAVServerTest { + + /** + * The assumption in these tests is that a PROPFIND is going on, and to + * fetch the sync-token, the event handler is just able to use the existing + * result. + * + * @param string $name + * @param mixed $value + * + * @dataProvider data + */ + function testAlreadyThere1($name, $value) { + + $propFind = new PropFind('foo', [ + '{http://calendarserver.org/ns/}getctag', + $name, + ]); + + $propFind->set($name, $value); + $corePlugin = new CorePlugin(); + $corePlugin->propFindLate($propFind, new SimpleCollection('hi')); + + $this->assertEquals("hello", $propFind->get('{http://calendarserver.org/ns/}getctag')); + + } + + /** + * In these test-cases, the plugin is forced to do a local propfind to + * fetch the items. + * + * @param string $name + * @param mixed $value + * + * @dataProvider data + */ + function testRefetch($name, $value) { + + $this->server->tree = new Tree( + new SimpleCollection('root', [ + new Mock\PropertiesCollection( + 'foo', + [], + [$name => $value] + ) + ]) + ); + $propFind = new PropFind('foo', [ + '{http://calendarserver.org/ns/}getctag', + $name, + ]); + + $corePlugin = $this->server->getPlugin('core'); + $corePlugin->propFindLate($propFind, new SimpleCollection('hi')); + + $this->assertEquals("hello", $propFind->get('{http://calendarserver.org/ns/}getctag')); + + } + + function testNoData() { + + $this->server->tree = new Tree( + new SimpleCollection('root', [ + new Mock\PropertiesCollection( + 'foo', + [], + [] + ) + ]) + ); + + $propFind = new PropFind('foo', [ + '{http://calendarserver.org/ns/}getctag', + ]); + + $corePlugin = $this->server->getPlugin('core'); + $corePlugin->propFindLate($propFind, new SimpleCollection('hi')); + + $this->assertNull($propFind->get('{http://calendarserver.org/ns/}getctag')); + + } + + function data() { + + return [ + [ + '{http://sabredav.org/ns}sync-token', + "hello" + ], + [ + '{DAV:}sync-token', + "hello" + ], + [ + '{DAV:}sync-token', + new Xml\Property\Href(Sync\Plugin::SYNCTOKEN_PREFIX . "hello", false) + ] + ]; + + } + +} diff --git a/vendor/sabre/dav/tests/Sabre/DAV/TemporaryFileFilterTest.php b/vendor/sabre/dav/tests/Sabre/DAV/TemporaryFileFilterTest.php new file mode 100644 index 000000000..6acd6b077 --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/DAV/TemporaryFileFilterTest.php @@ -0,0 +1,199 @@ +<?php + +namespace Sabre\DAV; + +use Sabre\HTTP; + +class TemporaryFileFilterTest extends AbstractServer { + + function setUp() { + + parent::setUp(); + $plugin = new TemporaryFileFilterPlugin(SABRE_TEMPDIR . '/tff'); + $this->server->addPlugin($plugin); + + } + + function testPutNormal() { + + $request = new HTTP\Request('PUT', '/testput.txt', [], 'Testing new file'); + + $this->server->httpRequest = ($request); + $this->server->exec(); + + $this->assertEquals('', $this->response->body); + $this->assertEquals(201, $this->response->status); + $this->assertEquals('0', $this->response->getHeader('Content-Length')); + + $this->assertEquals('Testing new file', file_get_contents(SABRE_TEMPDIR . '/testput.txt')); + + } + + function testPutTemp() { + + // mimicking an OS/X resource fork + $request = new HTTP\Request('PUT', '/._testput.txt', [], 'Testing new file'); + + $this->server->httpRequest = ($request); + $this->server->exec(); + + $this->assertEquals('', $this->response->body); + $this->assertEquals(201, $this->response->status); + $this->assertEquals([ + 'X-Sabre-Temp' => ['true'], + ], $this->response->getHeaders()); + + $this->assertFalse(file_exists(SABRE_TEMPDIR . '/._testput.txt'), '._testput.txt should not exist in the regular file structure.'); + + } + + function testPutTempIfNoneMatch() { + + // mimicking an OS/X resource fork + $request = new HTTP\Request('PUT', '/._testput.txt', ['If-None-Match' => '*'], 'Testing new file'); + + $this->server->httpRequest = ($request); + $this->server->exec(); + + $this->assertEquals('', $this->response->body); + $this->assertEquals(201, $this->response->status); + $this->assertEquals([ + 'X-Sabre-Temp' => ['true'], + ], $this->response->getHeaders()); + + $this->assertFalse(file_exists(SABRE_TEMPDIR . '/._testput.txt'), '._testput.txt should not exist in the regular file structure.'); + + + $this->server->exec(); + + $this->assertEquals(412, $this->response->status); + $this->assertEquals([ + 'X-Sabre-Temp' => ['true'], + 'Content-Type' => ['application/xml; charset=utf-8'], + ], $this->response->getHeaders()); + + } + + function testPutGet() { + + // mimicking an OS/X resource fork + $request = new HTTP\Request('PUT', '/._testput.txt', [], 'Testing new file'); + $this->server->httpRequest = ($request); + $this->server->exec(); + + $this->assertEquals('', $this->response->body); + $this->assertEquals(201, $this->response->status); + $this->assertEquals([ + 'X-Sabre-Temp' => ['true'], + ], $this->response->getHeaders()); + + $request = new HTTP\Request('GET', '/._testput.txt'); + + $this->server->httpRequest = $request; + $this->server->exec(); + + $this->assertEquals(200, $this->response->status); + $this->assertEquals([ + 'X-Sabre-Temp' => ['true'], + 'Content-Length' => [16], + 'Content-Type' => ['application/octet-stream'], + ], $this->response->getHeaders()); + + $this->assertEquals('Testing new file', stream_get_contents($this->response->body)); + + } + + function testLockNonExistant() { + + mkdir(SABRE_TEMPDIR . '/locksdir'); + $locksBackend = new Locks\Backend\File(SABRE_TEMPDIR . '/locks'); + $locksPlugin = new Locks\Plugin($locksBackend); + $this->server->addPlugin($locksPlugin); + + // mimicking an OS/X resource fork + $request = new HTTP\Request('LOCK', '/._testput.txt'); + $request->setBody('<?xml version="1.0"?> +<D:lockinfo xmlns:D="DAV:"> + <D:lockscope><D:exclusive/></D:lockscope> + <D:locktype><D:write/></D:locktype> + <D:owner> + <D:href>http://example.org/~ejw/contact.html</D:href> + </D:owner> +</D:lockinfo>'); + + $this->server->httpRequest = ($request); + $this->server->exec(); + + $this->assertEquals(201, $this->response->status); + $this->assertEquals('application/xml; charset=utf-8', $this->response->getHeader('Content-Type')); + $this->assertTrue(preg_match('/^<opaquelocktoken:(.*)>$/', $this->response->getHeader('Lock-Token')) === 1, 'We did not get a valid Locktoken back (' . $this->response->getHeader('Lock-Token') . ')'); + $this->assertEquals('true', $this->response->getHeader('X-Sabre-Temp')); + + $this->assertFalse(file_exists(SABRE_TEMPDIR . '/._testlock.txt'), '._testlock.txt should not exist in the regular file structure.'); + + } + + function testPutDelete() { + + // mimicking an OS/X resource fork + $request = new HTTP\Request('PUT', '/._testput.txt', [], 'Testing new file'); + + $this->server->httpRequest = $request; + $this->server->exec(); + + $this->assertEquals('', $this->response->body); + $this->assertEquals(201, $this->response->status); + $this->assertEquals([ + 'X-Sabre-Temp' => ['true'], + ], $this->response->getHeaders()); + + $request = new HTTP\Request('DELETE', '/._testput.txt'); + $this->server->httpRequest = $request; + $this->server->exec(); + + $this->assertEquals(204, $this->response->status, "Incorrect status code received. Full body:\n" . $this->response->body); + $this->assertEquals([ + 'X-Sabre-Temp' => ['true'], + ], $this->response->getHeaders()); + + $this->assertEquals('', $this->response->body); + + } + + function testPutPropfind() { + + // mimicking an OS/X resource fork + $request = new HTTP\Request('PUT', '/._testput.txt', [], 'Testing new file'); + $this->server->httpRequest = $request; + $this->server->exec(); + + $this->assertEquals('', $this->response->body); + $this->assertEquals(201, $this->response->status); + $this->assertEquals([ + 'X-Sabre-Temp' => ['true'], + ], $this->response->getHeaders()); + + $request = new HTTP\Request('PROPFIND', '/._testput.txt'); + + $this->server->httpRequest = ($request); + $this->server->exec(); + + $this->assertEquals(207, $this->response->status, 'Incorrect status code returned. Body: ' . $this->response->body); + $this->assertEquals([ + 'X-Sabre-Temp' => ['true'], + 'Content-Type' => ['application/xml; charset=utf-8'], + ], $this->response->getHeaders()); + + $body = preg_replace("/xmlns(:[A-Za-z0-9_])?=(\"|\')DAV:(\"|\')/", "xmlns\\1=\"urn:DAV\"", $this->response->body); + $xml = simplexml_load_string($body); + $xml->registerXPathNamespace('d', 'urn:DAV'); + + list($data) = $xml->xpath('/d:multistatus/d:response/d:href'); + $this->assertEquals('/._testput.txt', (string)$data, 'href element should have been /._testput.txt'); + + $data = $xml->xpath('/d:multistatus/d:response/d:propstat/d:prop/d:resourcetype'); + $this->assertEquals(1, count($data)); + + } + +} diff --git a/vendor/sabre/dav/tests/Sabre/DAV/TestPlugin.php b/vendor/sabre/dav/tests/Sabre/DAV/TestPlugin.php new file mode 100644 index 000000000..619ac03fd --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/DAV/TestPlugin.php @@ -0,0 +1,37 @@ +<?php + +namespace Sabre\DAV; + +use Sabre\HTTP\RequestInterface; +use Sabre\HTTP\ResponseInterface; + +class TestPlugin extends ServerPlugin { + + public $beforeMethod; + + function getFeatures() { + + return ['drinking']; + + } + + function getHTTPMethods($uri) { + + return ['BEER','WINE']; + + } + + function initialize(Server $server) { + + $server->on('beforeMethod', [$this, 'beforeMethod']); + + } + + function beforeMethod(RequestInterface $request, ResponseInterface $response) { + + $this->beforeMethod = $request->getMethod(); + return true; + + } + +} diff --git a/vendor/sabre/dav/tests/Sabre/DAV/TreeTest.php b/vendor/sabre/dav/tests/Sabre/DAV/TreeTest.php new file mode 100644 index 000000000..c70d17a22 --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/DAV/TreeTest.php @@ -0,0 +1,258 @@ +<?php + +namespace Sabre\DAV; + +class TreeTest extends \PHPUnit_Framework_TestCase { + + function testNodeExists() { + + $tree = new TreeMock(); + + $this->assertTrue($tree->nodeExists('hi')); + $this->assertFalse($tree->nodeExists('hello')); + + } + + function testCopy() { + + $tree = new TreeMock(); + $tree->copy('hi', 'hi2'); + + $this->assertArrayHasKey('hi2', $tree->getNodeForPath('')->newDirectories); + $this->assertEquals('foobar', $tree->getNodeForPath('hi/file')->get()); + $this->assertEquals(['test1' => 'value'], $tree->getNodeForPath('hi/file')->getProperties([])); + + } + + function testCopyFile() { + + $tree = new TreeMock(); + $tree->copy('hi/file', 'hi/newfile'); + + $this->assertArrayHasKey('newfile', $tree->getNodeForPath('hi')->newFiles); + } + + function testCopyFile0() { + + $tree = new TreeMock(); + $tree->copy('hi/file', 'hi/0'); + + $this->assertArrayHasKey('0', $tree->getNodeForPath('hi')->newFiles); + } + + function testMove() { + + $tree = new TreeMock(); + $tree->move('hi', 'hi2'); + + $this->assertEquals('hi2', $tree->getNodeForPath('hi')->getName()); + $this->assertTrue($tree->getNodeForPath('hi')->isRenamed); + + } + + function testDeepMove() { + + $tree = new TreeMock(); + $tree->move('hi/sub', 'hi2'); + + $this->assertArrayHasKey('hi2', $tree->getNodeForPath('')->newDirectories); + $this->assertTrue($tree->getNodeForPath('hi/sub')->isDeleted); + + } + + function testDelete() { + + $tree = new TreeMock(); + $tree->delete('hi'); + $this->assertTrue($tree->getNodeForPath('hi')->isDeleted); + + } + + function testGetChildren() { + + $tree = new TreeMock(); + $children = $tree->getChildren(''); + $this->assertEquals(2, count($children)); + $this->assertEquals('hi', $children[0]->getName()); + + } + + function testGetMultipleNodes() { + + $tree = new TreeMock(); + $result = $tree->getMultipleNodes(['hi/sub', 'hi/file']); + $this->assertArrayHasKey('hi/sub', $result); + $this->assertArrayHasKey('hi/file', $result); + + $this->assertEquals('sub', $result['hi/sub']->getName()); + $this->assertEquals('file', $result['hi/file']->getName()); + + } + function testGetMultipleNodes2() { + + $tree = new TreeMock(); + $result = $tree->getMultipleNodes(['multi/1', 'multi/2']); + $this->assertArrayHasKey('multi/1', $result); + $this->assertArrayHasKey('multi/2', $result); + + } + +} + +class TreeMock extends Tree { + + private $nodes = []; + + function __construct() { + + $file = new TreeFileTester('file'); + $file->properties = ['test1' => 'value']; + $file->data = 'foobar'; + + parent::__construct( + new TreeDirectoryTester('root', [ + new TreeDirectoryTester('hi', [ + new TreeDirectoryTester('sub'), + $file, + ]), + new TreeMultiGetTester('multi', [ + new TreeFileTester('1'), + new TreeFileTester('2'), + new TreeFileTester('3'), + ]) + ]) + ); + + } + +} + +class TreeDirectoryTester extends SimpleCollection { + + public $newDirectories = []; + public $newFiles = []; + public $isDeleted = false; + public $isRenamed = false; + + function createDirectory($name) { + + $this->newDirectories[$name] = true; + + } + + function createFile($name, $data = null) { + + $this->newFiles[$name] = $data; + + } + + function getChild($name) { + + if (isset($this->newDirectories[$name])) return new self($name); + if (isset($this->newFiles[$name])) return new TreeFileTester($name, $this->newFiles[$name]); + return parent::getChild($name); + + } + + function childExists($name) { + + return !!$this->getChild($name); + + } + + function delete() { + + $this->isDeleted = true; + + } + + function setName($name) { + + $this->isRenamed = true; + $this->name = $name; + + } + +} + +class TreeFileTester extends File implements IProperties { + + public $name; + public $data; + public $properties; + + function __construct($name, $data = null) { + + $this->name = $name; + if (is_null($data)) $data = 'bla'; + $this->data = $data; + + } + + function getName() { + + return $this->name; + + } + + function get() { + + return $this->data; + + } + + function getProperties($properties) { + + return $this->properties; + + } + + /** + * Updates properties on this node. + * + * This method received a PropPatch object, which contains all the + * information about the update. + * + * To update specific properties, call the 'handle' method on this object. + * Read the PropPatch documentation for more information. + * + * @param PropPatch $propPatch + * @return void + */ + function propPatch(PropPatch $propPatch) { + + $this->properties = $propPatch->getMutations(); + $propPatch->setRemainingResultCode(200); + + } + +} + +class TreeMultiGetTester extends TreeDirectoryTester implements IMultiGet { + + /** + * This method receives a list of paths in it's first argument. + * It must return an array with Node objects. + * + * If any children are not found, you do not have to return them. + * + * @param array $paths + * @return array + */ + function getMultipleChildren(array $paths) { + + $result = []; + foreach ($paths as $path) { + try { + $child = $this->getChild($path); + $result[] = $child; + } catch (Exception\NotFound $e) { + // Do nothing + } + } + + return $result; + + } + +} diff --git a/vendor/sabre/dav/tests/Sabre/DAV/UUIDUtilTest.php b/vendor/sabre/dav/tests/Sabre/DAV/UUIDUtilTest.php new file mode 100644 index 000000000..f005ecc75 --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/DAV/UUIDUtilTest.php @@ -0,0 +1,25 @@ +<?php + +namespace Sabre\DAV; + +class UUIDUtilTest extends \PHPUnit_Framework_TestCase { + + function testValidateUUID() { + + $this->assertTrue( + UUIDUtil::validateUUID('11111111-2222-3333-4444-555555555555') + ); + $this->assertFalse( + UUIDUtil::validateUUID(' 11111111-2222-3333-4444-555555555555') + ); + $this->assertTrue( + UUIDUtil::validateUUID('ffffffff-2222-3333-4444-555555555555') + ); + $this->assertFalse( + UUIDUtil::validateUUID('fffffffg-2222-3333-4444-555555555555') + ); + + + } + +} diff --git a/vendor/sabre/dav/tests/Sabre/DAV/Xml/Element/PropTest.php b/vendor/sabre/dav/tests/Sabre/DAV/Xml/Element/PropTest.php new file mode 100644 index 000000000..7cc10650c --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/DAV/Xml/Element/PropTest.php @@ -0,0 +1,154 @@ +<?php + +namespace Sabre\DAV\Xml\Element; + +use Sabre\DAV\Xml\Property\Complex; +use Sabre\DAV\Xml\Property\Href; +use Sabre\DAV\Xml\XmlTest; + +class PropTest extends XmlTest { + + function testDeserializeSimple() { + + $input = <<<XML +<?xml version="1.0"?> +<root xmlns="DAV:"> + <foo>bar</foo> +</root> +XML; + + $expected = [ + '{DAV:}foo' => 'bar', + ]; + + $this->assertDecodeProp($input, $expected); + + } + function testDeserializeEmpty() { + + $input = <<<XML +<?xml version="1.0"?> +<root xmlns="DAV:" /> +XML; + + $expected = [ + ]; + + $this->assertDecodeProp($input, $expected); + + } + function testDeserializeComplex() { + + $input = <<<XML +<?xml version="1.0"?> +<root xmlns="DAV:"> + <foo><no>yes</no></foo> +</root> +XML; + + $expected = [ + '{DAV:}foo' => new Complex('<no xmlns="DAV:">yes</no>') + ]; + + $this->assertDecodeProp($input, $expected); + + } + function testDeserializeCustom() { + + $input = <<<XML +<?xml version="1.0"?> +<root xmlns="DAV:"> + <foo><href>/hello</href></foo> +</root> +XML; + + $expected = [ + '{DAV:}foo' => new Href('/hello', false) + ]; + + $elementMap = [ + '{DAV:}foo' => 'Sabre\DAV\Xml\Property\Href' + ]; + + $this->assertDecodeProp($input, $expected, $elementMap); + + } + function testDeserializeCustomCallback() { + + $input = <<<XML +<?xml version="1.0"?> +<root xmlns="DAV:"> + <foo>blabla</foo> +</root> +XML; + + $expected = [ + '{DAV:}foo' => 'zim', + ]; + + $elementMap = [ + '{DAV:}foo' => function($reader) { + $reader->next(); + return 'zim'; + } + ]; + + $this->assertDecodeProp($input, $expected, $elementMap); + + } + + /** + * @expectedException \LogicException + */ + function testDeserializeCustomBad() { + + $input = <<<XML +<?xml version="1.0"?> +<root xmlns="DAV:"> + <foo>blabla</foo> +</root> +XML; + + $expected = []; + + $elementMap = [ + '{DAV:}foo' => 'idk?', + ]; + + $this->assertDecodeProp($input, $expected, $elementMap); + + } + + /** + * @expectedException \LogicException + */ + function testDeserializeCustomBadObj() { + + $input = <<<XML +<?xml version="1.0"?> +<root xmlns="DAV:"> + <foo>blabla</foo> +</root> +XML; + + $expected = []; + + $elementMap = [ + '{DAV:}foo' => new \StdClass(), + ]; + + $this->assertDecodeProp($input, $expected, $elementMap); + + } + + function assertDecodeProp($input, array $expected, array $elementMap = []) { + + $elementMap['{DAV:}root'] = 'Sabre\DAV\Xml\Element\Prop'; + + $result = $this->parse($input, $elementMap); + $this->assertInternalType('array', $result); + $this->assertEquals($expected, $result['value']); + + } + +} diff --git a/vendor/sabre/dav/tests/Sabre/DAV/Xml/Element/ResponseTest.php b/vendor/sabre/dav/tests/Sabre/DAV/Xml/Element/ResponseTest.php new file mode 100644 index 000000000..f19e7df7c --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/DAV/Xml/Element/ResponseTest.php @@ -0,0 +1,313 @@ +<?php + +namespace Sabre\DAV\Xml\Element; + +use Sabre\DAV; + +class ResponseTest extends DAV\Xml\XmlTest { + + function testSimple() { + + $innerProps = [ + 200 => [ + '{DAV:}displayname' => 'my file', + ], + 404 => [ + '{DAV:}owner' => null, + ] + ]; + + $property = new Response('uri', $innerProps); + + $this->assertEquals('uri', $property->getHref()); + $this->assertEquals($innerProps, $property->getResponseProperties()); + + + } + + /** + * @depends testSimple + */ + function testSerialize() { + + $innerProps = [ + 200 => [ + '{DAV:}displayname' => 'my file', + ], + 404 => [ + '{DAV:}owner' => null, + ] + ]; + + $property = new Response('uri', $innerProps); + + $xml = $this->write(['{DAV:}root' => ['{DAV:}response' => $property]]); + + $this->assertXmlStringEqualsXmlString( +'<?xml version="1.0"?> +<d:root xmlns:d="DAV:"> + <d:response> + <d:href>/uri</d:href> + <d:propstat> + <d:prop> + <d:displayname>my file</d:displayname> + </d:prop> + <d:status>HTTP/1.1 200 OK</d:status> + </d:propstat> + <d:propstat> + <d:prop> + <d:owner/> + </d:prop> + <d:status>HTTP/1.1 404 Not Found</d:status> + </d:propstat> + </d:response> +</d:root> +', $xml); + + } + + /** + * This one is specifically for testing properties with no namespaces, which is legal xml + * + * @depends testSerialize + */ + function testSerializeEmptyNamespace() { + + $innerProps = [ + 200 => [ + '{}propertyname' => 'value', + ], + ]; + + $property = new Response('uri', $innerProps); + + $xml = $this->write(['{DAV:}root' => ['{DAV:}response' => $property]]); + + $this->assertEquals( +'<d:root xmlns:d="DAV:"> + <d:response> + <d:href>/uri</d:href> + <d:propstat> + <d:prop> + <propertyname xmlns="">value</propertyname> + </d:prop> + <d:status>HTTP/1.1 200 OK</d:status> + </d:propstat> + </d:response> +</d:root> +', $xml); + + } + + /** + * This one is specifically for testing properties with no namespaces, which is legal xml + * + * @depends testSerialize + */ + function testSerializeCustomNamespace() { + + $innerProps = [ + 200 => [ + '{http://sabredav.org/NS/example}propertyname' => 'value', + ], + ]; + + $property = new Response('uri', $innerProps); + $xml = $this->write(['{DAV:}root' => ['{DAV:}response' => $property]]); + + $this->assertXmlStringEqualsXmlString( +'<?xml version="1.0"?> +<d:root xmlns:d="DAV:"> + <d:response> + <d:href>/uri</d:href> + <d:propstat> + <d:prop> + <x1:propertyname xmlns:x1="http://sabredav.org/NS/example">value</x1:propertyname> + </d:prop> + <d:status>HTTP/1.1 200 OK</d:status> + </d:propstat> + </d:response> +</d:root>', $xml); + + } + + /** + * @depends testSerialize + */ + function testSerializeComplexProperty() { + + $innerProps = [ + 200 => [ + '{DAV:}link' => new DAV\Xml\Property\Href('http://sabredav.org/', false) + ], + ]; + + $property = new Response('uri', $innerProps); + $xml = $this->write(['{DAV:}root' => ['{DAV:}response' => $property]]); + + $this->assertXmlStringEqualsXmlString( +'<?xml version="1.0"?> +<d:root xmlns:d="DAV:"> + <d:response> + <d:href>/uri</d:href> + <d:propstat> + <d:prop> + <d:link><d:href>http://sabredav.org/</d:href></d:link> + </d:prop> + <d:status>HTTP/1.1 200 OK</d:status> + </d:propstat> + </d:response> +</d:root> +', $xml); + + } + + /** + * @depends testSerialize + * @expectedException \InvalidArgumentException + */ + function testSerializeBreak() { + + $innerProps = [ + 200 => [ + '{DAV:}link' => new \STDClass() + ], + ]; + + $property = new Response('uri', $innerProps); + $this->write(['{DAV:}root' => ['{DAV:}response' => $property]]); + + } + + function testDeserializeComplexProperty() { + + $xml = '<?xml version="1.0"?> +<d:response xmlns:d="DAV:"> + <d:href>/uri</d:href> + <d:propstat> + <d:prop> + <d:foo>hello</d:foo> + </d:prop> + <d:status>HTTP/1.1 200 OK</d:status> + </d:propstat> +</d:response> +'; + + $result = $this->parse($xml, [ + '{DAV:}response' => 'Sabre\DAV\Xml\Element\Response', + '{DAV:}foo' => function($reader) { + + $reader->next(); + return 'world'; + }, + ]); + $this->assertEquals( + new Response('/uri', [ + '200' => [ + '{DAV:}foo' => 'world', + ] + ]), + $result['value'] + ); + + } + + /** + * @depends testSimple + */ + function testSerializeUrlencoding() { + + $innerProps = [ + 200 => [ + '{DAV:}displayname' => 'my file', + ], + ]; + + $property = new Response('space here', $innerProps); + + $xml = $this->write(['{DAV:}root' => ['{DAV:}response' => $property]]); + + $this->assertXmlStringEqualsXmlString( +'<?xml version="1.0"?> +<d:root xmlns:d="DAV:"> + <d:response> + <d:href>/space%20here</d:href> + <d:propstat> + <d:prop> + <d:displayname>my file</d:displayname> + </d:prop> + <d:status>HTTP/1.1 200 OK</d:status> + </d:propstat> + </d:response> +</d:root> +', $xml); + + } + + /** + * @depends testSerialize + * + * The WebDAV spec _requires_ at least one DAV:propstat to appear for + * every DAV:response. In some circumstances however, there are no + * properties to encode. + * + * In those cases we MUST specify at least one DAV:propstat anyway, with + * no properties. + */ + function testSerializeNoProperties() { + + $innerProps = []; + + $property = new Response('uri', $innerProps); + $xml = $this->write(['{DAV:}root' => ['{DAV:}response' => $property]]); + + $this->assertXmlStringEqualsXmlString( +'<?xml version="1.0"?> +<d:root xmlns:d="DAV:"> + <d:response> + <d:href>/uri</d:href> + <d:propstat> + <d:prop /> + <d:status>HTTP/1.1 418 I\'m a teapot</d:status> + </d:propstat> + </d:response> +</d:root> +', $xml); + + } + + /** + * In the case of {DAV:}prop, a deserializer should never get called, if + * the property element is empty. + */ + function testDeserializeComplexPropertyEmpty() { + + $xml = '<?xml version="1.0"?> +<d:response xmlns:d="DAV:"> + <d:href>/uri</d:href> + <d:propstat> + <d:prop> + <d:foo /> + </d:prop> + <d:status>HTTP/1.1 404 Not Found</d:status> + </d:propstat> +</d:response> +'; + + $result = $this->parse($xml, [ + '{DAV:}response' => 'Sabre\DAV\Xml\Element\Response', + '{DAV:}foo' => function($reader) { + throw new \LogicException('This should never happen'); + }, + ]); + $this->assertEquals( + new Response('/uri', [ + '404' => [ + '{DAV:}foo' => null + ] + ]), + $result['value'] + ); + + } +} diff --git a/vendor/sabre/dav/tests/Sabre/DAV/Xml/Element/ShareeTest.php b/vendor/sabre/dav/tests/Sabre/DAV/Xml/Element/ShareeTest.php new file mode 100644 index 000000000..3704d8782 --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/DAV/Xml/Element/ShareeTest.php @@ -0,0 +1,98 @@ +<?php + +namespace Sabre\DAV\Xml\Element; + +use Sabre\DAV\Sharing\Plugin; +use Sabre\DAV\Xml\XmlTest; + +class ShareeTest extends XmlTest { + + /** + * @expectedException \InvalidArgumentException + */ + function testShareeUnknownPropertyInConstructor() { + + new Sharee(['foo' => 'bar']); + + } + + function testDeserialize() { + + $xml = <<<XML +<?xml version="1.0" encoding="utf-8" ?> +<D:sharee xmlns:D="DAV:"> + <D:href>mailto:eric@example.com</D:href> + <D:prop> + <D:displayname>Eric York</D:displayname> + </D:prop> + <D:comment>Shared workspace</D:comment> + <D:share-access> + <D:read-write /> + </D:share-access> +</D:sharee> +XML; + + $result = $this->parse($xml, [ + '{DAV:}sharee' => 'Sabre\\DAV\\Xml\\Element\\Sharee' + ]); + + $expected = new Sharee([ + 'href' => 'mailto:eric@example.com', + 'properties' => ['{DAV:}displayname' => 'Eric York'], + 'comment' => 'Shared workspace', + 'access' => Plugin::ACCESS_READWRITE, + ]); + $this->assertEquals( + $expected, + $result['value'] + ); + + } + + /** + * @expectedException \Sabre\DAV\Exception\BadRequest + */ + function testDeserializeNoHref() { + + $xml = <<<XML +<?xml version="1.0" encoding="utf-8" ?> +<D:sharee xmlns:D="DAV:"> + <D:prop> + <D:displayname>Eric York</D:displayname> + </D:prop> + <D:comment>Shared workspace</D:comment> + <D:share-access> + <D:read-write /> + </D:share-access> +</D:sharee> +XML; + + $this->parse($xml, [ + '{DAV:}sharee' => 'Sabre\\DAV\\Xml\\Element\\Sharee' + ]); + + } + + + /** + * @expectedException \Sabre\DAV\Exception\BadRequest + */ + function testDeserializeNoShareeAccess() { + + $xml = <<<XML +<?xml version="1.0" encoding="utf-8" ?> +<D:sharee xmlns:D="DAV:"> + <D:href>mailto:eric@example.com</D:href> + <D:prop> + <D:displayname>Eric York</D:displayname> + </D:prop> + <D:comment>Shared workspace</D:comment> +</D:sharee> +XML; + + $this->parse($xml, [ + '{DAV:}sharee' => 'Sabre\\DAV\\Xml\\Element\\Sharee' + ]); + + } +} diff --git a/vendor/sabre/dav/tests/Sabre/DAV/Xml/Property/HrefTest.php b/vendor/sabre/dav/tests/Sabre/DAV/Xml/Property/HrefTest.php new file mode 100644 index 000000000..bf5885337 --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/DAV/Xml/Property/HrefTest.php @@ -0,0 +1,109 @@ +<?php + +namespace Sabre\DAV\Xml\Property; + +use Sabre\DAV; +use Sabre\DAV\Browser\HtmlOutputHelper; +use Sabre\DAV\Xml\XmlTest; + +class HrefTest extends XmlTest { + + function testConstruct() { + + $href = new Href('path'); + $this->assertEquals('path', $href->getHref()); + + } + + function testSerialize() { + + $href = new Href('path'); + $this->assertEquals('path', $href->getHref()); + + $this->contextUri = '/bla/'; + + $xml = $this->write(['{DAV:}anything' => $href]); + + $this->assertXmlStringEqualsXmlString( +'<?xml version="1.0"?> +<d:anything xmlns:d="DAV:"><d:href>/bla/path</d:href></d:anything> +', $xml); + + } + + function testUnserialize() { + + $xml = '<?xml version="1.0"?> +<d:anything xmlns:d="DAV:"><d:href>/bla/path</d:href></d:anything> +'; + + $result = $this->parse($xml, ['{DAV:}anything' => 'Sabre\\DAV\\Xml\\Property\\Href']); + + $href = $result['value']; + + $this->assertInstanceOf('Sabre\\DAV\\Xml\\Property\\Href', $href); + + $this->assertEquals('/bla/path', $href->getHref()); + + } + + function testUnserializeIncompatible() { + + $xml = '<?xml version="1.0"?> +<d:anything xmlns:d="DAV:"><d:href2>/bla/path</d:href2></d:anything> +'; + $result = $this->parse($xml, ['{DAV:}anything' => 'Sabre\\DAV\\Xml\\Property\\Href']); + $href = $result['value']; + $this->assertNull($href); + + } + function testUnserializeEmpty() { + + $xml = '<?xml version="1.0"?> +<d:anything xmlns:d="DAV:"></d:anything> +'; + $result = $this->parse($xml, ['{DAV:}anything' => 'Sabre\\DAV\\Xml\\Property\\Href']); + $href = $result['value']; + $this->assertNull($href); + + } + + /** + * This method tests if hrefs containing & are correctly encoded. + */ + function testSerializeEntity() { + + $href = new Href('http://example.org/?a&b', false); + $this->assertEquals('http://example.org/?a&b', $href->getHref()); + + $xml = $this->write(['{DAV:}anything' => $href]); + + $this->assertXmlStringEqualsXmlString( +'<?xml version="1.0"?> +<d:anything xmlns:d="DAV:"><d:href>http://example.org/?a&b</d:href></d:anything> +', $xml); + + } + + function testToHtml() { + + $href = new Href([ + '/foo/bar', + 'foo/bar', + 'http://example.org/bar' + ]); + + $html = new HtmlOutputHelper( + '/base/', + [] + ); + + $expected = + '<a href="/foo/bar">/foo/bar</a><br />' . + '<a href="/base/foo/bar">/base/foo/bar</a><br />' . + '<a href="http://example.org/bar">http://example.org/bar</a>'; + $this->assertEquals($expected, $href->toHtml($html)); + + } + +} diff --git a/vendor/sabre/dav/tests/Sabre/DAV/Xml/Property/InviteTest.php b/vendor/sabre/dav/tests/Sabre/DAV/Xml/Property/InviteTest.php new file mode 100644 index 000000000..6f8d6cc6c --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/DAV/Xml/Property/InviteTest.php @@ -0,0 +1,76 @@ +<?php + +namespace Sabre\DAV\Xml\Property; + +use Sabre\DAV\Sharing\Plugin; +use Sabre\DAV\Xml\Element\Sharee; +use Sabre\DAV\Xml\XmlTest; + +class InviteTest extends XmlTest { + + function testSerialize() { + + $sharees = [ + new Sharee(), + new Sharee(), + new Sharee(), + new Sharee() + ]; + $sharees[0]->href = 'mailto:foo@example.org'; + $sharees[0]->properties['{DAV:}displayname'] = 'Foo Bar'; + $sharees[0]->access = Plugin::ACCESS_SHAREDOWNER; + $sharees[0]->inviteStatus = Plugin::INVITE_ACCEPTED; + + $sharees[1]->href = 'mailto:bar@example.org'; + $sharees[1]->access = Plugin::ACCESS_READ; + $sharees[1]->inviteStatus = Plugin::INVITE_DECLINED; + + $sharees[2]->href = 'mailto:baz@example.org'; + $sharees[2]->access = Plugin::ACCESS_READWRITE; + $sharees[2]->inviteStatus = Plugin::INVITE_NORESPONSE; + + $sharees[3]->href = 'mailto:zim@example.org'; + $sharees[3]->access = Plugin::ACCESS_READWRITE; + $sharees[3]->inviteStatus = Plugin::INVITE_INVALID; + + $invite = new Invite($sharees); + + $xml = $this->write(['{DAV:}root' => $invite]); + + $expected = <<<XML +<?xml version="1.0"?> +<d:root xmlns:d="DAV:"> +<d:sharee> + <d:href>mailto:foo@example.org</d:href> + <d:prop> + <d:displayname>Foo Bar</d:displayname> + </d:prop> + <d:share-access><d:shared-owner /></d:share-access> + <d:invite-accepted/> +</d:sharee> +<d:sharee> + <d:href>mailto:bar@example.org</d:href> + <d:prop /> + <d:share-access><d:read /></d:share-access> + <d:invite-declined/> +</d:sharee> +<d:sharee> + <d:href>mailto:baz@example.org</d:href> + <d:prop /> + <d:share-access><d:read-write /></d:share-access> + <d:invite-noresponse/> +</d:sharee> +<d:sharee> + <d:href>mailto:zim@example.org</d:href> + <d:prop /> + <d:share-access><d:read-write /></d:share-access> + <d:invite-invalid/> +</d:sharee> +</d:root> +XML; + + $this->assertXmlStringEqualsXmlString($expected, $xml); + + } + +} diff --git a/vendor/sabre/dav/tests/Sabre/DAV/Xml/Property/LastModifiedTest.php b/vendor/sabre/dav/tests/Sabre/DAV/Xml/Property/LastModifiedTest.php new file mode 100644 index 000000000..669efbd45 --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/DAV/Xml/Property/LastModifiedTest.php @@ -0,0 +1,59 @@ +<?php + +namespace Sabre\DAV\Xml\Property; + +use DateTime; +use DateTimeZone; +use Sabre\DAV\Xml\XmlTest; + +class LastModifiedTest extends XmlTest { + + function testSerializeDateTime() { + + $dt = new DateTime('2015-03-24 11:47:00', new DateTimeZone('America/Vancouver')); + $val = ['{DAV:}getlastmodified' => new GetLastModified($dt)]; + + $result = $this->write($val); + $expected = <<<XML +<?xml version="1.0"?> +<d:getlastmodified xmlns:d="DAV:">Tue, 24 Mar 2015 18:47:00 GMT</d:getlastmodified> +XML; + + $this->assertXmlStringEqualsXmlString($expected, $result); + + } + + function testSerializeTimeStamp() { + + $dt = new DateTime('2015-03-24 11:47:00', new DateTimeZone('America/Vancouver')); + $dt = $dt->getTimeStamp(); + $val = ['{DAV:}getlastmodified' => new GetLastModified($dt)]; + + $result = $this->write($val); + $expected = <<<XML +<?xml version="1.0"?> +<d:getlastmodified xmlns:d="DAV:">Tue, 24 Mar 2015 18:47:00 GMT</d:getlastmodified> +XML; + + $this->assertXmlStringEqualsXmlString($expected, $result); + + } + + function testDeserialize() { + + $input = <<<XML +<?xml version="1.0"?> +<d:getlastmodified xmlns:d="DAV:">Tue, 24 Mar 2015 18:47:00 GMT</d:getlastmodified> +XML; + + $elementMap = ['{DAV:}getlastmodified' => 'Sabre\DAV\Xml\Property\GetLastModified']; + $result = $this->parse($input, $elementMap); + + $this->assertEquals( + new DateTime('2015-03-24 18:47:00', new DateTimeZone('UTC')), + $result['value']->getTime() + ); + + } + +} diff --git a/vendor/sabre/dav/tests/Sabre/DAV/Xml/Property/LocalHrefTest.php b/vendor/sabre/dav/tests/Sabre/DAV/Xml/Property/LocalHrefTest.php new file mode 100644 index 000000000..c3f69c929 --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/DAV/Xml/Property/LocalHrefTest.php @@ -0,0 +1,69 @@ +<?php + +namespace Sabre\DAV\Xml\Property; + +use Sabre\DAV; +use Sabre\DAV\Browser\HtmlOutputHelper; +use Sabre\DAV\Xml\XmlTest; + +class LocalHrefTest extends XmlTest { + + function testConstruct() { + + $href = new LocalHref('path'); + $this->assertEquals('path', $href->getHref()); + + } + + function testSerialize() { + + $href = new LocalHref('path'); + $this->assertEquals('path', $href->getHref()); + + $this->contextUri = '/bla/'; + + $xml = $this->write(['{DAV:}anything' => $href]); + + $this->assertXmlStringEqualsXmlString( +'<?xml version="1.0"?> +<d:anything xmlns:d="DAV:"><d:href>/bla/path</d:href></d:anything> +', $xml); + + } + function testSerializeSpace() { + + $href = new LocalHref('path alsopath'); + $this->assertEquals('path%20alsopath', $href->getHref()); + + $this->contextUri = '/bla/'; + + $xml = $this->write(['{DAV:}anything' => $href]); + + $this->assertXmlStringEqualsXmlString( +'<?xml version="1.0"?> +<d:anything xmlns:d="DAV:"><d:href>/bla/path%20alsopath</d:href></d:anything> +', $xml); + + } + function testToHtml() { + + $href = new LocalHref([ + '/foo/bar', + 'foo/bar', + 'http://example.org/bar' + ]); + + $html = new HtmlOutputHelper( + '/base/', + [] + ); + + $expected = + '<a href="/foo/bar">/foo/bar</a><br />' . + '<a href="/base/foo/bar">/base/foo/bar</a><br />' . + '<a href="http://example.org/bar">http://example.org/bar</a>'; + $this->assertEquals($expected, $href->toHtml($html)); + + } + +} diff --git a/vendor/sabre/dav/tests/Sabre/DAV/Xml/Property/LockDiscoveryTest.php b/vendor/sabre/dav/tests/Sabre/DAV/Xml/Property/LockDiscoveryTest.php new file mode 100644 index 000000000..0ad069c47 --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/DAV/Xml/Property/LockDiscoveryTest.php @@ -0,0 +1,86 @@ +<?php + +namespace Sabre\DAV\Xml\Property; + +use Sabre\DAV\Locks\LockInfo; +use Sabre\DAV\Xml\XmlTest; + +class LockDiscoveryTest extends XmlTest { + + function testSerialize() { + + $lock = new LockInfo(); + $lock->owner = 'hello'; + $lock->token = 'blabla'; + $lock->timeout = 600; + $lock->created = strtotime('2015-03-25 19:21:00'); + $lock->scope = LockInfo::EXCLUSIVE; + $lock->depth = 0; + $lock->uri = 'hi'; + + $prop = new LockDiscovery([$lock]); + + $xml = $this->write(['{DAV:}root' => $prop]); + + $this->assertXmlStringEqualsXmlString( +'<?xml version="1.0"?> +<d:root xmlns:d="DAV:"> + <d:activelock> + <d:lockscope><d:exclusive /></d:lockscope> + <d:locktype><d:write /></d:locktype> + <d:lockroot> + <d:href>/hi</d:href> + </d:lockroot> + <d:depth>0</d:depth> + <d:timeout>Second-600</d:timeout> + <d:locktoken> + <d:href>opaquelocktoken:blabla</d:href> + </d:locktoken> + <d:owner>hello</d:owner> + + +</d:activelock> +</d:root> +', $xml); + + } + + function testSerializeShared() { + + $lock = new LockInfo(); + $lock->owner = 'hello'; + $lock->token = 'blabla'; + $lock->timeout = 600; + $lock->created = strtotime('2015-03-25 19:21:00'); + $lock->scope = LockInfo::SHARED; + $lock->depth = 0; + $lock->uri = 'hi'; + + $prop = new LockDiscovery([$lock]); + + $xml = $this->write(['{DAV:}root' => $prop]); + + $this->assertXmlStringEqualsXmlString( +'<?xml version="1.0"?> +<d:root xmlns:d="DAV:"> + <d:activelock> + <d:lockscope><d:shared /></d:lockscope> + <d:locktype><d:write /></d:locktype> + <d:lockroot> + <d:href>/hi</d:href> + </d:lockroot> + <d:depth>0</d:depth> + <d:timeout>Second-600</d:timeout> + <d:locktoken> + <d:href>opaquelocktoken:blabla</d:href> + </d:locktoken> + <d:owner>hello</d:owner> + + +</d:activelock> +</d:root> +', $xml); + + } + +} diff --git a/vendor/sabre/dav/tests/Sabre/DAV/Xml/Property/ShareAccessTest.php b/vendor/sabre/dav/tests/Sabre/DAV/Xml/Property/ShareAccessTest.php new file mode 100644 index 000000000..6e733dded --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/DAV/Xml/Property/ShareAccessTest.php @@ -0,0 +1,121 @@ +<?php + +namespace Sabre\DAV\Xml\Property; + +use Sabre\DAV\Sharing\Plugin; +use Sabre\DAV\Xml\XmlTest; + +class ShareAccessTest extends XmlTest { + + function testSerialize() { + + $data = ['{DAV:}root' => [ + [ + 'name' => '{DAV:}share-access', + 'value' => new ShareAccess(Plugin::ACCESS_READ), + ], + [ + 'name' => '{DAV:}share-access', + 'value' => new ShareAccess(Plugin::ACCESS_READWRITE), + ], + [ + 'name' => '{DAV:}share-access', + 'value' => new ShareAccess(Plugin::ACCESS_NOTSHARED), + ], + [ + 'name' => '{DAV:}share-access', + 'value' => new ShareAccess(Plugin::ACCESS_NOACCESS), + ], + [ + 'name' => '{DAV:}share-access', + 'value' => new ShareAccess(Plugin::ACCESS_SHAREDOWNER), + ], + + ]]; + + $xml = $this->write($data); + + $expected = <<<XML +<?xml version="1.0"?> +<d:root xmlns:d="DAV:"> + <d:share-access><d:read /></d:share-access> + <d:share-access><d:read-write /></d:share-access> + <d:share-access><d:not-shared /></d:share-access> + <d:share-access><d:no-access /></d:share-access> + <d:share-access><d:shared-owner /></d:share-access> +</d:root> +XML; + + $this->assertXmlStringEqualsXmlString($expected, $xml); + + } + + function testDeserialize() { + + $input = <<<XML +<?xml version="1.0"?> +<d:root xmlns:d="DAV:"> + <d:share-access><d:read /></d:share-access> + <d:share-access><d:read-write /></d:share-access> + <d:share-access><d:not-shared /></d:share-access> + <d:share-access><d:no-access /></d:share-access> + <d:share-access><d:shared-owner /></d:share-access> +</d:root> +XML; + + $data = [ + [ + 'name' => '{DAV:}share-access', + 'value' => new ShareAccess(Plugin::ACCESS_READ), + 'attributes' => [], + ], + [ + 'name' => '{DAV:}share-access', + 'value' => new ShareAccess(Plugin::ACCESS_READWRITE), + 'attributes' => [], + ], + [ + 'name' => '{DAV:}share-access', + 'value' => new ShareAccess(Plugin::ACCESS_NOTSHARED), + 'attributes' => [], + ], + [ + 'name' => '{DAV:}share-access', + 'value' => new ShareAccess(Plugin::ACCESS_NOACCESS), + 'attributes' => [], + ], + [ + 'name' => '{DAV:}share-access', + 'value' => new ShareAccess(Plugin::ACCESS_SHAREDOWNER), + 'attributes' => [], + ], + + ]; + + $this->assertParsedValue( + $data, + $input, + ['{DAV:}share-access' => ShareAccess::class] + ); + + } + + /** + * @expectedException \Sabre\DAV\Exception\BadRequest + */ + function testDeserializeInvalid() { + + $input = <<<XML +<?xml version="1.0"?> +<d:root xmlns:d="DAV:"> + <d:share-access><d:foo /></d:share-access> +</d:root> +XML; + + $this->parse( + $input, + ['{DAV:}share-access' => ShareAccess::class] + ); + + } +} diff --git a/vendor/sabre/dav/tests/Sabre/DAV/Xml/Property/SupportedMethodSetTest.php b/vendor/sabre/dav/tests/Sabre/DAV/Xml/Property/SupportedMethodSetTest.php new file mode 100644 index 000000000..3d54acd2d --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/DAV/Xml/Property/SupportedMethodSetTest.php @@ -0,0 +1,45 @@ +<?php + +namespace Sabre\DAV\Xml\Property; + +use Sabre\DAV\Xml\XmlTest; + +class SupportedMethodSetTest extends XmlTest { + + function testSimple() { + + $cus = new SupportedMethodSet(['GET', 'PUT']); + $this->assertEquals(['GET', 'PUT'], $cus->getValue()); + + $this->assertTrue($cus->has('GET')); + $this->assertFalse($cus->has('HEAD')); + + } + + function testSerialize() { + + $cus = new SupportedMethodSet(['GET', 'PUT']); + $xml = $this->write(['{DAV:}foo' => $cus]); + + $expected = '<?xml version="1.0"?> +<d:foo xmlns:d="DAV:"> + <d:supported-method name="GET"/> + <d:supported-method name="PUT"/> +</d:foo>'; + + $this->assertXmlStringEqualsXmlString($expected, $xml); + + } + + function testSerializeHtml() { + + $cus = new SupportedMethodSet(['GET', 'PUT']); + $result = $cus->toHtml( + new \Sabre\DAV\Browser\HtmlOutputHelper('/', []) + ); + + $this->assertEquals('GET, PUT', $result); + + } + +} diff --git a/vendor/sabre/dav/tests/Sabre/DAV/Xml/Property/SupportedReportSetTest.php b/vendor/sabre/dav/tests/Sabre/DAV/Xml/Property/SupportedReportSetTest.php new file mode 100644 index 000000000..cc25697f6 --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/DAV/Xml/Property/SupportedReportSetTest.php @@ -0,0 +1,115 @@ +<?php + +namespace Sabre\DAV\Property; + +use Sabre\DAV; +use Sabre\HTTP; + +require_once 'Sabre/HTTP/ResponseMock.php'; +require_once 'Sabre/DAV/AbstractServer.php'; + +class SupportedReportSetTest extends DAV\AbstractServer { + + function sendPROPFIND($body) { + + $serverVars = [ + 'REQUEST_URI' => '/', + 'REQUEST_METHOD' => 'PROPFIND', + 'HTTP_DEPTH' => '0', + ]; + + $request = HTTP\Sapi::createFromServerArray($serverVars); + $request->setBody($body); + + $this->server->httpRequest = ($request); + $this->server->exec(); + + } + + /** + */ + function testNoReports() { + + $xml = '<?xml version="1.0"?> +<d:propfind xmlns:d="DAV:"> + <d:prop> + <d:supported-report-set /> + </d:prop> +</d:propfind>'; + + $this->sendPROPFIND($xml); + + $this->assertEquals(207, $this->response->status, 'We expected a multi-status response. Full response body: ' . $this->response->body); + + $body = preg_replace("/xmlns(:[A-Za-z0-9_])?=(\"|\')DAV:(\"|\')/", "xmlns\\1=\"urn:DAV\"", $this->response->body); + $xml = simplexml_load_string($body); + $xml->registerXPathNamespace('d', 'urn:DAV'); + + $data = $xml->xpath('/d:multistatus/d:response/d:propstat/d:prop'); + $this->assertEquals(1, count($data), 'We expected 1 \'d:prop\' element'); + + $data = $xml->xpath('/d:multistatus/d:response/d:propstat/d:prop/d:supported-report-set'); + $this->assertEquals(1, count($data), 'We expected 1 \'d:supported-report-set\' element'); + + $data = $xml->xpath('/d:multistatus/d:response/d:propstat/d:status'); + $this->assertEquals(1, count($data), 'We expected 1 \'d:status\' element'); + + $this->assertEquals('HTTP/1.1 200 OK', (string)$data[0], 'The status for this property should have been 200'); + + } + + /** + * @depends testNoReports + */ + function testCustomReport() { + + // Intercepting the report property + $this->server->on('propFind', function(DAV\PropFind $propFind, DAV\INode $node) { + if ($prop = $propFind->get('{DAV:}supported-report-set')) { + $prop->addReport('{http://www.rooftopsolutions.nl/testnamespace}myreport'); + $prop->addReport('{DAV:}anotherreport'); + } + }, 200); + + $xml = '<?xml version="1.0"?> +<d:propfind xmlns:d="DAV:"> + <d:prop> + <d:supported-report-set /> + </d:prop> +</d:propfind>'; + + $this->sendPROPFIND($xml); + + $this->assertEquals(207, $this->response->status, 'We expected a multi-status response. Full response body: ' . $this->response->body); + + $body = preg_replace("/xmlns(:[A-Za-z0-9_])?=(\"|\')DAV:(\"|\')/", "xmlns\\1=\"urn:DAV\"", $this->response->body); + $xml = simplexml_load_string($body); + $xml->registerXPathNamespace('d', 'urn:DAV'); + $xml->registerXPathNamespace('x', 'http://www.rooftopsolutions.nl/testnamespace'); + + $data = $xml->xpath('/d:multistatus/d:response/d:propstat/d:prop'); + $this->assertEquals(1, count($data), 'We expected 1 \'d:prop\' element'); + + $data = $xml->xpath('/d:multistatus/d:response/d:propstat/d:prop/d:supported-report-set'); + $this->assertEquals(1, count($data), 'We expected 1 \'d:supported-report-set\' element'); + + $data = $xml->xpath('/d:multistatus/d:response/d:propstat/d:prop/d:supported-report-set/d:supported-report'); + $this->assertEquals(2, count($data), 'We expected 2 \'d:supported-report\' elements'); + + $data = $xml->xpath('/d:multistatus/d:response/d:propstat/d:prop/d:supported-report-set/d:supported-report/d:report'); + $this->assertEquals(2, count($data), 'We expected 2 \'d:report\' elements'); + + $data = $xml->xpath('/d:multistatus/d:response/d:propstat/d:prop/d:supported-report-set/d:supported-report/d:report/x:myreport'); + $this->assertEquals(1, count($data), 'We expected 1 \'x:myreport\' element. Full body: ' . $this->response->body); + + $data = $xml->xpath('/d:multistatus/d:response/d:propstat/d:prop/d:supported-report-set/d:supported-report/d:report/d:anotherreport'); + $this->assertEquals(1, count($data), 'We expected 1 \'d:anotherreport\' element. Full body: ' . $this->response->body); + + $data = $xml->xpath('/d:multistatus/d:response/d:propstat/d:status'); + $this->assertEquals(1, count($data), 'We expected 1 \'d:status\' element'); + + $this->assertEquals('HTTP/1.1 200 OK', (string)$data[0], 'The status for this property should have been 200'); + + } + +} diff --git a/vendor/sabre/dav/tests/Sabre/DAV/Xml/Request/PropFindTest.php b/vendor/sabre/dav/tests/Sabre/DAV/Xml/Request/PropFindTest.php new file mode 100644 index 000000000..c11668b61 --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/DAV/Xml/Request/PropFindTest.php @@ -0,0 +1,48 @@ +<?php + +namespace Sabre\DAV\Xml\Request; + +use Sabre\DAV\Xml\XmlTest; + +class PropFindTest extends XmlTest { + + function testDeserializeProp() { + + $xml = '<?xml version="1.0"?> +<d:root xmlns:d="DAV:"> + <d:prop> + <d:hello /> + </d:prop> +</d:root> +'; + + $result = $this->parse($xml, ['{DAV:}root' => 'Sabre\\DAV\\Xml\\Request\PropFind']); + + $propFind = new PropFind(); + $propFind->properties = ['{DAV:}hello']; + + $this->assertEquals($propFind, $result['value']); + + + } + + function testDeserializeAllProp() { + + $xml = '<?xml version="1.0"?> +<d:root xmlns:d="DAV:"> + <d:allprop /> +</d:root> +'; + + $result = $this->parse($xml, ['{DAV:}root' => 'Sabre\\DAV\\Xml\\Request\PropFind']); + + $propFind = new PropFind(); + $propFind->allProp = true; + + $this->assertEquals($propFind, $result['value']); + + + } + + +} diff --git a/vendor/sabre/dav/tests/Sabre/DAV/Xml/Request/PropPatchTest.php b/vendor/sabre/dav/tests/Sabre/DAV/Xml/Request/PropPatchTest.php new file mode 100644 index 000000000..03514da5c --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/DAV/Xml/Request/PropPatchTest.php @@ -0,0 +1,53 @@ +<?php + +namespace Sabre\DAV\Xml\Request; + +use Sabre\DAV\Xml\Property\Href; +use Sabre\DAV\Xml\XmlTest; + +class PropPatchTest extends XmlTest { + + function testSerialize() { + + $propPatch = new PropPatch(); + $propPatch->properties = [ + '{DAV:}displayname' => 'Hello!', + '{DAV:}delete-me' => null, + '{DAV:}some-url' => new Href('foo/bar') + ]; + + $result = $this->write( + ['{DAV:}propertyupdate' => $propPatch] + ); + + $expected = <<<XML +<?xml version="1.0"?> +<d:propertyupdate xmlns:d="DAV:"> + <d:set> + <d:prop> + <d:displayname>Hello!</d:displayname> + </d:prop> + </d:set> + <d:remove> + <d:prop> + <d:delete-me /> + </d:prop> + </d:remove> + <d:set> + <d:prop> + <d:some-url> + <d:href>/foo/bar</d:href> + </d:some-url> + </d:prop> + </d:set> +</d:propertyupdate> +XML; + + $this->assertXmlStringEqualsXmlString( + $expected, + $result + ); + + } + +} diff --git a/vendor/sabre/dav/tests/Sabre/DAV/Xml/Request/ShareResourceTest.php b/vendor/sabre/dav/tests/Sabre/DAV/Xml/Request/ShareResourceTest.php new file mode 100644 index 000000000..1e6b5602d --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/DAV/Xml/Request/ShareResourceTest.php @@ -0,0 +1,75 @@ +<?php + +namespace Sabre\DAV\Xml\Request; + +use Sabre\DAV\Sharing\Plugin; +use Sabre\DAV\Xml\Element\Sharee; +use Sabre\DAV\Xml\XmlTest; + +class ShareResourceTest extends XmlTest { + + function testDeserialize() { + + $xml = <<<XML +<?xml version="1.0" encoding="utf-8" ?> +<D:share-resource xmlns:D="DAV:"> + <D:sharee> + <D:href>mailto:eric@example.com</D:href> + <D:prop> + <D:displayname>Eric York</D:displayname> + </D:prop> + <D:comment>Shared workspace</D:comment> + <D:share-access> + <D:read-write /> + </D:share-access> + </D:sharee> + <D:sharee> + <D:href>mailto:eric@example.com</D:href> + <D:share-access> + <D:read /> + </D:share-access> + </D:sharee> + <D:sharee> + <D:href>mailto:wilfredo@example.com</D:href> + <D:share-access> + <D:no-access /> + </D:share-access> + </D:sharee> +</D:share-resource> +XML; + + $result = $this->parse($xml, [ + '{DAV:}share-resource' => 'Sabre\\DAV\\Xml\\Request\\ShareResource' + ]); + + $this->assertInstanceOf( + 'Sabre\\DAV\\Xml\\Request\\ShareResource', + $result['value'] + ); + + $expected = [ + new Sharee(), + new Sharee(), + new Sharee(), + ]; + + $expected[0]->href = 'mailto:eric@example.com'; + $expected[0]->properties['{DAV:}displayname'] = 'Eric York'; + $expected[0]->comment = 'Shared workspace'; + $expected[0]->access = Plugin::ACCESS_READWRITE; + + $expected[1]->href = 'mailto:eric@example.com'; + $expected[1]->access = Plugin::ACCESS_READ; + + $expected[2]->href = 'mailto:wilfredo@example.com'; + $expected[2]->access = Plugin::ACCESS_NOACCESS; + + $this->assertEquals( + $expected, + $result['value']->sharees + ); + + } + + +} diff --git a/vendor/sabre/dav/tests/Sabre/DAV/Xml/Request/SyncCollectionTest.php b/vendor/sabre/dav/tests/Sabre/DAV/Xml/Request/SyncCollectionTest.php new file mode 100644 index 000000000..bde1a103d --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/DAV/Xml/Request/SyncCollectionTest.php @@ -0,0 +1,94 @@ +<?php + +namespace Sabre\DAV\Xml\Request; + +use Sabre\DAV\Xml\XmlTest; + +class SyncCollectionTest extends XmlTest { + + function testDeserializeProp() { + + $xml = '<?xml version="1.0"?> +<d:sync-collection xmlns:d="DAV:"> + <d:sync-token /> + <d:sync-level>1</d:sync-level> + <d:prop> + <d:foo /> + </d:prop> +</d:sync-collection> +'; + + $result = $this->parse($xml, ['{DAV:}sync-collection' => 'Sabre\\DAV\\Xml\\Request\\SyncCollectionReport']); + + $elem = new SyncCollectionReport(); + $elem->syncLevel = 1; + $elem->properties = ['{DAV:}foo']; + + $this->assertEquals($elem, $result['value']); + + } + + + function testDeserializeLimit() { + + $xml = '<?xml version="1.0"?> +<d:sync-collection xmlns:d="DAV:"> + <d:sync-token /> + <d:sync-level>1</d:sync-level> + <d:prop> + <d:foo /> + </d:prop> + <d:limit><d:nresults>5</d:nresults></d:limit> +</d:sync-collection> +'; + + $result = $this->parse($xml, ['{DAV:}sync-collection' => 'Sabre\\DAV\\Xml\\Request\\SyncCollectionReport']); + + $elem = new SyncCollectionReport(); + $elem->syncLevel = 1; + $elem->properties = ['{DAV:}foo']; + $elem->limit = 5; + + $this->assertEquals($elem, $result['value']); + + } + + + function testDeserializeInfinity() { + + $xml = '<?xml version="1.0"?> +<d:sync-collection xmlns:d="DAV:"> + <d:sync-token /> + <d:sync-level>infinity</d:sync-level> + <d:prop> + <d:foo /> + </d:prop> +</d:sync-collection> +'; + + $result = $this->parse($xml, ['{DAV:}sync-collection' => 'Sabre\\DAV\\Xml\\Request\\SyncCollectionReport']); + + $elem = new SyncCollectionReport(); + $elem->syncLevel = \Sabre\DAV\Server::DEPTH_INFINITY; + $elem->properties = ['{DAV:}foo']; + + $this->assertEquals($elem, $result['value']); + + } + + /** + * @expectedException \Sabre\DAV\Exception\BadRequest + */ + function testDeserializeMissingElem() { + + $xml = '<?xml version="1.0"?> +<d:sync-collection xmlns:d="DAV:"> + <d:sync-token /> +</d:sync-collection> +'; + + $result = $this->parse($xml, ['{DAV:}sync-collection' => 'Sabre\\DAV\\Xml\\Request\\SyncCollectionReport']); + + } + +} diff --git a/vendor/sabre/dav/tests/Sabre/DAV/Xml/XmlTest.php b/vendor/sabre/dav/tests/Sabre/DAV/Xml/XmlTest.php new file mode 100644 index 000000000..906a36085 --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/DAV/Xml/XmlTest.php @@ -0,0 +1,48 @@ +<?php + +namespace Sabre\DAV\Xml; + +use Sabre\Xml\Reader; +use Sabre\Xml\Writer; + +abstract class XmlTest extends \PHPUnit_Framework_TestCase { + + protected $elementMap = []; + protected $namespaceMap = ['DAV:' => 'd']; + protected $contextUri = '/'; + + function write($input) { + + $writer = new Writer(); + $writer->contextUri = $this->contextUri; + $writer->namespaceMap = $this->namespaceMap; + $writer->openMemory(); + $writer->setIndent(true); + $writer->write($input); + return $writer->outputMemory(); + + } + + function parse($xml, array $elementMap = []) { + + $reader = new Reader(); + $reader->elementMap = array_merge($this->elementMap, $elementMap); + $reader->xml($xml); + return $reader->parse(); + + } + + function assertParsedValue($expected, $xml, array $elementMap = []) { + + $result = $this->parse($xml, $elementMap); + $this->assertEquals($expected, $result['value']); + + } + + function cleanUp() { + + libxml_clear_errors(); + + } + +} diff --git a/vendor/sabre/dav/tests/Sabre/DAVACL/ACLMethodTest.php b/vendor/sabre/dav/tests/Sabre/DAVACL/ACLMethodTest.php new file mode 100644 index 000000000..7d7a54d06 --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/DAVACL/ACLMethodTest.php @@ -0,0 +1,337 @@ +<?php + +namespace Sabre\DAVACL; + +use Sabre\DAV; +use Sabre\HTTP; + +class ACLMethodTest extends \PHPUnit_Framework_TestCase { + + /** + * @expectedException Sabre\DAV\Exception\BadRequest + */ + function testCallback() { + + $acl = new Plugin(); + $server = new DAV\Server(); + $server->addPlugin(new DAV\Auth\Plugin()); + $server->addPlugin($acl); + + $acl->httpAcl($server->httpRequest, $server->httpResponse); + + } + + /** + /** + * @expectedException Sabre\DAV\Exception\MethodNotAllowed + */ + function testNotSupportedByNode() { + + $tree = [ + new DAV\SimpleCollection('test'), + ]; + $acl = new Plugin(); + $server = new DAV\Server($tree); + $server->httpRequest = new HTTP\Request(); + $body = '<?xml version="1.0"?> +<d:acl xmlns:d="DAV:"> +</d:acl>'; + $server->httpRequest->setBody($body); + $server->addPlugin(new DAV\Auth\Plugin()); + $server->addPlugin($acl); + + $acl->httpACL($server->httpRequest, $server->httpResponse); + + } + + function testSuccessSimple() { + + $tree = [ + new MockACLNode('test', []), + ]; + $acl = new Plugin(); + $server = new DAV\Server($tree); + $server->httpRequest = new HTTP\Request(); + $server->httpRequest->setUrl('/test'); + + $body = '<?xml version="1.0"?> +<d:acl xmlns:d="DAV:"> +</d:acl>'; + $server->httpRequest->setBody($body); + $server->addPlugin(new DAV\Auth\Plugin()); + $server->addPlugin($acl); + + $this->assertFalse($acl->httpACL($server->httpRequest, $server->httpResponse)); + + } + + /** + * @expectedException Sabre\DAVACL\Exception\NotRecognizedPrincipal + */ + function testUnrecognizedPrincipal() { + + $tree = [ + new MockACLNode('test', []), + ]; + $acl = new Plugin(); + $server = new DAV\Server($tree); + $server->httpRequest = new HTTP\Request('ACL', '/test'); + $body = '<?xml version="1.0"?> +<d:acl xmlns:d="DAV:"> + <d:ace> + <d:grant><d:privilege><d:read /></d:privilege></d:grant> + <d:principal><d:href>/principals/notfound</d:href></d:principal> + </d:ace> +</d:acl>'; + $server->httpRequest->setBody($body); + $server->addPlugin(new DAV\Auth\Plugin()); + $server->addPlugin($acl); + + $acl->httpACL($server->httpRequest, $server->httpResponse); + + } + + /** + * @expectedException Sabre\DAVACL\Exception\NotRecognizedPrincipal + */ + function testUnrecognizedPrincipal2() { + + $tree = [ + new MockACLNode('test', []), + new DAV\SimpleCollection('principals', [ + new DAV\SimpleCollection('notaprincipal'), + ]), + ]; + $acl = new Plugin(); + $server = new DAV\Server($tree); + $server->httpRequest = new HTTP\Request('ACL', '/test'); + $body = '<?xml version="1.0"?> +<d:acl xmlns:d="DAV:"> + <d:ace> + <d:grant><d:privilege><d:read /></d:privilege></d:grant> + <d:principal><d:href>/principals/notaprincipal</d:href></d:principal> + </d:ace> +</d:acl>'; + $server->httpRequest->setBody($body); + $server->addPlugin(new DAV\Auth\Plugin()); + $server->addPlugin($acl); + + $acl->httpACL($server->httpRequest, $server->httpResponse); + + } + + /** + * @expectedException Sabre\DAVACL\Exception\NotSupportedPrivilege + */ + function testUnknownPrivilege() { + + $tree = [ + new MockACLNode('test', []), + ]; + $acl = new Plugin(); + $server = new DAV\Server($tree); + $server->httpRequest = new HTTP\Request('ACL', '/test'); + $body = '<?xml version="1.0"?> +<d:acl xmlns:d="DAV:"> + <d:ace> + <d:grant><d:privilege><d:bananas /></d:privilege></d:grant> + <d:principal><d:href>/principals/notfound</d:href></d:principal> + </d:ace> +</d:acl>'; + $server->httpRequest->setBody($body); + $server->addPlugin(new DAV\Auth\Plugin()); + $server->addPlugin($acl); + + $acl->httpACL($server->httpRequest, $server->httpResponse); + + } + + /** + * @expectedException Sabre\DAVACL\Exception\NoAbstract + */ + function testAbstractPrivilege() { + + $tree = [ + new MockACLNode('test', []), + ]; + $acl = new Plugin(); + $server = new DAV\Server($tree); + $server->on('getSupportedPrivilegeSet', function($node, &$supportedPrivilegeSet) { + $supportedPrivilegeSet['{DAV:}foo'] = ['abstract' => true]; + }); + $server->httpRequest = new HTTP\Request('ACL', '/test'); + $body = '<?xml version="1.0"?> +<d:acl xmlns:d="DAV:"> + <d:ace> + <d:grant><d:privilege><d:foo /></d:privilege></d:grant> + <d:principal><d:href>/principals/foo/</d:href></d:principal> + </d:ace> +</d:acl>'; + $server->httpRequest->setBody($body); + $server->addPlugin(new DAV\Auth\Plugin()); + $server->addPlugin($acl); + + $acl->httpACL($server->httpRequest, $server->httpResponse); + + } + + /** + * @expectedException Sabre\DAVACL\Exception\AceConflict + */ + function testUpdateProtectedPrivilege() { + + $oldACL = [ + [ + 'principal' => 'principals/notfound', + 'privilege' => '{DAV:}write', + 'protected' => true, + ], + ]; + + $tree = [ + new MockACLNode('test', $oldACL), + ]; + $acl = new Plugin(); + $server = new DAV\Server($tree); + $server->httpRequest = new HTTP\Request('ACL', '/test'); + $body = '<?xml version="1.0"?> +<d:acl xmlns:d="DAV:"> + <d:ace> + <d:grant><d:privilege><d:read /></d:privilege></d:grant> + <d:principal><d:href>/principals/notfound</d:href></d:principal> + </d:ace> +</d:acl>'; + $server->httpRequest->setBody($body); + $server->addPlugin(new DAV\Auth\Plugin()); + $server->addPlugin($acl); + + $acl->httpACL($server->httpRequest, $server->httpResponse); + + } + + /** + * @expectedException Sabre\DAVACL\Exception\AceConflict + */ + function testUpdateProtectedPrivilege2() { + + $oldACL = [ + [ + 'principal' => 'principals/notfound', + 'privilege' => '{DAV:}write', + 'protected' => true, + ], + ]; + + $tree = [ + new MockACLNode('test', $oldACL), + ]; + $acl = new Plugin(); + $server = new DAV\Server($tree); + $server->httpRequest = new HTTP\Request('ACL', '/test'); + $body = '<?xml version="1.0"?> +<d:acl xmlns:d="DAV:"> + <d:ace> + <d:grant><d:privilege><d:write /></d:privilege></d:grant> + <d:principal><d:href>/principals/foo</d:href></d:principal> + </d:ace> +</d:acl>'; + $server->httpRequest->setBody($body); + $server->addPlugin(new DAV\Auth\Plugin()); + $server->addPlugin($acl); + + $acl->httpACL($server->httpRequest, $server->httpResponse); + + } + + /** + * @expectedException Sabre\DAVACL\Exception\AceConflict + */ + function testUpdateProtectedPrivilege3() { + + $oldACL = [ + [ + 'principal' => 'principals/notfound', + 'privilege' => '{DAV:}write', + 'protected' => true, + ], + ]; + + $tree = [ + new MockACLNode('test', $oldACL), + ]; + $acl = new Plugin(); + $server = new DAV\Server($tree); + $server->httpRequest = new HTTP\Request('ACL', '/test'); + $body = '<?xml version="1.0"?> +<d:acl xmlns:d="DAV:"> + <d:ace> + <d:grant><d:privilege><d:write /></d:privilege></d:grant> + <d:principal><d:href>/principals/notfound</d:href></d:principal> + </d:ace> +</d:acl>'; + $server->httpRequest->setBody($body); + $server->addPlugin(new DAV\Auth\Plugin()); + $server->addPlugin($acl); + + $acl->httpACL($server->httpRequest, $server->httpResponse); + + } + + function testSuccessComplex() { + + $oldACL = [ + [ + 'principal' => 'principals/foo', + 'privilege' => '{DAV:}write', + 'protected' => true, + ], + [ + 'principal' => 'principals/bar', + 'privilege' => '{DAV:}read', + ], + ]; + + $tree = [ + $node = new MockACLNode('test', $oldACL), + new DAV\SimpleCollection('principals', [ + new MockPrincipal('foo', 'principals/foo'), + new MockPrincipal('baz', 'principals/baz'), + ]), + ]; + $acl = new Plugin(); + $server = new DAV\Server($tree); + $server->httpRequest = new HTTP\Request('ACL', '/test'); + $body = '<?xml version="1.0"?> +<d:acl xmlns:d="DAV:"> + <d:ace> + <d:grant><d:privilege><d:write /></d:privilege></d:grant> + <d:principal><d:href>/principals/foo</d:href></d:principal> + <d:protected /> + </d:ace> + <d:ace> + <d:grant><d:privilege><d:write /></d:privilege></d:grant> + <d:principal><d:href>/principals/baz</d:href></d:principal> + </d:ace> +</d:acl>'; + $server->httpRequest->setBody($body); + $server->addPlugin(new DAV\Auth\Plugin()); + $server->addPlugin($acl); + + + $this->assertFalse($acl->httpAcl($server->httpRequest, $server->httpResponse)); + + $this->assertEquals([ + [ + 'principal' => 'principals/foo', + 'privilege' => '{DAV:}write', + 'protected' => true, + ], + [ + 'principal' => 'principals/baz', + 'privilege' => '{DAV:}write', + 'protected' => false, + ], + ], $node->getACL()); + + } +} diff --git a/vendor/sabre/dav/tests/Sabre/DAVACL/AclPrincipalPropSetReportTest.php b/vendor/sabre/dav/tests/Sabre/DAVACL/AclPrincipalPropSetReportTest.php new file mode 100644 index 000000000..338fe36ab --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/DAVACL/AclPrincipalPropSetReportTest.php @@ -0,0 +1,69 @@ +<?php + +namespace Sabre\DAVACL; + +use Sabre\HTTP\Request; + +class AclPrincipalPropSetReportTest extends \Sabre\DAVServerTest { + + public $setupACL = true; + public $autoLogin = 'admin'; + + function testReport() { + + $xml = <<<XML +<?xml version="1.0"?> +<acl-principal-prop-set xmlns="DAV:"> + <prop> + <principal-URL /> + <displayname /> + </prop> +</acl-principal-prop-set> +XML; + + $request = new Request('REPORT', '/principals/user1', ['Content-Type' => 'application/xml', 'Depth' => 0]); + $request->setBody($xml); + + $response = $this->request($request, 207); + + $expected = <<<XML +<?xml version="1.0"?> +<d:multistatus xmlns:d="DAV:" xmlns:s="http://sabredav.org/ns"> + <d:response> + <d:href>/principals/admin/</d:href> + <d:propstat> + <d:prop> + <d:principal-URL><d:href>/principals/admin/</d:href></d:principal-URL> + <d:displayname>Admin</d:displayname> + </d:prop> + <d:status>HTTP/1.1 200 OK</d:status> + </d:propstat> + </d:response> +</d:multistatus> +XML; + + $this->assertXmlStringEqualsXmlString( + $expected, + $response->getBodyAsString() + ); + + } + + function testReportDepth1() { + + $xml = <<<XML +<?xml version="1.0"?> +<acl-principal-prop-set xmlns="DAV:"> + <principal-URL /> + <displayname /> +</acl-principal-prop-set> +XML; + + $request = new Request('REPORT', '/principals/user1', ['Content-Type' => 'application/xml', 'Depth' => 1]); + $request->setBody($xml); + + $this->request($request, 400); + + } + +} diff --git a/vendor/sabre/dav/tests/Sabre/DAVACL/AllowAccessTest.php b/vendor/sabre/dav/tests/Sabre/DAVACL/AllowAccessTest.php new file mode 100644 index 000000000..f16693625 --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/DAVACL/AllowAccessTest.php @@ -0,0 +1,132 @@ +<?php + +namespace Sabre\DAVACL; + +use Sabre\DAV; + +class AllowAccessTest extends \PHPUnit_Framework_TestCase { + + /** + * @var DAV\Server + */ + protected $server; + + function setUp() { + + $nodes = [ + new DAV\Mock\Collection('testdir', [ + 'file1.txt' => 'contents', + ]), + ]; + + $this->server = new DAV\Server($nodes); + $this->server->addPlugin( + new DAV\Auth\Plugin( + new DAV\Auth\Backend\Mock() + ) + ); + // Login + $this->server->getPlugin('auth')->beforeMethod( + new \Sabre\HTTP\Request(), + new \Sabre\HTTP\Response() + ); + $aclPlugin = new Plugin(); + $this->server->addPlugin($aclPlugin); + + } + + function testGet() { + + $this->server->httpRequest->setMethod('GET'); + $this->server->httpRequest->setUrl('/testdir'); + + $this->assertTrue($this->server->emit('beforeMethod', [$this->server->httpRequest, $this->server->httpResponse])); + + } + + function testGetDoesntExist() { + + $this->server->httpRequest->setMethod('GET'); + $this->server->httpRequest->setUrl('/foo'); + + $this->assertTrue($this->server->emit('beforeMethod', [$this->server->httpRequest, $this->server->httpResponse])); + + } + + function testHEAD() { + + $this->server->httpRequest->setMethod('HEAD'); + $this->server->httpRequest->setUrl('/testdir'); + + $this->assertTrue($this->server->emit('beforeMethod', [$this->server->httpRequest, $this->server->httpResponse])); + + } + + function testOPTIONS() { + + $this->server->httpRequest->setMethod('OPTIONS'); + $this->server->httpRequest->setUrl('/testdir'); + + $this->assertTrue($this->server->emit('beforeMethod', [$this->server->httpRequest, $this->server->httpResponse])); + + } + + function testPUT() { + + $this->server->httpRequest->setMethod('PUT'); + $this->server->httpRequest->setUrl('/testdir/file1.txt'); + + $this->assertTrue($this->server->emit('beforeMethod', [$this->server->httpRequest, $this->server->httpResponse])); + + } + + function testPROPPATCH() { + + $this->server->httpRequest->setMethod('PROPPATCH'); + $this->server->httpRequest->setUrl('/testdir'); + + $this->assertTrue($this->server->emit('beforeMethod', [$this->server->httpRequest, $this->server->httpResponse])); + + } + + function testCOPY() { + + $this->server->httpRequest->setMethod('COPY'); + $this->server->httpRequest->setUrl('/testdir'); + + $this->assertTrue($this->server->emit('beforeMethod', [$this->server->httpRequest, $this->server->httpResponse])); + + } + + function testMOVE() { + + $this->server->httpRequest->setMethod('MOVE'); + $this->server->httpRequest->setUrl('/testdir'); + + $this->assertTrue($this->server->emit('beforeMethod', [$this->server->httpRequest, $this->server->httpResponse])); + + } + + function testLOCK() { + + $this->server->httpRequest->setMethod('LOCK'); + $this->server->httpRequest->setUrl('/testdir'); + + $this->assertTrue($this->server->emit('beforeMethod', [$this->server->httpRequest, $this->server->httpResponse])); + + } + + function testBeforeBind() { + + $this->assertTrue($this->server->emit('beforeBind', ['testdir/file'])); + + } + + + function testBeforeUnbind() { + + $this->assertTrue($this->server->emit('beforeUnbind', ['testdir'])); + + } + +} diff --git a/vendor/sabre/dav/tests/Sabre/DAVACL/BlockAccessTest.php b/vendor/sabre/dav/tests/Sabre/DAVACL/BlockAccessTest.php new file mode 100644 index 000000000..ceae9aed0 --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/DAVACL/BlockAccessTest.php @@ -0,0 +1,215 @@ +<?php + +namespace Sabre\DAVACL; + +use Sabre\DAV; + +class BlockAccessTest extends \PHPUnit_Framework_TestCase { + + /** + * @var DAV\Server + */ + protected $server; + protected $plugin; + + function setUp() { + + $nodes = [ + new DAV\SimpleCollection('testdir'), + ]; + + $this->server = new DAV\Server($nodes); + $this->plugin = new Plugin(); + $this->plugin->setDefaultAcl([]); + $this->server->addPlugin( + new DAV\Auth\Plugin( + new DAV\Auth\Backend\Mock() + ) + ); + // Login + $this->server->getPlugin('auth')->beforeMethod( + new \Sabre\HTTP\Request(), + new \Sabre\HTTP\Response() + ); + $this->server->addPlugin($this->plugin); + + } + + /** + * @expectedException Sabre\DAVACL\Exception\NeedPrivileges + */ + function testGet() { + + $this->server->httpRequest->setMethod('GET'); + $this->server->httpRequest->setUrl('/testdir'); + + $this->server->emit('beforeMethod', [$this->server->httpRequest, $this->server->httpResponse]); + + } + + function testGetDoesntExist() { + + $this->server->httpRequest->setMethod('GET'); + $this->server->httpRequest->setUrl('/foo'); + + $r = $this->server->emit('beforeMethod', [$this->server->httpRequest, $this->server->httpResponse]); + $this->assertTrue($r); + + } + + /** + * @expectedException Sabre\DAVACL\Exception\NeedPrivileges + */ + function testHEAD() { + + $this->server->httpRequest->setMethod('HEAD'); + $this->server->httpRequest->setUrl('/testdir'); + + $this->server->emit('beforeMethod', [$this->server->httpRequest, $this->server->httpResponse]); + + } + + /** + * @expectedException Sabre\DAVACL\Exception\NeedPrivileges + */ + function testOPTIONS() { + + $this->server->httpRequest->setMethod('OPTIONS'); + $this->server->httpRequest->setUrl('/testdir'); + + $this->server->emit('beforeMethod', [$this->server->httpRequest, $this->server->httpResponse]); + + } + + /** + * @expectedException Sabre\DAVACL\Exception\NeedPrivileges + */ + function testPUT() { + + $this->server->httpRequest->setMethod('PUT'); + $this->server->httpRequest->setUrl('/testdir'); + + $this->server->emit('beforeMethod', [$this->server->httpRequest, $this->server->httpResponse]); + + } + + /** + * @expectedException Sabre\DAVACL\Exception\NeedPrivileges + */ + function testPROPPATCH() { + + $this->server->httpRequest->setMethod('PROPPATCH'); + $this->server->httpRequest->setUrl('/testdir'); + + $this->server->emit('beforeMethod', [$this->server->httpRequest, $this->server->httpResponse]); + + } + + /** + * @expectedException Sabre\DAVACL\Exception\NeedPrivileges + */ + function testCOPY() { + + $this->server->httpRequest->setMethod('COPY'); + $this->server->httpRequest->setUrl('/testdir'); + + $this->server->emit('beforeMethod', [$this->server->httpRequest, $this->server->httpResponse]); + + } + + /** + * @expectedException Sabre\DAVACL\Exception\NeedPrivileges + */ + function testMOVE() { + + $this->server->httpRequest->setMethod('MOVE'); + $this->server->httpRequest->setUrl('/testdir'); + + $this->server->emit('beforeMethod', [$this->server->httpRequest, $this->server->httpResponse]); + + } + + /** + * @expectedException Sabre\DAVACL\Exception\NeedPrivileges + */ + function testACL() { + + $this->server->httpRequest->setMethod('ACL'); + $this->server->httpRequest->setUrl('/testdir'); + + $this->server->emit('beforeMethod', [$this->server->httpRequest, $this->server->httpResponse]); + + } + + /** + * @expectedException Sabre\DAVACL\Exception\NeedPrivileges + */ + function testLOCK() { + + $this->server->httpRequest->setMethod('LOCK'); + $this->server->httpRequest->setUrl('/testdir'); + + $this->server->emit('beforeMethod', [$this->server->httpRequest, $this->server->httpResponse]); + + } + + /** + * @expectedException Sabre\DAVACL\Exception\NeedPrivileges + */ + function testBeforeBind() { + + $this->server->emit('beforeBind', ['testdir/file']); + + } + + /** + * @expectedException Sabre\DAVACL\Exception\NeedPrivileges + */ + function testBeforeUnbind() { + + $this->server->emit('beforeUnbind', ['testdir']); + + } + + function testPropFind() { + + $propFind = new DAV\PropFind('testdir', [ + '{DAV:}displayname', + '{DAV:}getcontentlength', + '{DAV:}bar', + '{DAV:}owner', + ]); + + $r = $this->server->emit('propFind', [$propFind, new DAV\SimpleCollection('testdir')]); + $this->assertTrue($r); + + $expected = [ + 200 => [], + 404 => [], + 403 => [ + '{DAV:}displayname' => null, + '{DAV:}getcontentlength' => null, + '{DAV:}bar' => null, + '{DAV:}owner' => null, + ], + ]; + + $this->assertEquals($expected, $propFind->getResultForMultiStatus()); + + } + + function testBeforeGetPropertiesNoListing() { + + $this->plugin->hideNodesFromListings = true; + $propFind = new DAV\PropFind('testdir', [ + '{DAV:}displayname', + '{DAV:}getcontentlength', + '{DAV:}bar', + '{DAV:}owner', + ]); + + $r = $this->server->emit('propFind', [$propFind, new DAV\SimpleCollection('testdir')]); + $this->assertFalse($r); + + } +} diff --git a/vendor/sabre/dav/tests/Sabre/DAVACL/Exception/AceConflictTest.php b/vendor/sabre/dav/tests/Sabre/DAVACL/Exception/AceConflictTest.php new file mode 100644 index 000000000..1cdf2949f --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/DAVACL/Exception/AceConflictTest.php @@ -0,0 +1,39 @@ +<?php + +namespace Sabre\DAVACL\Exception; + +use Sabre\DAV; + +class AceConflictTest extends \PHPUnit_Framework_TestCase { + + function testSerialize() { + + $ex = new AceConflict('message'); + + $server = new DAV\Server(); + $dom = new \DOMDocument('1.0', 'utf-8'); + $root = $dom->createElementNS('DAV:', 'd:root'); + $dom->appendChild($root); + + $ex->serialize($server, $root); + + $xpaths = [ + '/d:root' => 1, + '/d:root/d:no-ace-conflict' => 1, + ]; + + // Reloading because PHP DOM sucks + $dom2 = new \DOMDocument('1.0', 'utf-8'); + $dom2->loadXML($dom->saveXML()); + + $dxpath = new \DOMXPath($dom2); + $dxpath->registerNamespace('d', 'DAV:'); + foreach ($xpaths as $xpath => $count) { + + $this->assertEquals($count, $dxpath->query($xpath)->length, 'Looking for : ' . $xpath . ', we could only find ' . $dxpath->query($xpath)->length . ' elements, while we expected ' . $count); + + } + + } + +} diff --git a/vendor/sabre/dav/tests/Sabre/DAVACL/Exception/NeedPrivilegesExceptionTest.php b/vendor/sabre/dav/tests/Sabre/DAVACL/Exception/NeedPrivilegesExceptionTest.php new file mode 100644 index 000000000..b13e7722d --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/DAVACL/Exception/NeedPrivilegesExceptionTest.php @@ -0,0 +1,49 @@ +<?php + +namespace Sabre\DAVACL\Exception; + +use Sabre\DAV; + +class NeedPrivilegesExceptionTest extends \PHPUnit_Framework_TestCase { + + function testSerialize() { + + $uri = 'foo'; + $privileges = [ + '{DAV:}read', + '{DAV:}write', + ]; + $ex = new NeedPrivileges($uri, $privileges); + + $server = new DAV\Server(); + $dom = new \DOMDocument('1.0', 'utf-8'); + $root = $dom->createElementNS('DAV:', 'd:root'); + $dom->appendChild($root); + + $ex->serialize($server, $root); + + $xpaths = [ + '/d:root' => 1, + '/d:root/d:need-privileges' => 1, + '/d:root/d:need-privileges/d:resource' => 2, + '/d:root/d:need-privileges/d:resource/d:href' => 2, + '/d:root/d:need-privileges/d:resource/d:privilege' => 2, + '/d:root/d:need-privileges/d:resource/d:privilege/d:read' => 1, + '/d:root/d:need-privileges/d:resource/d:privilege/d:write' => 1, + ]; + + // Reloading because PHP DOM sucks + $dom2 = new \DOMDocument('1.0', 'utf-8'); + $dom2->loadXML($dom->saveXML()); + + $dxpath = new \DOMXPath($dom2); + $dxpath->registerNamespace('d', 'DAV:'); + foreach ($xpaths as $xpath => $count) { + + $this->assertEquals($count, $dxpath->query($xpath)->length, 'Looking for : ' . $xpath . ', we could only find ' . $dxpath->query($xpath)->length . ' elements, while we expected ' . $count); + + } + + } + +} diff --git a/vendor/sabre/dav/tests/Sabre/DAVACL/Exception/NoAbstractTest.php b/vendor/sabre/dav/tests/Sabre/DAVACL/Exception/NoAbstractTest.php new file mode 100644 index 000000000..f52b17371 --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/DAVACL/Exception/NoAbstractTest.php @@ -0,0 +1,39 @@ +<?php + +namespace Sabre\DAVACL\Exception; + +use Sabre\DAV; + +class NoAbstractTest extends \PHPUnit_Framework_TestCase { + + function testSerialize() { + + $ex = new NoAbstract('message'); + + $server = new DAV\Server(); + $dom = new \DOMDocument('1.0', 'utf-8'); + $root = $dom->createElementNS('DAV:', 'd:root'); + $dom->appendChild($root); + + $ex->serialize($server, $root); + + $xpaths = [ + '/d:root' => 1, + '/d:root/d:no-abstract' => 1, + ]; + + // Reloading because PHP DOM sucks + $dom2 = new \DOMDocument('1.0', 'utf-8'); + $dom2->loadXML($dom->saveXML()); + + $dxpath = new \DOMXPath($dom2); + $dxpath->registerNamespace('d', 'DAV:'); + foreach ($xpaths as $xpath => $count) { + + $this->assertEquals($count, $dxpath->query($xpath)->length, 'Looking for : ' . $xpath . ', we could only find ' . $dxpath->query($xpath)->length . ' elements, while we expected ' . $count); + + } + + } + +} diff --git a/vendor/sabre/dav/tests/Sabre/DAVACL/Exception/NotRecognizedPrincipalTest.php b/vendor/sabre/dav/tests/Sabre/DAVACL/Exception/NotRecognizedPrincipalTest.php new file mode 100644 index 000000000..df89aaf84 --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/DAVACL/Exception/NotRecognizedPrincipalTest.php @@ -0,0 +1,39 @@ +<?php + +namespace Sabre\DAVACL\Exception; + +use Sabre\DAV; + +class NotRecognizedPrincipalTest extends \PHPUnit_Framework_TestCase { + + function testSerialize() { + + $ex = new NotRecognizedPrincipal('message'); + + $server = new DAV\Server(); + $dom = new \DOMDocument('1.0', 'utf-8'); + $root = $dom->createElementNS('DAV:', 'd:root'); + $dom->appendChild($root); + + $ex->serialize($server, $root); + + $xpaths = [ + '/d:root' => 1, + '/d:root/d:recognized-principal' => 1, + ]; + + // Reloading because PHP DOM sucks + $dom2 = new \DOMDocument('1.0', 'utf-8'); + $dom2->loadXML($dom->saveXML()); + + $dxpath = new \DOMXPath($dom2); + $dxpath->registerNamespace('d', 'DAV:'); + foreach ($xpaths as $xpath => $count) { + + $this->assertEquals($count, $dxpath->query($xpath)->length, 'Looking for : ' . $xpath . ', we could only find ' . $dxpath->query($xpath)->length . ' elements, while we expected ' . $count); + + } + + } + +} diff --git a/vendor/sabre/dav/tests/Sabre/DAVACL/Exception/NotSupportedPrivilegeTest.php b/vendor/sabre/dav/tests/Sabre/DAVACL/Exception/NotSupportedPrivilegeTest.php new file mode 100644 index 000000000..50623952b --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/DAVACL/Exception/NotSupportedPrivilegeTest.php @@ -0,0 +1,39 @@ +<?php + +namespace Sabre\DAVACL\Exception; + +use Sabre\DAV; + +class NotSupportedPrivilegeTest extends \PHPUnit_Framework_TestCase { + + function testSerialize() { + + $ex = new NotSupportedPrivilege('message'); + + $server = new DAV\Server(); + $dom = new \DOMDocument('1.0', 'utf-8'); + $root = $dom->createElementNS('DAV:', 'd:root'); + $dom->appendChild($root); + + $ex->serialize($server, $root); + + $xpaths = [ + '/d:root' => 1, + '/d:root/d:not-supported-privilege' => 1, + ]; + + // Reloading because PHP DOM sucks + $dom2 = new \DOMDocument('1.0', 'utf-8'); + $dom2->loadXML($dom->saveXML()); + + $dxpath = new \DOMXPath($dom2); + $dxpath->registerNamespace('d', 'DAV:'); + foreach ($xpaths as $xpath => $count) { + + $this->assertEquals($count, $dxpath->query($xpath)->length, 'Looking for : ' . $xpath . ', we could only find ' . $dxpath->query($xpath)->length . ' elements, while we expected ' . $count); + + } + + } + +} diff --git a/vendor/sabre/dav/tests/Sabre/DAVACL/ExpandPropertiesTest.php b/vendor/sabre/dav/tests/Sabre/DAVACL/ExpandPropertiesTest.php new file mode 100644 index 000000000..91de64372 --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/DAVACL/ExpandPropertiesTest.php @@ -0,0 +1,317 @@ +<?php + +namespace Sabre\DAVACL; + +use Sabre\DAV; +use Sabre\HTTP; + +require_once 'Sabre/HTTP/ResponseMock.php'; + +class ExpandPropertiesTest extends \PHPUnit_Framework_TestCase { + + function getServer() { + + $tree = [ + new DAV\Mock\PropertiesCollection('node1', [], [ + '{http://sabredav.org/ns}simple' => 'foo', + '{http://sabredav.org/ns}href' => new DAV\Xml\Property\Href('node2'), + '{DAV:}displayname' => 'Node 1', + ]), + new DAV\Mock\PropertiesCollection('node2', [], [ + '{http://sabredav.org/ns}simple' => 'simple', + '{http://sabredav.org/ns}hreflist' => new DAV\Xml\Property\Href(['node1', 'node3']), + '{DAV:}displayname' => 'Node 2', + ]), + new DAV\Mock\PropertiesCollection('node3', [], [ + '{http://sabredav.org/ns}simple' => 'simple', + '{DAV:}displayname' => 'Node 3', + ]), + ]; + + $fakeServer = new DAV\Server($tree); + $fakeServer->sapi = new HTTP\SapiMock(); + $fakeServer->debugExceptions = true; + $fakeServer->httpResponse = new HTTP\ResponseMock(); + $plugin = new Plugin(); + $plugin->allowUnauthenticatedAccess = false; + // Anyone can do anything + $plugin->setDefaultACL([ + [ + 'principal' => '{DAV:}all', + 'privilege' => '{DAV:}all', + ] + ]); + $this->assertTrue($plugin instanceof Plugin); + + $fakeServer->addPlugin($plugin); + $this->assertEquals($plugin, $fakeServer->getPlugin('acl')); + + return $fakeServer; + + } + + function testSimple() { + + $xml = '<?xml version="1.0"?> +<d:expand-property xmlns:d="DAV:"> + <d:property name="displayname" /> + <d:property name="foo" namespace="http://www.sabredav.org/NS/2010/nonexistant" /> + <d:property name="simple" namespace="http://sabredav.org/ns" /> + <d:property name="href" namespace="http://sabredav.org/ns" /> +</d:expand-property>'; + + $serverVars = [ + 'REQUEST_METHOD' => 'REPORT', + 'HTTP_DEPTH' => '0', + 'REQUEST_URI' => '/node1', + ]; + + $request = HTTP\Sapi::createFromServerArray($serverVars); + $request->setBody($xml); + + $server = $this->getServer(); + $server->httpRequest = $request; + + $server->exec(); + + $this->assertEquals(207, $server->httpResponse->status, 'Incorrect status code received. Full body: ' . $server->httpResponse->body); + $this->assertEquals([ + 'X-Sabre-Version' => [DAV\Version::VERSION], + 'Content-Type' => ['application/xml; charset=utf-8'], + ], $server->httpResponse->getHeaders()); + + + $check = [ + '/d:multistatus', + '/d:multistatus/d:response' => 1, + '/d:multistatus/d:response/d:href' => 1, + '/d:multistatus/d:response/d:propstat' => 2, + '/d:multistatus/d:response/d:propstat/d:prop' => 2, + '/d:multistatus/d:response/d:propstat/d:prop/d:displayname' => 1, + '/d:multistatus/d:response/d:propstat/d:prop/s:simple' => 1, + '/d:multistatus/d:response/d:propstat/d:prop/s:href' => 1, + '/d:multistatus/d:response/d:propstat/d:prop/s:href/d:href' => 1, + ]; + + $xml = simplexml_load_string($server->httpResponse->body); + $xml->registerXPathNamespace('d', 'DAV:'); + $xml->registerXPathNamespace('s', 'http://sabredav.org/ns'); + foreach ($check as $v1 => $v2) { + + $xpath = is_int($v1) ? $v2 : $v1; + + $result = $xml->xpath($xpath); + + $count = 1; + if (!is_int($v1)) $count = $v2; + + $this->assertEquals($count, count($result), 'we expected ' . $count . ' appearances of ' . $xpath . ' . We found ' . count($result) . '. Full response: ' . $server->httpResponse->body); + + } + + } + + /** + * @depends testSimple + */ + function testExpand() { + + $xml = '<?xml version="1.0"?> +<d:expand-property xmlns:d="DAV:"> + <d:property name="href" namespace="http://sabredav.org/ns"> + <d:property name="displayname" /> + </d:property> +</d:expand-property>'; + + $serverVars = [ + 'REQUEST_METHOD' => 'REPORT', + 'HTTP_DEPTH' => '0', + 'REQUEST_URI' => '/node1', + ]; + + $request = HTTP\Sapi::createFromServerArray($serverVars); + $request->setBody($xml); + + $server = $this->getServer(); + $server->httpRequest = $request; + + $server->exec(); + + $this->assertEquals(207, $server->httpResponse->status, 'Incorrect response status received. Full response body: ' . $server->httpResponse->body); + $this->assertEquals([ + 'X-Sabre-Version' => [DAV\Version::VERSION], + 'Content-Type' => ['application/xml; charset=utf-8'], + ], $server->httpResponse->getHeaders()); + + + $check = [ + '/d:multistatus', + '/d:multistatus/d:response' => 1, + '/d:multistatus/d:response/d:href' => 1, + '/d:multistatus/d:response/d:propstat' => 1, + '/d:multistatus/d:response/d:propstat/d:prop' => 1, + '/d:multistatus/d:response/d:propstat/d:prop/s:href' => 1, + '/d:multistatus/d:response/d:propstat/d:prop/s:href/d:response' => 1, + '/d:multistatus/d:response/d:propstat/d:prop/s:href/d:response/d:href' => 1, + '/d:multistatus/d:response/d:propstat/d:prop/s:href/d:response/d:propstat' => 1, + '/d:multistatus/d:response/d:propstat/d:prop/s:href/d:response/d:propstat/d:prop' => 1, + '/d:multistatus/d:response/d:propstat/d:prop/s:href/d:response/d:propstat/d:prop/d:displayname' => 1, + ]; + + $xml = simplexml_load_string($server->httpResponse->body); + $xml->registerXPathNamespace('d', 'DAV:'); + $xml->registerXPathNamespace('s', 'http://sabredav.org/ns'); + foreach ($check as $v1 => $v2) { + + $xpath = is_int($v1) ? $v2 : $v1; + + $result = $xml->xpath($xpath); + + $count = 1; + if (!is_int($v1)) $count = $v2; + + $this->assertEquals($count, count($result), 'we expected ' . $count . ' appearances of ' . $xpath . ' . We found ' . count($result) . ' Full response body: ' . $server->httpResponse->getBodyAsString()); + + } + + } + + /** + * @depends testSimple + */ + function testExpandHrefList() { + + $xml = '<?xml version="1.0"?> +<d:expand-property xmlns:d="DAV:"> + <d:property name="hreflist" namespace="http://sabredav.org/ns"> + <d:property name="displayname" /> + </d:property> +</d:expand-property>'; + + $serverVars = [ + 'REQUEST_METHOD' => 'REPORT', + 'HTTP_DEPTH' => '0', + 'REQUEST_URI' => '/node2', + ]; + + $request = HTTP\Sapi::createFromServerArray($serverVars); + $request->setBody($xml); + + $server = $this->getServer(); + $server->httpRequest = $request; + + $server->exec(); + + $this->assertEquals(207, $server->httpResponse->status); + $this->assertEquals([ + 'X-Sabre-Version' => [DAV\Version::VERSION], + 'Content-Type' => ['application/xml; charset=utf-8'], + ], $server->httpResponse->getHeaders()); + + + $check = [ + '/d:multistatus', + '/d:multistatus/d:response' => 1, + '/d:multistatus/d:response/d:href' => 1, + '/d:multistatus/d:response/d:propstat' => 1, + '/d:multistatus/d:response/d:propstat/d:prop' => 1, + '/d:multistatus/d:response/d:propstat/d:prop/s:hreflist' => 1, + '/d:multistatus/d:response/d:propstat/d:prop/s:hreflist/d:response' => 2, + '/d:multistatus/d:response/d:propstat/d:prop/s:hreflist/d:response/d:href' => 2, + '/d:multistatus/d:response/d:propstat/d:prop/s:hreflist/d:response/d:propstat' => 2, + '/d:multistatus/d:response/d:propstat/d:prop/s:hreflist/d:response/d:propstat/d:prop' => 2, + '/d:multistatus/d:response/d:propstat/d:prop/s:hreflist/d:response/d:propstat/d:prop/d:displayname' => 2, + ]; + + $xml = simplexml_load_string($server->httpResponse->body); + $xml->registerXPathNamespace('d', 'DAV:'); + $xml->registerXPathNamespace('s', 'http://sabredav.org/ns'); + foreach ($check as $v1 => $v2) { + + $xpath = is_int($v1) ? $v2 : $v1; + + $result = $xml->xpath($xpath); + + $count = 1; + if (!is_int($v1)) $count = $v2; + + $this->assertEquals($count, count($result), 'we expected ' . $count . ' appearances of ' . $xpath . ' . We found ' . count($result)); + + } + + } + + /** + * @depends testExpand + */ + function testExpandDeep() { + + $xml = '<?xml version="1.0"?> +<d:expand-property xmlns:d="DAV:"> + <d:property name="hreflist" namespace="http://sabredav.org/ns"> + <d:property name="href" namespace="http://sabredav.org/ns"> + <d:property name="displayname" /> + </d:property> + <d:property name="displayname" /> + </d:property> +</d:expand-property>'; + + $serverVars = [ + 'REQUEST_METHOD' => 'REPORT', + 'HTTP_DEPTH' => '0', + 'REQUEST_URI' => '/node2', + ]; + + $request = HTTP\Sapi::createFromServerArray($serverVars); + $request->setBody($xml); + + $server = $this->getServer(); + $server->httpRequest = $request; + + $server->exec(); + + $this->assertEquals(207, $server->httpResponse->status); + $this->assertEquals([ + 'X-Sabre-Version' => [DAV\Version::VERSION], + 'Content-Type' => ['application/xml; charset=utf-8'], + ], $server->httpResponse->getHeaders()); + + + $check = [ + '/d:multistatus', + '/d:multistatus/d:response' => 1, + '/d:multistatus/d:response/d:href' => 1, + '/d:multistatus/d:response/d:propstat' => 1, + '/d:multistatus/d:response/d:propstat/d:prop' => 1, + '/d:multistatus/d:response/d:propstat/d:prop/s:hreflist' => 1, + '/d:multistatus/d:response/d:propstat/d:prop/s:hreflist/d:response' => 2, + '/d:multistatus/d:response/d:propstat/d:prop/s:hreflist/d:response/d:href' => 2, + '/d:multistatus/d:response/d:propstat/d:prop/s:hreflist/d:response/d:propstat' => 3, + '/d:multistatus/d:response/d:propstat/d:prop/s:hreflist/d:response/d:propstat/d:prop' => 3, + '/d:multistatus/d:response/d:propstat/d:prop/s:hreflist/d:response/d:propstat/d:prop/d:displayname' => 2, + '/d:multistatus/d:response/d:propstat/d:prop/s:hreflist/d:response/d:propstat/d:prop/s:href' => 2, + '/d:multistatus/d:response/d:propstat/d:prop/s:hreflist/d:response/d:propstat/d:prop/s:href/d:response' => 1, + '/d:multistatus/d:response/d:propstat/d:prop/s:hreflist/d:response/d:propstat/d:prop/s:href/d:response/d:href' => 1, + '/d:multistatus/d:response/d:propstat/d:prop/s:hreflist/d:response/d:propstat/d:prop/s:href/d:response/d:propstat' => 1, + '/d:multistatus/d:response/d:propstat/d:prop/s:hreflist/d:response/d:propstat/d:prop/s:href/d:response/d:propstat/d:prop' => 1, + '/d:multistatus/d:response/d:propstat/d:prop/s:hreflist/d:response/d:propstat/d:prop/s:href/d:response/d:propstat/d:prop/d:displayname' => 1, + ]; + + $xml = simplexml_load_string($server->httpResponse->body); + $xml->registerXPathNamespace('d', 'DAV:'); + $xml->registerXPathNamespace('s', 'http://sabredav.org/ns'); + foreach ($check as $v1 => $v2) { + + $xpath = is_int($v1) ? $v2 : $v1; + + $result = $xml->xpath($xpath); + + $count = 1; + if (!is_int($v1)) $count = $v2; + + $this->assertEquals($count, count($result), 'we expected ' . $count . ' appearances of ' . $xpath . ' . We found ' . count($result)); + + } + + } +} diff --git a/vendor/sabre/dav/tests/Sabre/DAVACL/FS/CollectionTest.php b/vendor/sabre/dav/tests/Sabre/DAVACL/FS/CollectionTest.php new file mode 100644 index 000000000..af18e7cc0 --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/DAVACL/FS/CollectionTest.php @@ -0,0 +1,44 @@ +<?php + +namespace Sabre\DAVACL\FS; + +class CollectionTest extends FileTest { + + function setUp() { + + $this->path = SABRE_TEMPDIR; + $this->sut = new Collection($this->path, $this->acl, $this->owner); + + } + + function tearDown() { + + \Sabre\TestUtil::clearTempDir(); + + } + + function testGetChildFile() { + + file_put_contents(SABRE_TEMPDIR . '/file.txt', 'hello'); + $child = $this->sut->getChild('file.txt'); + $this->assertInstanceOf('Sabre\\DAVACL\\FS\\File', $child); + + $this->assertEquals('file.txt', $child->getName()); + $this->assertEquals($this->acl, $child->getACL()); + $this->assertEquals($this->owner, $child->getOwner()); + + } + + function testGetChildDirectory() { + + mkdir(SABRE_TEMPDIR . '/dir'); + $child = $this->sut->getChild('dir'); + $this->assertInstanceOf('Sabre\\DAVACL\\FS\\Collection', $child); + + $this->assertEquals('dir', $child->getName()); + $this->assertEquals($this->acl, $child->getACL()); + $this->assertEquals($this->owner, $child->getOwner()); + + } + +} diff --git a/vendor/sabre/dav/tests/Sabre/DAVACL/FS/FileTest.php b/vendor/sabre/dav/tests/Sabre/DAVACL/FS/FileTest.php new file mode 100644 index 000000000..f57b2fa1d --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/DAVACL/FS/FileTest.php @@ -0,0 +1,73 @@ +<?php + +namespace Sabre\DAVACL\FS; + +class FileTest extends \PHPUnit_Framework_TestCase { + + /** + * System under test + * + * @var File + */ + protected $sut; + + protected $path = 'foo'; + protected $acl = [ + [ + 'privilege' => '{DAV:}read', + 'principal' => '{DAV:}authenticated', + ] + ]; + + protected $owner = 'principals/evert'; + + function setUp() { + + $this->sut = new File($this->path, $this->acl, $this->owner); + + } + + function testGetOwner() { + + $this->assertEquals( + $this->owner, + $this->sut->getOwner() + ); + + } + + function testGetGroup() { + + $this->assertNull( + $this->sut->getGroup() + ); + + } + + function testGetACL() { + + $this->assertEquals( + $this->acl, + $this->sut->getACL() + ); + + } + + /** + * @expectedException \Sabre\DAV\Exception\Forbidden + */ + function testSetAcl() { + + $this->sut->setACL([]); + + } + + function testGetSupportedPrivilegeSet() { + + $this->assertNull( + $this->sut->getSupportedPrivilegeSet() + ); + + } + +} diff --git a/vendor/sabre/dav/tests/Sabre/DAVACL/FS/HomeCollectionTest.php b/vendor/sabre/dav/tests/Sabre/DAVACL/FS/HomeCollectionTest.php new file mode 100644 index 000000000..87cfc83e9 --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/DAVACL/FS/HomeCollectionTest.php @@ -0,0 +1,116 @@ +<?php + +namespace Sabre\DAVACL\FS; + +use Sabre\DAVACL\PrincipalBackend\Mock as PrincipalBackend; + +class HomeCollectionTest extends \PHPUnit_Framework_TestCase { + + /** + * System under test + * + * @var HomeCollection + */ + protected $sut; + + protected $path; + protected $name = 'thuis'; + + function setUp() { + + $principalBackend = new PrincipalBackend(); + + $this->path = SABRE_TEMPDIR . '/home'; + + $this->sut = new HomeCollection($principalBackend, $this->path); + $this->sut->collectionName = $this->name; + + + } + + function tearDown() { + + \Sabre\TestUtil::clearTempDir(); + + } + + function testGetName() { + + $this->assertEquals( + $this->name, + $this->sut->getName() + ); + + } + + function testGetChild() { + + $child = $this->sut->getChild('user1'); + $this->assertInstanceOf('Sabre\\DAVACL\\FS\\Collection', $child); + $this->assertEquals('user1', $child->getName()); + + $owner = 'principals/user1'; + $acl = [ + [ + 'privilege' => '{DAV:}all', + 'principal' => '{DAV:}owner', + 'protected' => true, + ], + ]; + + $this->assertEquals($acl, $child->getACL()); + $this->assertEquals($owner, $child->getOwner()); + + } + + function testGetOwner() { + + $this->assertNull( + $this->sut->getOwner() + ); + + } + + function testGetGroup() { + + $this->assertNull( + $this->sut->getGroup() + ); + + } + + function testGetACL() { + + $acl = [ + [ + 'principal' => '{DAV:}authenticated', + 'privilege' => '{DAV:}read', + 'protected' => true, + ] + ]; + + $this->assertEquals( + $acl, + $this->sut->getACL() + ); + + } + + /** + * @expectedException \Sabre\DAV\Exception\Forbidden + */ + function testSetAcl() { + + $this->sut->setACL([]); + + } + + function testGetSupportedPrivilegeSet() { + + $this->assertNull( + $this->sut->getSupportedPrivilegeSet() + ); + + } + +} diff --git a/vendor/sabre/dav/tests/Sabre/DAVACL/MockACLNode.php b/vendor/sabre/dav/tests/Sabre/DAVACL/MockACLNode.php new file mode 100644 index 000000000..2d9744e29 --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/DAVACL/MockACLNode.php @@ -0,0 +1,55 @@ +<?php + +namespace Sabre\DAVACL; + +use Sabre\DAV; + +class MockACLNode extends DAV\Node implements IACL { + + public $name; + public $acl; + + function __construct($name, array $acl = []) { + + $this->name = $name; + $this->acl = $acl; + + } + + function getName() { + + return $this->name; + + } + + function getOwner() { + + return null; + + } + + function getGroup() { + + return null; + + } + + function getACL() { + + return $this->acl; + + } + + function setACL(array $acl) { + + $this->acl = $acl; + + } + + function getSupportedPrivilegeSet() { + + return null; + + } + +} diff --git a/vendor/sabre/dav/tests/Sabre/DAVACL/MockPrincipal.php b/vendor/sabre/dav/tests/Sabre/DAVACL/MockPrincipal.php new file mode 100644 index 000000000..934906802 --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/DAVACL/MockPrincipal.php @@ -0,0 +1,64 @@ +<?php + +namespace Sabre\DAVACL; + +use Sabre\DAV; + +class MockPrincipal extends DAV\Node implements IPrincipal { + + public $name; + public $principalUrl; + public $groupMembership = []; + public $groupMemberSet = []; + + function __construct($name, $principalUrl, array $groupMembership = [], array $groupMemberSet = []) { + + $this->name = $name; + $this->principalUrl = $principalUrl; + $this->groupMembership = $groupMembership; + $this->groupMemberSet = $groupMemberSet; + + } + + function getName() { + + return $this->name; + + } + + function getDisplayName() { + + return $this->getName(); + + } + + function getAlternateUriSet() { + + return []; + + } + + function getPrincipalUrl() { + + return $this->principalUrl; + + } + + function getGroupMemberSet() { + + return $this->groupMemberSet; + + } + + function getGroupMemberShip() { + + return $this->groupMembership; + + } + + function setGroupMemberSet(array $groupMemberSet) { + + $this->groupMemberSet = $groupMemberSet; + + } +} diff --git a/vendor/sabre/dav/tests/Sabre/DAVACL/PluginAdminTest.php b/vendor/sabre/dav/tests/Sabre/DAVACL/PluginAdminTest.php new file mode 100644 index 000000000..8552448f5 --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/DAVACL/PluginAdminTest.php @@ -0,0 +1,79 @@ +<?php + +namespace Sabre\DAVACL; + +use Sabre\DAV; +use Sabre\HTTP; + +require_once 'Sabre/DAVACL/MockACLNode.php'; +require_once 'Sabre/HTTP/ResponseMock.php'; + +class PluginAdminTest extends \PHPUnit_Framework_TestCase { + + public $server; + + function setUp() { + + $principalBackend = new PrincipalBackend\Mock(); + + $tree = [ + new MockACLNode('adminonly', []), + new PrincipalCollection($principalBackend), + ]; + + $this->server = new DAV\Server($tree); + $this->server->sapi = new HTTP\SapiMock(); + $plugin = new DAV\Auth\Plugin(new DAV\Auth\Backend\Mock()); + $this->server->addPlugin($plugin); + } + + function testNoAdminAccess() { + + $plugin = new Plugin(); + $this->server->addPlugin($plugin); + + $request = HTTP\Sapi::createFromServerArray([ + 'REQUEST_METHOD' => 'OPTIONS', + 'HTTP_DEPTH' => 1, + 'REQUEST_URI' => '/adminonly', + ]); + + $response = new HTTP\ResponseMock(); + + $this->server->httpRequest = $request; + $this->server->httpResponse = $response; + + $this->server->exec(); + + $this->assertEquals(403, $response->status); + + } + + /** + * @depends testNoAdminAccess + */ + function testAdminAccess() { + + $plugin = new Plugin(); + $plugin->adminPrincipals = [ + 'principals/admin', + ]; + $this->server->addPlugin($plugin); + + $request = HTTP\Sapi::createFromServerArray([ + 'REQUEST_METHOD' => 'OPTIONS', + 'HTTP_DEPTH' => 1, + 'REQUEST_URI' => '/adminonly', + ]); + + $response = new HTTP\ResponseMock(); + + $this->server->httpRequest = $request; + $this->server->httpResponse = $response; + + $this->server->exec(); + + $this->assertEquals(200, $response->status); + + } +} diff --git a/vendor/sabre/dav/tests/Sabre/DAVACL/PluginPropertiesTest.php b/vendor/sabre/dav/tests/Sabre/DAVACL/PluginPropertiesTest.php new file mode 100644 index 000000000..fb42efba7 --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/DAVACL/PluginPropertiesTest.php @@ -0,0 +1,415 @@ +<?php + +namespace Sabre\DAVACL; + +use Sabre\DAV; +use Sabre\HTTP; + +class PluginPropertiesTest extends \PHPUnit_Framework_TestCase { + + function testPrincipalCollectionSet() { + + $plugin = new Plugin(); + $plugin->allowUnauthenticatedAccess = false; + $plugin->setDefaultACL([ + [ + 'principal' => '{DAV:}all', + 'privilege' => '{DAV:}all', + ], + ]); + //Anyone can do anything + $plugin->principalCollectionSet = [ + 'principals1', + 'principals2', + ]; + + $requestedProperties = [ + '{DAV:}principal-collection-set', + ]; + + $server = new DAV\Server(new DAV\SimpleCollection('root')); + $server->addPlugin($plugin); + + $result = $server->getPropertiesForPath('', $requestedProperties); + $result = $result[0]; + + $this->assertEquals(1, count($result[200])); + $this->assertArrayHasKey('{DAV:}principal-collection-set', $result[200]); + $this->assertInstanceOf('Sabre\\DAV\\Xml\\Property\\Href', $result[200]['{DAV:}principal-collection-set']); + + $expected = [ + 'principals1/', + 'principals2/', + ]; + + + $this->assertEquals($expected, $result[200]['{DAV:}principal-collection-set']->getHrefs()); + + + } + + function testCurrentUserPrincipal() { + + $fakeServer = new DAV\Server(); + $plugin = new DAV\Auth\Plugin(new DAV\Auth\Backend\Mock()); + $fakeServer->addPlugin($plugin); + $plugin = new Plugin(); + $plugin->setDefaultACL([ + [ + 'principal' => '{DAV:}all', + 'privilege' => '{DAV:}all', + ], + ]); + $fakeServer->addPlugin($plugin); + + + $requestedProperties = [ + '{DAV:}current-user-principal', + ]; + + $result = $fakeServer->getPropertiesForPath('', $requestedProperties); + $result = $result[0]; + + $this->assertEquals(1, count($result[200])); + $this->assertArrayHasKey('{DAV:}current-user-principal', $result[200]); + $this->assertInstanceOf('Sabre\DAVACL\Xml\Property\Principal', $result[200]['{DAV:}current-user-principal']); + $this->assertEquals(Xml\Property\Principal::UNAUTHENTICATED, $result[200]['{DAV:}current-user-principal']->getType()); + + // This will force the login + $fakeServer->emit('beforeMethod', [$fakeServer->httpRequest, $fakeServer->httpResponse]); + + $result = $fakeServer->getPropertiesForPath('', $requestedProperties); + $result = $result[0]; + + $this->assertEquals(1, count($result[200])); + $this->assertArrayHasKey('{DAV:}current-user-principal', $result[200]); + $this->assertInstanceOf('Sabre\DAVACL\Xml\Property\Principal', $result[200]['{DAV:}current-user-principal']); + $this->assertEquals(Xml\Property\Principal::HREF, $result[200]['{DAV:}current-user-principal']->getType()); + $this->assertEquals('principals/admin/', $result[200]['{DAV:}current-user-principal']->getHref()); + + } + + function testSupportedPrivilegeSet() { + + $plugin = new Plugin(); + $plugin->allowUnauthenticatedAccess = false; + $plugin->setDefaultACL([ + [ + 'principal' => '{DAV:}all', + 'privilege' => '{DAV:}all', + ], + ]); + $server = new DAV\Server(); + $server->addPlugin($plugin); + + $requestedProperties = [ + '{DAV:}supported-privilege-set', + ]; + + $result = $server->getPropertiesForPath('', $requestedProperties); + $result = $result[0]; + + $this->assertEquals(1, count($result[200])); + $this->assertArrayHasKey('{DAV:}supported-privilege-set', $result[200]); + $this->assertInstanceOf('Sabre\\DAVACL\\Xml\\Property\\SupportedPrivilegeSet', $result[200]['{DAV:}supported-privilege-set']); + + $server = new DAV\Server(); + + $prop = $result[200]['{DAV:}supported-privilege-set']; + $result = $server->xml->write('{DAV:}root', $prop); + + $xpaths = [ + '/d:root' => 1, + '/d:root/d:supported-privilege' => 1, + '/d:root/d:supported-privilege/d:privilege' => 1, + '/d:root/d:supported-privilege/d:privilege/d:all' => 1, + '/d:root/d:supported-privilege/d:abstract' => 0, + '/d:root/d:supported-privilege/d:supported-privilege' => 2, + '/d:root/d:supported-privilege/d:supported-privilege/d:privilege' => 2, + '/d:root/d:supported-privilege/d:supported-privilege/d:privilege/d:read' => 1, + '/d:root/d:supported-privilege/d:supported-privilege/d:privilege/d:write' => 1, + '/d:root/d:supported-privilege/d:supported-privilege/d:supported-privilege' => 7, + '/d:root/d:supported-privilege/d:supported-privilege/d:supported-privilege/d:privilege' => 7, + '/d:root/d:supported-privilege/d:supported-privilege/d:supported-privilege/d:privilege/d:read-acl' => 1, + '/d:root/d:supported-privilege/d:supported-privilege/d:supported-privilege/d:privilege/d:read-current-user-privilege-set' => 1, + '/d:root/d:supported-privilege/d:supported-privilege/d:supported-privilege/d:privilege/d:write-content' => 1, + '/d:root/d:supported-privilege/d:supported-privilege/d:supported-privilege/d:privilege/d:write-properties' => 1, + '/d:root/d:supported-privilege/d:supported-privilege/d:supported-privilege/d:privilege/d:bind' => 1, + '/d:root/d:supported-privilege/d:supported-privilege/d:supported-privilege/d:privilege/d:unbind' => 1, + '/d:root/d:supported-privilege/d:supported-privilege/d:supported-privilege/d:privilege/d:unlock' => 1, + '/d:root/d:supported-privilege/d:supported-privilege/d:supported-privilege/d:abstract' => 0, + ]; + + + // reloading because php dom sucks + $dom2 = new \DOMDocument('1.0', 'utf-8'); + $dom2->loadXML($result); + + $dxpath = new \DOMXPath($dom2); + $dxpath->registerNamespace('d', 'DAV:'); + foreach ($xpaths as $xpath => $count) { + + $this->assertEquals($count, $dxpath->query($xpath)->length, 'Looking for : ' . $xpath . ', we could only find ' . $dxpath->query($xpath)->length . ' elements, while we expected ' . $count . ' Full XML: ' . $result); + + } + + } + + function testACL() { + + $plugin = new Plugin(); + $plugin->allowUnauthenticatedAccess = false; + $plugin->setDefaultACL([ + [ + 'principal' => '{DAV:}all', + 'privilege' => '{DAV:}all', + ], + ]); + + $nodes = [ + new MockACLNode('foo', [ + [ + 'principal' => 'principals/admin', + 'privilege' => '{DAV:}read', + ] + ]), + new DAV\SimpleCollection('principals', [ + $principal = new MockPrincipal('admin', 'principals/admin'), + ]), + + ]; + + $server = new DAV\Server($nodes); + $server->addPlugin($plugin); + $authPlugin = new DAV\Auth\Plugin(new DAV\Auth\Backend\Mock()); + $server->addPlugin($authPlugin); + + // Force login + $authPlugin->beforeMethod(new HTTP\Request(), new HTTP\Response()); + + $requestedProperties = [ + '{DAV:}acl', + ]; + + $result = $server->getPropertiesForPath('foo', $requestedProperties); + $result = $result[0]; + + $this->assertEquals(1, count($result[200]), 'The {DAV:}acl property did not return from the list. Full list: ' . print_r($result, true)); + $this->assertArrayHasKey('{DAV:}acl', $result[200]); + $this->assertInstanceOf('Sabre\\DAVACL\\Xml\Property\\Acl', $result[200]['{DAV:}acl']); + + } + + function testACLRestrictions() { + + $plugin = new Plugin(); + $plugin->allowUnauthenticatedAccess = false; + + $nodes = [ + new MockACLNode('foo', [ + [ + 'principal' => 'principals/admin', + 'privilege' => '{DAV:}read', + ] + ]), + new DAV\SimpleCollection('principals', [ + $principal = new MockPrincipal('admin', 'principals/admin'), + ]), + + ]; + + $server = new DAV\Server($nodes); + $server->addPlugin($plugin); + $authPlugin = new DAV\Auth\Plugin(new DAV\Auth\Backend\Mock()); + $server->addPlugin($authPlugin); + + // Force login + $authPlugin->beforeMethod(new HTTP\Request(), new HTTP\Response()); + + $requestedProperties = [ + '{DAV:}acl-restrictions', + ]; + + $result = $server->getPropertiesForPath('foo', $requestedProperties); + $result = $result[0]; + + $this->assertEquals(1, count($result[200]), 'The {DAV:}acl-restrictions property did not return from the list. Full list: ' . print_r($result, true)); + $this->assertArrayHasKey('{DAV:}acl-restrictions', $result[200]); + $this->assertInstanceOf('Sabre\\DAVACL\\Xml\\Property\\AclRestrictions', $result[200]['{DAV:}acl-restrictions']); + + } + + function testAlternateUriSet() { + + $tree = [ + new DAV\SimpleCollection('principals', [ + $principal = new MockPrincipal('user', 'principals/user'), + ]) + ]; + + $fakeServer = new DAV\Server($tree); + //$plugin = new DAV\Auth\Plugin(new DAV\Auth\MockBackend()) + //$fakeServer->addPlugin($plugin); + $plugin = new Plugin(); + $plugin->allowUnauthenticatedAccess = false; + $plugin->setDefaultACL([ + [ + 'principal' => '{DAV:}all', + 'privilege' => '{DAV:}all', + ], + ]); + $fakeServer->addPlugin($plugin); + + $requestedProperties = [ + '{DAV:}alternate-URI-set', + ]; + $result = $fakeServer->getPropertiesForPath('principals/user', $requestedProperties); + $result = $result[0]; + + $this->assertTrue(isset($result[200])); + $this->assertTrue(isset($result[200]['{DAV:}alternate-URI-set'])); + $this->assertInstanceOf('Sabre\\DAV\\Xml\\Property\\Href', $result[200]['{DAV:}alternate-URI-set']); + + $this->assertEquals([], $result[200]['{DAV:}alternate-URI-set']->getHrefs()); + + } + + function testPrincipalURL() { + + $tree = [ + new DAV\SimpleCollection('principals', [ + $principal = new MockPrincipal('user', 'principals/user'), + ]), + ]; + + $fakeServer = new DAV\Server($tree); + //$plugin = new DAV\Auth\Plugin(new DAV\Auth\MockBackend()); + //$fakeServer->addPlugin($plugin); + $plugin = new Plugin(); + $plugin->allowUnauthenticatedAccess = false; + $plugin->setDefaultACL([ + [ + 'principal' => '{DAV:}all', + 'privilege' => '{DAV:}all', + ], + ]); + $fakeServer->addPlugin($plugin); + + $requestedProperties = [ + '{DAV:}principal-URL', + ]; + + $result = $fakeServer->getPropertiesForPath('principals/user', $requestedProperties); + $result = $result[0]; + + $this->assertTrue(isset($result[200])); + $this->assertTrue(isset($result[200]['{DAV:}principal-URL'])); + $this->assertInstanceOf('Sabre\\DAV\\Xml\\Property\\Href', $result[200]['{DAV:}principal-URL']); + + $this->assertEquals('principals/user/', $result[200]['{DAV:}principal-URL']->getHref()); + + } + + function testGroupMemberSet() { + + $tree = [ + new DAV\SimpleCollection('principals', [ + $principal = new MockPrincipal('user', 'principals/user'), + ]), + ]; + + $fakeServer = new DAV\Server($tree); + //$plugin = new DAV\Auth\Plugin(new DAV\Auth\MockBackend()); + //$fakeServer->addPlugin($plugin); + $plugin = new Plugin(); + $plugin->allowUnauthenticatedAccess = false; + $plugin->setDefaultACL([ + [ + 'principal' => '{DAV:}all', + 'privilege' => '{DAV:}all', + ], + ]); + $fakeServer->addPlugin($plugin); + + $requestedProperties = [ + '{DAV:}group-member-set', + ]; + + $result = $fakeServer->getPropertiesForPath('principals/user', $requestedProperties); + $result = $result[0]; + + $this->assertTrue(isset($result[200])); + $this->assertTrue(isset($result[200]['{DAV:}group-member-set'])); + $this->assertInstanceOf('Sabre\\DAV\\Xml\\Property\\Href', $result[200]['{DAV:}group-member-set']); + + $this->assertEquals([], $result[200]['{DAV:}group-member-set']->getHrefs()); + + } + + function testGroupMemberShip() { + + $tree = [ + new DAV\SimpleCollection('principals', [ + $principal = new MockPrincipal('user', 'principals/user'), + ]), + ]; + + $fakeServer = new DAV\Server($tree); + $plugin = new Plugin(); + $plugin->allowUnauthenticatedAccess = false; + $fakeServer->addPlugin($plugin); + $plugin->setDefaultACL([ + [ + 'principal' => '{DAV:}all', + 'privilege' => '{DAV:}all', + ], + ]); + + $requestedProperties = [ + '{DAV:}group-membership', + ]; + + $result = $fakeServer->getPropertiesForPath('principals/user', $requestedProperties); + $result = $result[0]; + + $this->assertTrue(isset($result[200])); + $this->assertTrue(isset($result[200]['{DAV:}group-membership'])); + $this->assertInstanceOf('Sabre\\DAV\\Xml\\Property\\Href', $result[200]['{DAV:}group-membership']); + + $this->assertEquals([], $result[200]['{DAV:}group-membership']->getHrefs()); + + } + + function testGetDisplayName() { + + $tree = [ + new DAV\SimpleCollection('principals', [ + $principal = new MockPrincipal('user', 'principals/user'), + ]), + ]; + + $fakeServer = new DAV\Server($tree); + $plugin = new Plugin(); + $plugin->allowUnauthenticatedAccess = false; + $fakeServer->addPlugin($plugin); + $plugin->setDefaultACL([ + [ + 'principal' => '{DAV:}all', + 'privilege' => '{DAV:}all', + ], + ]); + + $requestedProperties = [ + '{DAV:}displayname', + ]; + + $result = $fakeServer->getPropertiesForPath('principals/user', $requestedProperties); + $result = $result[0]; + + $this->assertTrue(isset($result[200])); + $this->assertTrue(isset($result[200]['{DAV:}displayname'])); + + $this->assertEquals('user', $result[200]['{DAV:}displayname']); + + } +} diff --git a/vendor/sabre/dav/tests/Sabre/DAVACL/PluginUpdatePropertiesTest.php b/vendor/sabre/dav/tests/Sabre/DAVACL/PluginUpdatePropertiesTest.php new file mode 100644 index 000000000..0147e6a61 --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/DAVACL/PluginUpdatePropertiesTest.php @@ -0,0 +1,116 @@ +<?php + +namespace Sabre\DAVACL; + +use Sabre\DAV; + +class PluginUpdatePropertiesTest extends \PHPUnit_Framework_TestCase { + + function testUpdatePropertiesPassthrough() { + + $tree = [ + new DAV\SimpleCollection('foo'), + ]; + $server = new DAV\Server($tree); + $server->addPlugin(new DAV\Auth\Plugin()); + $server->addPlugin(new Plugin()); + + $result = $server->updateProperties('foo', [ + '{DAV:}foo' => 'bar', + ]); + + $expected = [ + '{DAV:}foo' => 403, + ]; + + $this->assertEquals($expected, $result); + + } + + function testRemoveGroupMembers() { + + $tree = [ + new MockPrincipal('foo', 'foo'), + ]; + $server = new DAV\Server($tree); + $plugin = new Plugin(); + $plugin->allowUnauthenticatedAccess = false; + $server->addPlugin($plugin); + + $result = $server->updateProperties('foo', [ + '{DAV:}group-member-set' => null, + ]); + + $expected = [ + '{DAV:}group-member-set' => 204 + ]; + + $this->assertEquals($expected, $result); + $this->assertEquals([], $tree[0]->getGroupMemberSet()); + + } + + function testSetGroupMembers() { + + $tree = [ + new MockPrincipal('foo', 'foo'), + ]; + $server = new DAV\Server($tree); + $plugin = new Plugin(); + $plugin->allowUnauthenticatedAccess = false; + $server->addPlugin($plugin); + + $result = $server->updateProperties('foo', [ + '{DAV:}group-member-set' => new DAV\Xml\Property\Href(['/bar', '/baz'], true), + ]); + + $expected = [ + '{DAV:}group-member-set' => 200 + ]; + + $this->assertEquals($expected, $result); + $this->assertEquals(['bar', 'baz'], $tree[0]->getGroupMemberSet()); + + } + + /** + * @expectedException Sabre\DAV\Exception + */ + function testSetBadValue() { + + $tree = [ + new MockPrincipal('foo', 'foo'), + ]; + $server = new DAV\Server($tree); + $plugin = new Plugin(); + $plugin->allowUnauthenticatedAccess = false; + $server->addPlugin($plugin); + + $result = $server->updateProperties('foo', [ + '{DAV:}group-member-set' => new \StdClass(), + ]); + + } + + function testSetBadNode() { + + $tree = [ + new DAV\SimpleCollection('foo'), + ]; + $server = new DAV\Server($tree); + $plugin = new Plugin(); + $plugin->allowUnauthenticatedAccess = false; + $server->addPlugin($plugin); + + $result = $server->updateProperties('foo', [ + '{DAV:}group-member-set' => new DAV\Xml\Property\Href(['/bar', '/baz'], false), + ]); + + $expected = [ + '{DAV:}group-member-set' => 403, + ]; + + $this->assertEquals($expected, $result); + + } +} diff --git a/vendor/sabre/dav/tests/Sabre/DAVACL/PrincipalBackend/AbstractPDOTest.php b/vendor/sabre/dav/tests/Sabre/DAVACL/PrincipalBackend/AbstractPDOTest.php new file mode 100644 index 000000000..9fef3018d --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/DAVACL/PrincipalBackend/AbstractPDOTest.php @@ -0,0 +1,217 @@ +<?php + +namespace Sabre\DAVACL\PrincipalBackend; + +use Sabre\DAV; +use Sabre\HTTP; + +abstract class AbstractPDOTest extends \PHPUnit_Framework_TestCase { + + use DAV\DbTestHelperTrait; + + function setUp() { + + $this->dropTables(['principals', 'groupmembers']); + $this->createSchema('principals'); + + $pdo = $this->getPDO(); + + $pdo->query("INSERT INTO principals (uri,email,displayname) VALUES ('principals/user','user@example.org','User')"); + $pdo->query("INSERT INTO principals (uri,email,displayname) VALUES ('principals/group','group@example.org','Group')"); + + $pdo->query("INSERT INTO groupmembers (principal_id,member_id) VALUES (5,4)"); + + } + + + function testConstruct() { + + $pdo = $this->getPDO(); + $backend = new PDO($pdo); + $this->assertTrue($backend instanceof PDO); + + } + + /** + * @depends testConstruct + */ + function testGetPrincipalsByPrefix() { + + $pdo = $this->getPDO(); + $backend = new PDO($pdo); + + $expected = [ + [ + 'uri' => 'principals/admin', + '{http://sabredav.org/ns}email-address' => 'admin@example.org', + '{DAV:}displayname' => 'Administrator', + ], + [ + 'uri' => 'principals/user', + '{http://sabredav.org/ns}email-address' => 'user@example.org', + '{DAV:}displayname' => 'User', + ], + [ + 'uri' => 'principals/group', + '{http://sabredav.org/ns}email-address' => 'group@example.org', + '{DAV:}displayname' => 'Group', + ], + ]; + + $this->assertEquals($expected, $backend->getPrincipalsByPrefix('principals')); + $this->assertEquals([], $backend->getPrincipalsByPrefix('foo')); + + } + + /** + * @depends testConstruct + */ + function testGetPrincipalByPath() { + + $pdo = $this->getPDO(); + $backend = new PDO($pdo); + + $expected = [ + 'id' => 4, + 'uri' => 'principals/user', + '{http://sabredav.org/ns}email-address' => 'user@example.org', + '{DAV:}displayname' => 'User', + ]; + + $this->assertEquals($expected, $backend->getPrincipalByPath('principals/user')); + $this->assertEquals(null, $backend->getPrincipalByPath('foo')); + + } + + function testGetGroupMemberSet() { + + $pdo = $this->getPDO(); + $backend = new PDO($pdo); + $expected = ['principals/user']; + + $this->assertEquals($expected, $backend->getGroupMemberSet('principals/group')); + + } + + function testGetGroupMembership() { + + $pdo = $this->getPDO(); + $backend = new PDO($pdo); + $expected = ['principals/group']; + + $this->assertEquals($expected, $backend->getGroupMembership('principals/user')); + + } + + function testSetGroupMemberSet() { + + $pdo = $this->getPDO(); + + // Start situation + $backend = new PDO($pdo); + $this->assertEquals(['principals/user'], $backend->getGroupMemberSet('principals/group')); + + // Removing all principals + $backend->setGroupMemberSet('principals/group', []); + $this->assertEquals([], $backend->getGroupMemberSet('principals/group')); + + // Adding principals again + $backend->setGroupMemberSet('principals/group', ['principals/user']); + $this->assertEquals(['principals/user'], $backend->getGroupMemberSet('principals/group')); + + + } + + function testSearchPrincipals() { + + $pdo = $this->getPDO(); + + $backend = new PDO($pdo); + + $result = $backend->searchPrincipals('principals', ['{DAV:}blabla' => 'foo']); + $this->assertEquals([], $result); + + $result = $backend->searchPrincipals('principals', ['{DAV:}displayname' => 'ou']); + $this->assertEquals(['principals/group'], $result); + + $result = $backend->searchPrincipals('principals', ['{DAV:}displayname' => 'UsEr', '{http://sabredav.org/ns}email-address' => 'USER@EXAMPLE']); + $this->assertEquals(['principals/user'], $result); + + $result = $backend->searchPrincipals('mom', ['{DAV:}displayname' => 'UsEr', '{http://sabredav.org/ns}email-address' => 'USER@EXAMPLE']); + $this->assertEquals([], $result); + + } + + function testUpdatePrincipal() { + + $pdo = $this->getPDO(); + $backend = new PDO($pdo); + + $propPatch = new DAV\PropPatch([ + '{DAV:}displayname' => 'pietje', + ]); + + $backend->updatePrincipal('principals/user', $propPatch); + $result = $propPatch->commit(); + + $this->assertTrue($result); + + $this->assertEquals([ + 'id' => 4, + 'uri' => 'principals/user', + '{DAV:}displayname' => 'pietje', + '{http://sabredav.org/ns}email-address' => 'user@example.org', + ], $backend->getPrincipalByPath('principals/user')); + + } + + function testUpdatePrincipalUnknownField() { + + $pdo = $this->getPDO(); + $backend = new PDO($pdo); + + $propPatch = new DAV\PropPatch([ + '{DAV:}displayname' => 'pietje', + '{DAV:}unknown' => 'foo', + ]); + + $backend->updatePrincipal('principals/user', $propPatch); + $result = $propPatch->commit(); + + $this->assertFalse($result); + + $this->assertEquals([ + '{DAV:}displayname' => 424, + '{DAV:}unknown' => 403 + ], $propPatch->getResult()); + + $this->assertEquals([ + 'id' => '4', + 'uri' => 'principals/user', + '{DAV:}displayname' => 'User', + '{http://sabredav.org/ns}email-address' => 'user@example.org', + ], $backend->getPrincipalByPath('principals/user')); + + } + + function testFindByUriUnknownScheme() { + + $pdo = $this->getPDO(); + $backend = new PDO($pdo); + $this->assertNull($backend->findByUri('http://foo', 'principals')); + + } + + + function testFindByUri() { + + $pdo = $this->getPDO(); + $backend = new PDO($pdo); + $this->assertEquals( + 'principals/user', + $backend->findByUri('mailto:user@example.org', 'principals') + ); + + } + +} diff --git a/vendor/sabre/dav/tests/Sabre/DAVACL/PrincipalBackend/Mock.php b/vendor/sabre/dav/tests/Sabre/DAVACL/PrincipalBackend/Mock.php new file mode 100644 index 000000000..1464f4c26 --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/DAVACL/PrincipalBackend/Mock.php @@ -0,0 +1,168 @@ +<?php + +namespace Sabre\DAVACL\PrincipalBackend; + +class Mock extends AbstractBackend { + + public $groupMembers = []; + public $principals; + + function __construct(array $principals = null) { + + $this->principals = $principals; + + if (is_null($principals)) { + + $this->principals = [ + [ + 'uri' => 'principals/user1', + '{DAV:}displayname' => 'User 1', + '{http://sabredav.org/ns}email-address' => 'user1.sabredav@sabredav.org', + '{http://sabredav.org/ns}vcard-url' => 'addressbooks/user1/book1/vcard1.vcf', + ], + [ + 'uri' => 'principals/admin', + '{DAV:}displayname' => 'Admin', + ], + [ + 'uri' => 'principals/user2', + '{DAV:}displayname' => 'User 2', + '{http://sabredav.org/ns}email-address' => 'user2.sabredav@sabredav.org', + ], + ]; + + } + + } + + function getPrincipalsByPrefix($prefix) { + + $prefix = trim($prefix, '/'); + if ($prefix) $prefix .= '/'; + $return = []; + + foreach ($this->principals as $principal) { + + if ($prefix && strpos($principal['uri'], $prefix) !== 0) continue; + + $return[] = $principal; + + } + + return $return; + + } + + function addPrincipal(array $principal) { + + $this->principals[] = $principal; + + } + + function getPrincipalByPath($path) { + + foreach ($this->getPrincipalsByPrefix('principals') as $principal) { + if ($principal['uri'] === $path) return $principal; + } + + } + + function searchPrincipals($prefixPath, array $searchProperties, $test = 'allof') { + + $matches = []; + foreach ($this->getPrincipalsByPrefix($prefixPath) as $principal) { + + foreach ($searchProperties as $key => $value) { + + if (!isset($principal[$key])) { + continue 2; + } + if (mb_stripos($principal[$key], $value, 0, 'UTF-8') === false) { + continue 2; + } + + // We have a match for this searchProperty! + if ($test === 'allof') { + continue; + } else { + break; + } + + } + $matches[] = $principal['uri']; + + } + return $matches; + + } + + function getGroupMemberSet($path) { + + return isset($this->groupMembers[$path]) ? $this->groupMembers[$path] : []; + + } + + function getGroupMembership($path) { + + $membership = []; + foreach ($this->groupMembers as $group => $members) { + if (in_array($path, $members)) $membership[] = $group; + } + return $membership; + + } + + function setGroupMemberSet($path, array $members) { + + $this->groupMembers[$path] = $members; + + } + + /** + * Updates one ore more webdav properties on a principal. + * + * The list of mutations is stored in a Sabre\DAV\PropPatch object. + * To do the actual updates, you must tell this object which properties + * you're going to process with the handle() method. + * + * Calling the handle method is like telling the PropPatch object "I + * promise I can handle updating this property". + * + * Read the PropPatch documentation for more info and examples. + * + * @param string $path + * @param \Sabre\DAV\PropPatch $propPatch + */ + function updatePrincipal($path, \Sabre\DAV\PropPatch $propPatch) { + + $value = null; + foreach ($this->principals as $principalIndex => $value) { + if ($value['uri'] === $path) { + $principal = $value; + break; + } + } + if (!$principal) return; + + $propPatch->handleRemaining(function($mutations) use ($principal, $principalIndex) { + + foreach ($mutations as $prop => $value) { + + if (is_null($value) && isset($principal[$prop])) { + unset($principal[$prop]); + } else { + $principal[$prop] = $value; + } + + } + + $this->principals[$principalIndex] = $principal; + + return true; + + }); + + } + + +} diff --git a/vendor/sabre/dav/tests/Sabre/DAVACL/PrincipalBackend/PDOMySQLTest.php b/vendor/sabre/dav/tests/Sabre/DAVACL/PrincipalBackend/PDOMySQLTest.php new file mode 100644 index 000000000..8779eb69f --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/DAVACL/PrincipalBackend/PDOMySQLTest.php @@ -0,0 +1,9 @@ +<?php + +namespace Sabre\DAVACL\PrincipalBackend; + +class PDOMySQLTest extends AbstractPDOTest { + + public $driver = 'mysql'; + +} diff --git a/vendor/sabre/dav/tests/Sabre/DAVACL/PrincipalBackend/PDOPgSqlTest.php b/vendor/sabre/dav/tests/Sabre/DAVACL/PrincipalBackend/PDOPgSqlTest.php new file mode 100644 index 000000000..302616e78 --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/DAVACL/PrincipalBackend/PDOPgSqlTest.php @@ -0,0 +1,9 @@ +<?php + +namespace Sabre\DAVACL\PrincipalBackend; + +class PDOPgSqlTest extends AbstractPDOTest { + + public $driver = 'pgsql'; + +} diff --git a/vendor/sabre/dav/tests/Sabre/DAVACL/PrincipalBackend/PDOSqliteTest.php b/vendor/sabre/dav/tests/Sabre/DAVACL/PrincipalBackend/PDOSqliteTest.php new file mode 100644 index 000000000..48454981d --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/DAVACL/PrincipalBackend/PDOSqliteTest.php @@ -0,0 +1,9 @@ +<?php + +namespace Sabre\DAVACL\PrincipalBackend; + +class PDOSqliteTest extends AbstractPDOTest { + + public $driver = 'sqlite'; + +} diff --git a/vendor/sabre/dav/tests/Sabre/DAVACL/PrincipalCollectionTest.php b/vendor/sabre/dav/tests/Sabre/DAVACL/PrincipalCollectionTest.php new file mode 100644 index 000000000..bcf78821b --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/DAVACL/PrincipalCollectionTest.php @@ -0,0 +1,57 @@ +<?php + +namespace Sabre\DAVACL; + +class PrincipalCollectionTest extends \PHPUnit_Framework_TestCase { + + function testBasic() { + + $backend = new PrincipalBackend\Mock(); + $pc = new PrincipalCollection($backend); + $this->assertTrue($pc instanceof PrincipalCollection); + + $this->assertEquals('principals', $pc->getName()); + + } + + /** + * @depends testBasic + */ + function testGetChildren() { + + $backend = new PrincipalBackend\Mock(); + $pc = new PrincipalCollection($backend); + + $children = $pc->getChildren(); + $this->assertTrue(is_array($children)); + + foreach ($children as $child) { + $this->assertTrue($child instanceof IPrincipal); + } + + } + + /** + * @depends testBasic + * @expectedException Sabre\DAV\Exception\MethodNotAllowed + */ + function testGetChildrenDisable() { + + $backend = new PrincipalBackend\Mock(); + $pc = new PrincipalCollection($backend); + $pc->disableListing = true; + + $children = $pc->getChildren(); + + } + + function testFindByUri() { + + $backend = new PrincipalBackend\Mock(); + $pc = new PrincipalCollection($backend); + $this->assertEquals('principals/user1', $pc->findByUri('mailto:user1.sabredav@sabredav.org')); + $this->assertNull($pc->findByUri('mailto:fake.user.sabredav@sabredav.org')); + $this->assertNull($pc->findByUri('')); + } + +} diff --git a/vendor/sabre/dav/tests/Sabre/DAVACL/PrincipalMatchTest.php b/vendor/sabre/dav/tests/Sabre/DAVACL/PrincipalMatchTest.php new file mode 100644 index 000000000..427e37972 --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/DAVACL/PrincipalMatchTest.php @@ -0,0 +1,123 @@ +<?php + +namespace Sabre\DAVACL; + +use Sabre\HTTP\Request; + +class PrincipalMatchTest extends \Sabre\DAVServerTest { + + public $setupACL = true; + public $autoLogin = 'user1'; + + function testPrincipalMatch() { + + $xml = <<<XML +<?xml version="1.0"?> +<principal-match xmlns="DAV:"> + <self /> +</principal-match> +XML; + + $request = new Request('REPORT', '/principals', ['Content-Type' => 'application/xml']); + $request->setBody($xml); + + $response = $this->request($request, 207); + + $expected = <<<XML +<?xml version="1.0"?> +<d:multistatus xmlns:d="DAV:" xmlns:s="http://sabredav.org/ns"> + <d:status>HTTP/1.1 200 OK</d:status> + <d:href>/principals/user1</d:href> + <d:propstat> + <d:prop/> + <d:status>HTTP/1.1 418 I'm a teapot</d:status> + </d:propstat> +</d:multistatus> +XML; + + $this->assertXmlStringEqualsXmlString( + $expected, + $response->getBodyAsString() + ); + + } + + function testPrincipalMatchProp() { + + $xml = <<<XML +<?xml version="1.0"?> +<principal-match xmlns="DAV:"> + <self /> + <prop> + <resourcetype /> + </prop> +</principal-match> +XML; + + $request = new Request('REPORT', '/principals', ['Content-Type' => 'application/xml']); + $request->setBody($xml); + + $response = $this->request($request, 207); + + $expected = <<<XML +<?xml version="1.0"?> +<d:multistatus xmlns:d="DAV:" xmlns:s="http://sabredav.org/ns"> + <d:status>HTTP/1.1 200 OK</d:status> + <d:href>/principals/user1/</d:href> + <d:propstat> + <d:prop> + <d:resourcetype><d:principal/></d:resourcetype> + </d:prop> + <d:status>HTTP/1.1 200 OK</d:status> + </d:propstat> +</d:multistatus> +XML; + + $this->assertXmlStringEqualsXmlString( + $expected, + $response->getBodyAsString() + ); + + } + + function testPrincipalMatchPrincipalProperty() { + + $xml = <<<XML +<?xml version="1.0"?> +<principal-match xmlns="DAV:"> + <principal-property> + <principal-URL /> + </principal-property> + <prop> + <resourcetype /> + </prop> +</principal-match> +XML; + + $request = new Request('REPORT', '/principals', ['Content-Type' => 'application/xml']); + $request->setBody($xml); + + $response = $this->request($request, 207); + + $expected = <<<XML +<?xml version="1.0"?> +<d:multistatus xmlns:d="DAV:" xmlns:s="http://sabredav.org/ns"> + <d:status>HTTP/1.1 200 OK</d:status> + <d:href>/principals/user1/</d:href> + <d:propstat> + <d:prop> + <d:resourcetype><d:principal/></d:resourcetype> + </d:prop> + <d:status>HTTP/1.1 200 OK</d:status> + </d:propstat> +</d:multistatus> +XML; + + $this->assertXmlStringEqualsXmlString( + $expected, + $response->getBodyAsString() + ); + + } + +} diff --git a/vendor/sabre/dav/tests/Sabre/DAVACL/PrincipalPropertySearchTest.php b/vendor/sabre/dav/tests/Sabre/DAVACL/PrincipalPropertySearchTest.php new file mode 100644 index 000000000..60e156d9a --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/DAVACL/PrincipalPropertySearchTest.php @@ -0,0 +1,397 @@ +<?php + +namespace Sabre\DAVACL; + +use Sabre\DAV; +use Sabre\HTTP; + +require_once 'Sabre/HTTP/ResponseMock.php'; + +class PrincipalPropertySearchTest extends \PHPUnit_Framework_TestCase { + + function getServer() { + + $backend = new PrincipalBackend\Mock(); + + $dir = new DAV\SimpleCollection('root'); + $principals = new PrincipalCollection($backend); + $dir->addChild($principals); + + $fakeServer = new DAV\Server($dir); + $fakeServer->sapi = new HTTP\SapiMock(); + $fakeServer->httpResponse = new HTTP\ResponseMock(); + $fakeServer->debugExceptions = true; + $plugin = new MockPlugin(); + $plugin->allowAccessToNodesWithoutACL = true; + $plugin->allowUnauthenticatedAccess = false; + + $this->assertTrue($plugin instanceof Plugin); + $fakeServer->addPlugin($plugin); + $this->assertEquals($plugin, $fakeServer->getPlugin('acl')); + + return $fakeServer; + + } + + function testDepth1() { + + $xml = '<?xml version="1.0"?> +<d:principal-property-search xmlns:d="DAV:"> + <d:property-search> + <d:prop> + <d:displayname /> + </d:prop> + <d:match>user</d:match> + </d:property-search> + <d:prop> + <d:displayname /> + <d:getcontentlength /> + </d:prop> +</d:principal-property-search>'; + + $serverVars = [ + 'REQUEST_METHOD' => 'REPORT', + 'HTTP_DEPTH' => '1', + 'REQUEST_URI' => '/principals', + ]; + + $request = HTTP\Sapi::createFromServerArray($serverVars); + $request->setBody($xml); + + $server = $this->getServer(); + $server->httpRequest = $request; + + $server->exec(); + + $this->assertEquals(400, $server->httpResponse->getStatus(), $server->httpResponse->getBodyAsString()); + $this->assertEquals([ + 'X-Sabre-Version' => [DAV\Version::VERSION], + 'Content-Type' => ['application/xml; charset=utf-8'], + ], $server->httpResponse->getHeaders()); + + } + + + function testUnknownSearchField() { + + $xml = '<?xml version="1.0"?> +<d:principal-property-search xmlns:d="DAV:"> + <d:property-search> + <d:prop> + <d:yourmom /> + </d:prop> + <d:match>user</d:match> + </d:property-search> + <d:prop> + <d:displayname /> + <d:getcontentlength /> + </d:prop> +</d:principal-property-search>'; + + $serverVars = [ + 'REQUEST_METHOD' => 'REPORT', + 'HTTP_DEPTH' => '0', + 'REQUEST_URI' => '/principals', + ]; + + $request = HTTP\Sapi::createFromServerArray($serverVars); + $request->setBody($xml); + + $server = $this->getServer(); + $server->httpRequest = $request; + + $server->exec(); + + $this->assertEquals(207, $server->httpResponse->getStatus(), "Full body: " . $server->httpResponse->getBodyAsString()); + $this->assertEquals([ + 'X-Sabre-Version' => [DAV\Version::VERSION], + 'Content-Type' => ['application/xml; charset=utf-8'], + 'Vary' => ['Brief,Prefer'], + ], $server->httpResponse->getHeaders()); + + } + + function testCorrect() { + + $xml = '<?xml version="1.0"?> +<d:principal-property-search xmlns:d="DAV:"> + <d:apply-to-principal-collection-set /> + <d:property-search> + <d:prop> + <d:displayname /> + </d:prop> + <d:match>user</d:match> + </d:property-search> + <d:prop> + <d:displayname /> + <d:getcontentlength /> + </d:prop> +</d:principal-property-search>'; + + $serverVars = [ + 'REQUEST_METHOD' => 'REPORT', + 'HTTP_DEPTH' => '0', + 'REQUEST_URI' => '/', + ]; + + $request = HTTP\Sapi::createFromServerArray($serverVars); + $request->setBody($xml); + + $server = $this->getServer(); + $server->httpRequest = $request; + + $server->exec(); + + $this->assertEquals(207, $server->httpResponse->status, $server->httpResponse->body); + $this->assertEquals([ + 'X-Sabre-Version' => [DAV\Version::VERSION], + 'Content-Type' => ['application/xml; charset=utf-8'], + 'Vary' => ['Brief,Prefer'], + ], $server->httpResponse->getHeaders()); + + + $check = [ + '/d:multistatus', + '/d:multistatus/d:response' => 2, + '/d:multistatus/d:response/d:href' => 2, + '/d:multistatus/d:response/d:propstat' => 4, + '/d:multistatus/d:response/d:propstat/d:prop' => 4, + '/d:multistatus/d:response/d:propstat/d:prop/d:displayname' => 2, + '/d:multistatus/d:response/d:propstat/d:prop/d:getcontentlength' => 2, + '/d:multistatus/d:response/d:propstat/d:status' => 4, + ]; + + $xml = simplexml_load_string($server->httpResponse->body); + $xml->registerXPathNamespace('d', 'DAV:'); + foreach ($check as $v1 => $v2) { + + $xpath = is_int($v1) ? $v2 : $v1; + + $result = $xml->xpath($xpath); + + $count = 1; + if (!is_int($v1)) $count = $v2; + + $this->assertEquals($count, count($result), 'we expected ' . $count . ' appearances of ' . $xpath . ' . We found ' . count($result) . '. Full response body: ' . $server->httpResponse->body); + + } + + } + + function testAND() { + + $xml = '<?xml version="1.0"?> +<d:principal-property-search xmlns:d="DAV:"> + <d:apply-to-principal-collection-set /> + <d:property-search> + <d:prop> + <d:displayname /> + </d:prop> + <d:match>user</d:match> + </d:property-search> + <d:property-search> + <d:prop> + <d:foo /> + </d:prop> + <d:match>bar</d:match> + </d:property-search> + <d:prop> + <d:displayname /> + <d:getcontentlength /> + </d:prop> +</d:principal-property-search>'; + + $serverVars = [ + 'REQUEST_METHOD' => 'REPORT', + 'HTTP_DEPTH' => '0', + 'REQUEST_URI' => '/', + ]; + + $request = HTTP\Sapi::createFromServerArray($serverVars); + $request->setBody($xml); + + $server = $this->getServer(); + $server->httpRequest = $request; + + $server->exec(); + + $this->assertEquals(207, $server->httpResponse->status, $server->httpResponse->body); + $this->assertEquals([ + 'X-Sabre-Version' => [DAV\Version::VERSION], + 'Content-Type' => ['application/xml; charset=utf-8'], + 'Vary' => ['Brief,Prefer'], + ], $server->httpResponse->getHeaders()); + + + $check = [ + '/d:multistatus', + '/d:multistatus/d:response' => 0, + '/d:multistatus/d:response/d:href' => 0, + '/d:multistatus/d:response/d:propstat' => 0, + '/d:multistatus/d:response/d:propstat/d:prop' => 0, + '/d:multistatus/d:response/d:propstat/d:prop/d:displayname' => 0, + '/d:multistatus/d:response/d:propstat/d:prop/d:getcontentlength' => 0, + '/d:multistatus/d:response/d:propstat/d:status' => 0, + ]; + + $xml = simplexml_load_string($server->httpResponse->body); + $xml->registerXPathNamespace('d', 'DAV:'); + foreach ($check as $v1 => $v2) { + + $xpath = is_int($v1) ? $v2 : $v1; + + $result = $xml->xpath($xpath); + + $count = 1; + if (!is_int($v1)) $count = $v2; + + $this->assertEquals($count, count($result), 'we expected ' . $count . ' appearances of ' . $xpath . ' . We found ' . count($result) . '. Full response body: ' . $server->httpResponse->body); + + } + + } + function testOR() { + + $xml = '<?xml version="1.0"?> +<d:principal-property-search xmlns:d="DAV:" test="anyof"> + <d:apply-to-principal-collection-set /> + <d:property-search> + <d:prop> + <d:displayname /> + </d:prop> + <d:match>user</d:match> + </d:property-search> + <d:property-search> + <d:prop> + <d:foo /> + </d:prop> + <d:match>bar</d:match> + </d:property-search> + <d:prop> + <d:displayname /> + <d:getcontentlength /> + </d:prop> +</d:principal-property-search>'; + + $serverVars = [ + 'REQUEST_METHOD' => 'REPORT', + 'HTTP_DEPTH' => '0', + 'REQUEST_URI' => '/', + ]; + + $request = HTTP\Sapi::createFromServerArray($serverVars); + $request->setBody($xml); + + $server = $this->getServer(); + $server->httpRequest = $request; + + $server->exec(); + + $this->assertEquals(207, $server->httpResponse->status, $server->httpResponse->body); + $this->assertEquals([ + 'X-Sabre-Version' => [DAV\Version::VERSION], + 'Content-Type' => ['application/xml; charset=utf-8'], + 'Vary' => ['Brief,Prefer'], + ], $server->httpResponse->getHeaders()); + + + $check = [ + '/d:multistatus', + '/d:multistatus/d:response' => 2, + '/d:multistatus/d:response/d:href' => 2, + '/d:multistatus/d:response/d:propstat' => 4, + '/d:multistatus/d:response/d:propstat/d:prop' => 4, + '/d:multistatus/d:response/d:propstat/d:prop/d:displayname' => 2, + '/d:multistatus/d:response/d:propstat/d:prop/d:getcontentlength' => 2, + '/d:multistatus/d:response/d:propstat/d:status' => 4, + ]; + + $xml = simplexml_load_string($server->httpResponse->body); + $xml->registerXPathNamespace('d', 'DAV:'); + foreach ($check as $v1 => $v2) { + + $xpath = is_int($v1) ? $v2 : $v1; + + $result = $xml->xpath($xpath); + + $count = 1; + if (!is_int($v1)) $count = $v2; + + $this->assertEquals($count, count($result), 'we expected ' . $count . ' appearances of ' . $xpath . ' . We found ' . count($result) . '. Full response body: ' . $server->httpResponse->body); + + } + + } + function testWrongUri() { + + $xml = '<?xml version="1.0"?> +<d:principal-property-search xmlns:d="DAV:"> + <d:property-search> + <d:prop> + <d:displayname /> + </d:prop> + <d:match>user</d:match> + </d:property-search> + <d:prop> + <d:displayname /> + <d:getcontentlength /> + </d:prop> +</d:principal-property-search>'; + + $serverVars = [ + 'REQUEST_METHOD' => 'REPORT', + 'HTTP_DEPTH' => '0', + 'REQUEST_URI' => '/', + ]; + + $request = HTTP\Sapi::createFromServerArray($serverVars); + $request->setBody($xml); + + $server = $this->getServer(); + $server->httpRequest = $request; + + $server->exec(); + + $this->assertEquals(207, $server->httpResponse->status, $server->httpResponse->body); + $this->assertEquals([ + 'X-Sabre-Version' => [DAV\Version::VERSION], + 'Content-Type' => ['application/xml; charset=utf-8'], + 'Vary' => ['Brief,Prefer'], + ], $server->httpResponse->getHeaders()); + + + $check = [ + '/d:multistatus', + '/d:multistatus/d:response' => 0, + ]; + + $xml = simplexml_load_string($server->httpResponse->body); + $xml->registerXPathNamespace('d', 'DAV:'); + foreach ($check as $v1 => $v2) { + + $xpath = is_int($v1) ? $v2 : $v1; + + $result = $xml->xpath($xpath); + + $count = 1; + if (!is_int($v1)) $count = $v2; + + $this->assertEquals($count, count($result), 'we expected ' . $count . ' appearances of ' . $xpath . ' . We found ' . count($result) . '. Full response body: ' . $server->httpResponse->body); + + } + + } +} + +class MockPlugin extends Plugin { + + function getCurrentUserPrivilegeSet($node) { + + return [ + '{DAV:}read', + '{DAV:}write', + ]; + + } + +} diff --git a/vendor/sabre/dav/tests/Sabre/DAVACL/PrincipalSearchPropertySetTest.php b/vendor/sabre/dav/tests/Sabre/DAVACL/PrincipalSearchPropertySetTest.php new file mode 100644 index 000000000..fa1314d10 --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/DAVACL/PrincipalSearchPropertySetTest.php @@ -0,0 +1,140 @@ +<?php + +namespace Sabre\DAVACL; + +use Sabre\DAV; +use Sabre\HTTP; + +require_once 'Sabre/HTTP/ResponseMock.php'; + +class PrincipalSearchPropertySetTest extends \PHPUnit_Framework_TestCase { + + function getServer() { + + $backend = new PrincipalBackend\Mock(); + + $dir = new DAV\SimpleCollection('root'); + $principals = new PrincipalCollection($backend); + $dir->addChild($principals); + + $fakeServer = new DAV\Server($dir); + $fakeServer->sapi = new HTTP\SapiMock(); + $fakeServer->httpResponse = new HTTP\ResponseMock(); + $plugin = new Plugin(); + $plugin->allowUnauthenticatedAccess = false; + $this->assertTrue($plugin instanceof Plugin); + $fakeServer->addPlugin($plugin); + $this->assertEquals($plugin, $fakeServer->getPlugin('acl')); + + return $fakeServer; + + } + + function testDepth1() { + + $xml = '<?xml version="1.0"?> +<d:principal-search-property-set xmlns:d="DAV:" />'; + + $serverVars = [ + 'REQUEST_METHOD' => 'REPORT', + 'HTTP_DEPTH' => '1', + 'REQUEST_URI' => '/principals', + ]; + + $request = HTTP\Sapi::createFromServerArray($serverVars); + $request->setBody($xml); + + $server = $this->getServer(); + $server->httpRequest = $request; + + $server->exec(); + + $this->assertEquals(400, $server->httpResponse->status); + $this->assertEquals([ + 'X-Sabre-Version' => [DAV\Version::VERSION], + 'Content-Type' => ['application/xml; charset=utf-8'], + ], $server->httpResponse->getHeaders()); + + } + + function testDepthIncorrectXML() { + + $xml = '<?xml version="1.0"?> +<d:principal-search-property-set xmlns:d="DAV:"><d:ohell /></d:principal-search-property-set>'; + + $serverVars = [ + 'REQUEST_METHOD' => 'REPORT', + 'HTTP_DEPTH' => '0', + 'REQUEST_URI' => '/principals', + ]; + + $request = HTTP\Sapi::createFromServerArray($serverVars); + $request->setBody($xml); + + $server = $this->getServer(); + $server->httpRequest = $request; + + $server->exec(); + + $this->assertEquals(400, $server->httpResponse->status, $server->httpResponse->body); + $this->assertEquals([ + 'X-Sabre-Version' => [DAV\Version::VERSION], + 'Content-Type' => ['application/xml; charset=utf-8'], + ], $server->httpResponse->getHeaders()); + + } + + function testCorrect() { + + $xml = '<?xml version="1.0"?> +<d:principal-search-property-set xmlns:d="DAV:"/>'; + + $serverVars = [ + 'REQUEST_METHOD' => 'REPORT', + 'HTTP_DEPTH' => '0', + 'REQUEST_URI' => '/principals', + ]; + + $request = HTTP\Sapi::createFromServerArray($serverVars); + $request->setBody($xml); + + $server = $this->getServer(); + $server->httpRequest = $request; + + $server->exec(); + + $this->assertEquals(200, $server->httpResponse->status, $server->httpResponse->body); + $this->assertEquals([ + 'X-Sabre-Version' => [DAV\Version::VERSION], + 'Content-Type' => ['application/xml; charset=utf-8'], + ], $server->httpResponse->getHeaders()); + + + $check = [ + '/d:principal-search-property-set', + '/d:principal-search-property-set/d:principal-search-property' => 2, + '/d:principal-search-property-set/d:principal-search-property/d:prop' => 2, + '/d:principal-search-property-set/d:principal-search-property/d:prop/d:displayname' => 1, + '/d:principal-search-property-set/d:principal-search-property/d:prop/s:email-address' => 1, + '/d:principal-search-property-set/d:principal-search-property/d:description' => 2, + ]; + + $xml = simplexml_load_string($server->httpResponse->body); + $xml->registerXPathNamespace('d', 'DAV:'); + $xml->registerXPathNamespace('s', 'http://sabredav.org/ns'); + foreach ($check as $v1 => $v2) { + + $xpath = is_int($v1) ? $v2 : $v1; + + $result = $xml->xpath($xpath); + + $count = 1; + if (!is_int($v1)) $count = $v2; + + $this->assertEquals($count, count($result), 'we expected ' . $count . ' appearances of ' . $xpath . ' . We found ' . count($result) . '. Full response body: ' . $server->httpResponse->body); + + } + + } + +} diff --git a/vendor/sabre/dav/tests/Sabre/DAVACL/PrincipalTest.php b/vendor/sabre/dav/tests/Sabre/DAVACL/PrincipalTest.php new file mode 100644 index 000000000..20622ad17 --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/DAVACL/PrincipalTest.php @@ -0,0 +1,208 @@ +<?php + +namespace Sabre\DAVACL; + +use Sabre\DAV; +use Sabre\HTTP; + +class PrincipalTest extends \PHPUnit_Framework_TestCase { + + function testConstruct() { + + $principalBackend = new PrincipalBackend\Mock(); + $principal = new Principal($principalBackend, ['uri' => 'principals/admin']); + $this->assertTrue($principal instanceof Principal); + + } + + /** + * @expectedException Sabre\DAV\Exception + */ + function testConstructNoUri() { + + $principalBackend = new PrincipalBackend\Mock(); + $principal = new Principal($principalBackend, []); + + } + + function testGetName() { + + $principalBackend = new PrincipalBackend\Mock(); + $principal = new Principal($principalBackend, ['uri' => 'principals/admin']); + $this->assertEquals('admin', $principal->getName()); + + } + + function testGetDisplayName() { + + $principalBackend = new PrincipalBackend\Mock(); + $principal = new Principal($principalBackend, ['uri' => 'principals/admin']); + $this->assertEquals('admin', $principal->getDisplayname()); + + $principal = new Principal($principalBackend, [ + 'uri' => 'principals/admin', + '{DAV:}displayname' => 'Mr. Admin' + ]); + $this->assertEquals('Mr. Admin', $principal->getDisplayname()); + + } + + function testGetProperties() { + + $principalBackend = new PrincipalBackend\Mock(); + $principal = new Principal($principalBackend, [ + 'uri' => 'principals/admin', + '{DAV:}displayname' => 'Mr. Admin', + '{http://www.example.org/custom}custom' => 'Custom', + '{http://sabredav.org/ns}email-address' => 'admin@example.org', + ]); + + $keys = [ + '{DAV:}displayname', + '{http://www.example.org/custom}custom', + '{http://sabredav.org/ns}email-address', + ]; + $props = $principal->getProperties($keys); + + foreach ($keys as $key) $this->assertArrayHasKey($key, $props); + + $this->assertEquals('Mr. Admin', $props['{DAV:}displayname']); + + $this->assertEquals('admin@example.org', $props['{http://sabredav.org/ns}email-address']); + } + + function testUpdateProperties() { + + $principalBackend = new PrincipalBackend\Mock(); + $principal = new Principal($principalBackend, ['uri' => 'principals/admin']); + + $propPatch = new DAV\PropPatch(['{DAV:}yourmom' => 'test']); + + $result = $principal->propPatch($propPatch); + $result = $propPatch->commit(); + $this->assertTrue($result); + + } + + function testGetPrincipalUrl() { + + $principalBackend = new PrincipalBackend\Mock(); + $principal = new Principal($principalBackend, ['uri' => 'principals/admin']); + $this->assertEquals('principals/admin', $principal->getPrincipalUrl()); + + } + + function testGetAlternateUriSet() { + + $principalBackend = new PrincipalBackend\Mock(); + $principal = new Principal($principalBackend, [ + 'uri' => 'principals/admin', + '{DAV:}displayname' => 'Mr. Admin', + '{http://www.example.org/custom}custom' => 'Custom', + '{http://sabredav.org/ns}email-address' => 'admin@example.org', + '{DAV:}alternate-URI-set' => [ + 'mailto:admin+1@example.org', + 'mailto:admin+2@example.org', + 'mailto:admin@example.org', + ], + ]); + + $expected = [ + 'mailto:admin+1@example.org', + 'mailto:admin+2@example.org', + 'mailto:admin@example.org', + ]; + + $this->assertEquals($expected, $principal->getAlternateUriSet()); + + } + function testGetAlternateUriSetEmpty() { + + $principalBackend = new PrincipalBackend\Mock(); + $principal = new Principal($principalBackend, [ + 'uri' => 'principals/admin', + ]); + + $expected = []; + + $this->assertEquals($expected, $principal->getAlternateUriSet()); + + } + + function testGetGroupMemberSet() { + + $principalBackend = new PrincipalBackend\Mock(); + $principal = new Principal($principalBackend, ['uri' => 'principals/admin']); + $this->assertEquals([], $principal->getGroupMemberSet()); + + } + function testGetGroupMembership() { + + $principalBackend = new PrincipalBackend\Mock(); + $principal = new Principal($principalBackend, ['uri' => 'principals/admin']); + $this->assertEquals([], $principal->getGroupMembership()); + + } + + function testSetGroupMemberSet() { + + $principalBackend = new PrincipalBackend\Mock(); + $principal = new Principal($principalBackend, ['uri' => 'principals/admin']); + $principal->setGroupMemberSet(['principals/foo']); + + $this->assertEquals([ + 'principals/admin' => ['principals/foo'], + ], $principalBackend->groupMembers); + + } + + function testGetOwner() { + + $principalBackend = new PrincipalBackend\Mock(); + $principal = new Principal($principalBackend, ['uri' => 'principals/admin']); + $this->assertEquals('principals/admin', $principal->getOwner()); + + } + + function testGetGroup() { + + $principalBackend = new PrincipalBackend\Mock(); + $principal = new Principal($principalBackend, ['uri' => 'principals/admin']); + $this->assertNull($principal->getGroup()); + + } + + function testGetACl() { + + $principalBackend = new PrincipalBackend\Mock(); + $principal = new Principal($principalBackend, ['uri' => 'principals/admin']); + $this->assertEquals([ + [ + 'privilege' => '{DAV:}all', + 'principal' => '{DAV:}owner', + 'protected' => true, + ] + ], $principal->getACL()); + + } + + /** + * @expectedException \Sabre\DAV\Exception\Forbidden + */ + function testSetACl() { + + $principalBackend = new PrincipalBackend\Mock(); + $principal = new Principal($principalBackend, ['uri' => 'principals/admin']); + $principal->setACL([]); + + } + + function testGetSupportedPrivilegeSet() { + + $principalBackend = new PrincipalBackend\Mock(); + $principal = new Principal($principalBackend, ['uri' => 'principals/admin']); + $this->assertNull($principal->getSupportedPrivilegeSet()); + + } + +} diff --git a/vendor/sabre/dav/tests/Sabre/DAVACL/SimplePluginTest.php b/vendor/sabre/dav/tests/Sabre/DAVACL/SimplePluginTest.php new file mode 100644 index 000000000..2de0ba6a8 --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/DAVACL/SimplePluginTest.php @@ -0,0 +1,321 @@ +<?php + +namespace Sabre\DAVACL; + +use Sabre\DAV; +use Sabre\HTTP; + +require_once 'Sabre/DAVACL/MockPrincipal.php'; +require_once 'Sabre/DAVACL/MockACLNode.php'; + +class SimplePluginTest extends \PHPUnit_Framework_TestCase { + + function testValues() { + + $aclPlugin = new Plugin(); + $this->assertEquals('acl', $aclPlugin->getPluginName()); + $this->assertEquals( + ['access-control', 'calendarserver-principal-property-search'], + $aclPlugin->getFeatures() + ); + + $this->assertEquals( + [ + '{DAV:}expand-property', + '{DAV:}principal-match', + '{DAV:}principal-property-search', + '{DAV:}principal-search-property-set' + ], + $aclPlugin->getSupportedReportSet('')); + + $this->assertEquals(['ACL'], $aclPlugin->getMethods('')); + + + $this->assertEquals( + 'acl', + $aclPlugin->getPluginInfo()['name'] + ); + } + + function testGetFlatPrivilegeSet() { + + $expected = [ + '{DAV:}all' => [ + 'privilege' => '{DAV:}all', + 'abstract' => false, + 'aggregates' => [ + '{DAV:}read', + '{DAV:}write', + ], + 'concrete' => '{DAV:}all', + ], + '{DAV:}read' => [ + 'privilege' => '{DAV:}read', + 'abstract' => false, + 'aggregates' => [ + '{DAV:}read-acl', + '{DAV:}read-current-user-privilege-set', + ], + 'concrete' => '{DAV:}read', + ], + '{DAV:}read-acl' => [ + 'privilege' => '{DAV:}read-acl', + 'abstract' => false, + 'aggregates' => [], + 'concrete' => '{DAV:}read-acl', + ], + '{DAV:}read-current-user-privilege-set' => [ + 'privilege' => '{DAV:}read-current-user-privilege-set', + 'abstract' => false, + 'aggregates' => [], + 'concrete' => '{DAV:}read-current-user-privilege-set', + ], + '{DAV:}write' => [ + 'privilege' => '{DAV:}write', + 'abstract' => false, + 'aggregates' => [ + '{DAV:}write-properties', + '{DAV:}write-content', + '{DAV:}unlock', + '{DAV:}bind', + '{DAV:}unbind', + ], + 'concrete' => '{DAV:}write', + ], + '{DAV:}write-properties' => [ + 'privilege' => '{DAV:}write-properties', + 'abstract' => false, + 'aggregates' => [], + 'concrete' => '{DAV:}write-properties', + ], + '{DAV:}write-content' => [ + 'privilege' => '{DAV:}write-content', + 'abstract' => false, + 'aggregates' => [], + 'concrete' => '{DAV:}write-content', + ], + '{DAV:}unlock' => [ + 'privilege' => '{DAV:}unlock', + 'abstract' => false, + 'aggregates' => [], + 'concrete' => '{DAV:}unlock', + ], + '{DAV:}bind' => [ + 'privilege' => '{DAV:}bind', + 'abstract' => false, + 'aggregates' => [], + 'concrete' => '{DAV:}bind', + ], + '{DAV:}unbind' => [ + 'privilege' => '{DAV:}unbind', + 'abstract' => false, + 'aggregates' => [], + 'concrete' => '{DAV:}unbind', + ], + + ]; + + $plugin = new Plugin(); + $plugin->allowUnauthenticatedAccess = false; + $server = new DAV\Server(); + $server->addPlugin($plugin); + $this->assertEquals($expected, $plugin->getFlatPrivilegeSet('')); + + } + + function testCurrentUserPrincipalsNotLoggedIn() { + + $acl = new Plugin(); + $acl->allowUnauthenticatedAccess = false; + $server = new DAV\Server(); + $server->addPlugin($acl); + + $this->assertEquals([], $acl->getCurrentUserPrincipals()); + + } + + function testCurrentUserPrincipalsSimple() { + + $tree = [ + + new DAV\SimpleCollection('principals', [ + new MockPrincipal('admin', 'principals/admin'), + ]) + + ]; + + $acl = new Plugin(); + $acl->allowUnauthenticatedAccess = false; + $server = new DAV\Server($tree); + $server->addPlugin($acl); + + $auth = new DAV\Auth\Plugin(new DAV\Auth\Backend\Mock()); + $server->addPlugin($auth); + + //forcing login + $auth->beforeMethod(new HTTP\Request(), new HTTP\Response()); + + $this->assertEquals(['principals/admin'], $acl->getCurrentUserPrincipals()); + + } + + function testCurrentUserPrincipalsGroups() { + + $tree = [ + + new DAV\SimpleCollection('principals', [ + new MockPrincipal('admin', 'principals/admin', ['principals/administrators', 'principals/everyone']), + new MockPrincipal('administrators', 'principals/administrators', ['principals/groups'], ['principals/admin']), + new MockPrincipal('everyone', 'principals/everyone', [], ['principals/admin']), + new MockPrincipal('groups', 'principals/groups', [], ['principals/administrators']), + ]) + + ]; + + $acl = new Plugin(); + $acl->allowUnauthenticatedAccess = false; + $server = new DAV\Server($tree); + $server->addPlugin($acl); + + $auth = new DAV\Auth\Plugin(new DAV\Auth\Backend\Mock()); + $server->addPlugin($auth); + + //forcing login + $auth->beforeMethod(new HTTP\Request(), new HTTP\Response()); + + $expected = [ + 'principals/admin', + 'principals/administrators', + 'principals/everyone', + 'principals/groups', + ]; + + $this->assertEquals($expected, $acl->getCurrentUserPrincipals()); + + // The second one should trigger the cache and be identical + $this->assertEquals($expected, $acl->getCurrentUserPrincipals()); + + } + + function testGetACL() { + + $acl = [ + [ + 'principal' => 'principals/admin', + 'privilege' => '{DAV:}read', + ], + [ + 'principal' => 'principals/admin', + 'privilege' => '{DAV:}write', + ], + ]; + + + $tree = [ + new MockACLNode('foo', $acl), + ]; + + $server = new DAV\Server($tree); + $aclPlugin = new Plugin(); + $aclPlugin->allowUnauthenticatedAccess = false; + $server->addPlugin($aclPlugin); + + $this->assertEquals($acl, $aclPlugin->getACL('foo')); + + } + + function testGetCurrentUserPrivilegeSet() { + + $acl = [ + [ + 'principal' => 'principals/admin', + 'privilege' => '{DAV:}read', + ], + [ + 'principal' => 'principals/user1', + 'privilege' => '{DAV:}read', + ], + [ + 'principal' => 'principals/admin', + 'privilege' => '{DAV:}write', + ], + ]; + + + $tree = [ + new MockACLNode('foo', $acl), + + new DAV\SimpleCollection('principals', [ + new MockPrincipal('admin', 'principals/admin'), + ]), + + ]; + + $server = new DAV\Server($tree); + $aclPlugin = new Plugin(); + $aclPlugin->allowUnauthenticatedAccess = false; + $server->addPlugin($aclPlugin); + + $auth = new DAV\Auth\Plugin(new DAV\Auth\Backend\Mock()); + $server->addPlugin($auth); + + //forcing login + $auth->beforeMethod(new HTTP\Request(), new HTTP\Response()); + + $expected = [ + '{DAV:}write', + '{DAV:}write-properties', + '{DAV:}write-content', + '{DAV:}unlock', + '{DAV:}write-acl', + '{DAV:}read', + '{DAV:}read-acl', + '{DAV:}read-current-user-privilege-set', + ]; + + $this->assertEquals($expected, $aclPlugin->getCurrentUserPrivilegeSet('foo')); + + } + + function testCheckPrivileges() { + + $acl = [ + [ + 'principal' => 'principals/admin', + 'privilege' => '{DAV:}read', + ], + [ + 'principal' => 'principals/user1', + 'privilege' => '{DAV:}read', + ], + [ + 'principal' => 'principals/admin', + 'privilege' => '{DAV:}write', + ], + ]; + + + $tree = [ + new MockACLNode('foo', $acl), + + new DAV\SimpleCollection('principals', [ + new MockPrincipal('admin', 'principals/admin'), + ]), + + ]; + + $server = new DAV\Server($tree); + $aclPlugin = new Plugin(); + $aclPlugin->allowUnauthenticatedAccess = false; + $server->addPlugin($aclPlugin); + + $auth = new DAV\Auth\Plugin(new DAV\Auth\Backend\Mock()); + $server->addPlugin($auth); + + //forcing login + //$auth->beforeMethod('GET','/'); + + $this->assertFalse($aclPlugin->checkPrivileges('foo', ['{DAV:}read'], Plugin::R_PARENT, false)); + + } +} diff --git a/vendor/sabre/dav/tests/Sabre/DAVACL/Xml/Property/ACLTest.php b/vendor/sabre/dav/tests/Sabre/DAVACL/Xml/Property/ACLTest.php new file mode 100644 index 000000000..7b9853fe5 --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/DAVACL/Xml/Property/ACLTest.php @@ -0,0 +1,342 @@ +<?php + +namespace Sabre\DAVACL\Xml\Property; + +use Sabre\DAV; +use Sabre\DAV\Browser\HtmlOutputHelper; +use Sabre\HTTP; + +class ACLTest extends \PHPUnit_Framework_TestCase { + + function testConstruct() { + + $acl = new Acl([]); + $this->assertInstanceOf('Sabre\DAVACL\Xml\Property\ACL', $acl); + + } + + function testSerializeEmpty() { + + $acl = new Acl([]); + $xml = (new DAV\Server())->xml->write('{DAV:}root', $acl); + + $expected = '<?xml version="1.0"?> +<d:root xmlns:d="DAV:" xmlns:s="http://sabredav.org/ns" />'; + + $this->assertXmlStringEqualsXmlString($expected, $xml); + + } + + function testSerialize() { + + $privileges = [ + [ + 'principal' => 'principals/evert', + 'privilege' => '{DAV:}write', + ], + [ + 'principal' => 'principals/foo', + 'privilege' => '{DAV:}read', + 'protected' => true, + ], + ]; + + $acl = new Acl($privileges); + $xml = (new DAV\Server())->xml->write('{DAV:}root', $acl, '/'); + + $expected = '<?xml version="1.0"?> +<d:root xmlns:d="DAV:" xmlns:s="http://sabredav.org/ns"> + <d:ace> + <d:principal> + <d:href>/principals/evert/</d:href> + </d:principal> + <d:grant> + <d:privilege> + <d:write/> + </d:privilege> + </d:grant> + </d:ace> + <d:ace> + <d:principal> + <d:href>/principals/foo/</d:href> + </d:principal> + <d:grant> + <d:privilege> + <d:read/> + </d:privilege> + </d:grant> + <d:protected/> + </d:ace> +</d:root> +'; + $this->assertXmlStringEqualsXmlString($expected, $xml); + + } + + function testSerializeSpecialPrincipals() { + + $privileges = [ + [ + 'principal' => '{DAV:}authenticated', + 'privilege' => '{DAV:}write', + ], + [ + 'principal' => '{DAV:}unauthenticated', + 'privilege' => '{DAV:}write', + ], + [ + 'principal' => '{DAV:}all', + 'privilege' => '{DAV:}write', + ], + + ]; + + $acl = new Acl($privileges); + $xml = (new DAV\Server())->xml->write('{DAV:}root', $acl, '/'); + + $expected = '<?xml version="1.0"?> +<d:root xmlns:d="DAV:" xmlns:s="http://sabredav.org/ns"> + <d:ace> + <d:principal> + <d:authenticated/> + </d:principal> + <d:grant> + <d:privilege> + <d:write/> + </d:privilege> + </d:grant> + </d:ace> + <d:ace> + <d:principal> + <d:unauthenticated/> + </d:principal> + <d:grant> + <d:privilege> + <d:write/> + </d:privilege> + </d:grant> + </d:ace> + <d:ace> + <d:principal> + <d:all/> + </d:principal> + <d:grant> + <d:privilege> + <d:write/> + </d:privilege> + </d:grant> + </d:ace> +</d:root> +'; + $this->assertXmlStringEqualsXmlString($expected, $xml); + + } + + function testUnserialize() { + + $source = '<?xml version="1.0"?> +<d:root xmlns:d="DAV:"> + <d:ace> + <d:principal> + <d:href>/principals/evert/</d:href> + </d:principal> + <d:grant> + <d:privilege> + <d:write/> + </d:privilege> + </d:grant> + </d:ace> + <d:ace> + <d:principal> + <d:href>/principals/foo/</d:href> + </d:principal> + <d:grant> + <d:privilege> + <d:read/> + </d:privilege> + </d:grant> + <d:protected/> + </d:ace> +</d:root> +'; + + $reader = new \Sabre\Xml\Reader(); + $reader->elementMap['{DAV:}root'] = 'Sabre\DAVACL\Xml\Property\Acl'; + $reader->xml($source); + + $result = $reader->parse(); + $result = $result['value']; + + $this->assertInstanceOf('Sabre\\DAVACL\\Xml\\Property\\Acl', $result); + + $expected = [ + [ + 'principal' => '/principals/evert/', + 'protected' => false, + 'privilege' => '{DAV:}write', + ], + [ + 'principal' => '/principals/foo/', + 'protected' => true, + 'privilege' => '{DAV:}read', + ], + ]; + + $this->assertEquals($expected, $result->getPrivileges()); + + + } + + /** + * @expectedException Sabre\DAV\Exception\BadRequest + */ + function testUnserializeNoPrincipal() { + + $source = '<?xml version="1.0"?> +<d:root xmlns:d="DAV:"> + <d:ace> + <d:grant> + <d:privilege> + <d:write/> + </d:privilege> + </d:grant> + </d:ace> +</d:root> +'; + + + $reader = new \Sabre\Xml\Reader(); + $reader->elementMap['{DAV:}root'] = 'Sabre\DAVACL\Xml\Property\Acl'; + $reader->xml($source); + + $result = $reader->parse(); + + } + + function testUnserializeOtherPrincipal() { + + $source = '<?xml version="1.0"?> +<d:root xmlns:d="DAV:"> + <d:ace> + <d:grant> + <d:privilege> + <d:write/> + </d:privilege> + </d:grant> + <d:principal><d:authenticated /></d:principal> + </d:ace> + <d:ace> + <d:grant> + <d:ignoreme /> + <d:privilege> + <d:write/> + </d:privilege> + </d:grant> + <d:principal><d:unauthenticated /></d:principal> + </d:ace> + <d:ace> + <d:grant> + <d:privilege> + <d:write/> + </d:privilege> + </d:grant> + <d:principal><d:all /></d:principal> + </d:ace> +</d:root> +'; + + $reader = new \Sabre\Xml\Reader(); + $reader->elementMap['{DAV:}root'] = 'Sabre\DAVACL\Xml\Property\Acl'; + $reader->xml($source); + + $result = $reader->parse(); + $result = $result['value']; + + $this->assertInstanceOf('Sabre\\DAVACL\\Xml\\Property\\Acl', $result); + + $expected = [ + [ + 'principal' => '{DAV:}authenticated', + 'protected' => false, + 'privilege' => '{DAV:}write', + ], + [ + 'principal' => '{DAV:}unauthenticated', + 'protected' => false, + 'privilege' => '{DAV:}write', + ], + [ + 'principal' => '{DAV:}all', + 'protected' => false, + 'privilege' => '{DAV:}write', + ], + ]; + + $this->assertEquals($expected, $result->getPrivileges()); + + } + + /** + * @expectedException Sabre\DAV\Exception\NotImplemented + */ + function testUnserializeDeny() { + + $source = '<?xml version="1.0"?> +<d:root xmlns:d="DAV:"> + <d:ignore-me /> + <d:ace> + <d:deny> + <d:privilege> + <d:write/> + </d:privilege> + </d:deny> + <d:principal><d:href>/principals/evert</d:href></d:principal> + </d:ace> +</d:root> +'; + + $reader = new \Sabre\Xml\Reader(); + $reader->elementMap['{DAV:}root'] = 'Sabre\DAVACL\Xml\Property\Acl'; + $reader->xml($source); + + $result = $reader->parse(); + + } + + function testToHtml() { + + $privileges = [ + [ + 'principal' => 'principals/evert', + 'privilege' => '{DAV:}write', + ], + [ + 'principal' => 'principals/foo', + 'privilege' => '{http://example.org/ns}read', + 'protected' => true, + ], + [ + 'principal' => '{DAV:}authenticated', + 'privilege' => '{DAV:}write', + ], + ]; + + $acl = new Acl($privileges); + $html = new HtmlOutputHelper( + '/base/', + ['DAV:' => 'd'] + ); + + $expected = + '<table>' . + '<tr><th>Principal</th><th>Privilege</th><th></th></tr>' . + '<tr><td><a href="/base/principals/evert">/base/principals/evert</a></td><td><span title="{DAV:}write">d:write</span></td><td></td></tr>' . + '<tr><td><a href="/base/principals/foo">/base/principals/foo</a></td><td><span title="{http://example.org/ns}read">{http://example.org/ns}read</span></td><td>(protected)</td></tr>' . + '<tr><td><span title="{DAV:}authenticated">d:authenticated</span></td><td><span title="{DAV:}write">d:write</span></td><td></td></tr>' . + '</table>'; + + $this->assertEquals($expected, $acl->toHtml($html)); + + } + +} diff --git a/vendor/sabre/dav/tests/Sabre/DAVACL/Xml/Property/AclRestrictionsTest.php b/vendor/sabre/dav/tests/Sabre/DAVACL/Xml/Property/AclRestrictionsTest.php new file mode 100644 index 000000000..6d8b83a12 --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/DAVACL/Xml/Property/AclRestrictionsTest.php @@ -0,0 +1,30 @@ +<?php + +namespace Sabre\DAVACL\Xml\Property; + +use Sabre\DAV; +use Sabre\HTTP; + +class AclRestrictionsTest extends \PHPUnit_Framework_TestCase { + + function testConstruct() { + + $prop = new AclRestrictions(); + $this->assertInstanceOf('Sabre\DAVACL\Xml\Property\AclRestrictions', $prop); + + } + + function testSerialize() { + + $prop = new AclRestrictions(); + $xml = (new DAV\Server())->xml->write('{DAV:}root', $prop); + + $expected = '<?xml version="1.0"?> +<d:root xmlns:d="DAV:" xmlns:s="http://sabredav.org/ns"><d:grant-only/><d:no-invert/></d:root>'; + + $this->assertXmlStringEqualsXmlString($expected, $xml); + + } + + +} diff --git a/vendor/sabre/dav/tests/Sabre/DAVACL/Xml/Property/CurrentUserPrivilegeSetTest.php b/vendor/sabre/dav/tests/Sabre/DAVACL/Xml/Property/CurrentUserPrivilegeSetTest.php new file mode 100644 index 000000000..d6e6b2d19 --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/DAVACL/Xml/Property/CurrentUserPrivilegeSetTest.php @@ -0,0 +1,86 @@ +<?php + +namespace Sabre\DAVACL\Xml\Property; + +use Sabre\DAV; +use Sabre\DAV\Browser\HtmlOutputHelper; +use Sabre\HTTP; +use Sabre\Xml\Reader; + +class CurrentUserPrivilegeSetTest extends \PHPUnit_Framework_TestCase { + + function testSerialize() { + + $privileges = [ + '{DAV:}read', + '{DAV:}write', + ]; + $prop = new CurrentUserPrivilegeSet($privileges); + $xml = (new DAV\Server())->xml->write('{DAV:}root', $prop); + + $expected = <<<XML +<d:root xmlns:d="DAV:" xmlns:s="http://sabredav.org/ns"> + <d:privilege> + <d:read /> + </d:privilege> + <d:privilege> + <d:write /> + </d:privilege> +</d:root> +XML; + + + $this->assertXmlStringEqualsXmlString($expected, $xml); + + } + + function testUnserialize() { + + $source = '<?xml version="1.0"?> +<d:root xmlns:d="DAV:"> + <d:privilege> + <d:write-properties /> + </d:privilege> + <d:ignoreme /> + <d:privilege> + <d:read /> + </d:privilege> +</d:root> +'; + + $result = $this->parse($source); + $this->assertTrue($result->has('{DAV:}read')); + $this->assertTrue($result->has('{DAV:}write-properties')); + $this->assertFalse($result->has('{DAV:}bind')); + + } + + function parse($xml) { + + $reader = new Reader(); + $reader->elementMap['{DAV:}root'] = 'Sabre\\DAVACL\\Xml\\Property\\CurrentUserPrivilegeSet'; + $reader->xml($xml); + $result = $reader->parse(); + return $result['value']; + + } + + function testToHtml() { + + $privileges = ['{DAV:}read', '{DAV:}write']; + + $prop = new CurrentUserPrivilegeSet($privileges); + $html = new HtmlOutputHelper( + '/base/', + ['DAV:' => 'd'] + ); + + $expected = + '<span title="{DAV:}read">d:read</span>, ' . + '<span title="{DAV:}write">d:write</span>'; + + $this->assertEquals($expected, $prop->toHtml($html)); + + } + +} diff --git a/vendor/sabre/dav/tests/Sabre/DAVACL/Xml/Property/PrincipalTest.php b/vendor/sabre/dav/tests/Sabre/DAVACL/Xml/Property/PrincipalTest.php new file mode 100644 index 000000000..876d1073a --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/DAVACL/Xml/Property/PrincipalTest.php @@ -0,0 +1,191 @@ +<?php + +namespace Sabre\DAVACL\Xml\Property; + +use Sabre\DAV; +use Sabre\DAV\Browser\HtmlOutputHelper; +use Sabre\HTTP; +use Sabre\Xml\Reader; + +class PrincipalTest extends \PHPUnit_Framework_TestCase { + + function testSimple() { + + $principal = new Principal(Principal::UNAUTHENTICATED); + $this->assertEquals(Principal::UNAUTHENTICATED, $principal->getType()); + $this->assertNull($principal->getHref()); + + $principal = new Principal(Principal::AUTHENTICATED); + $this->assertEquals(Principal::AUTHENTICATED, $principal->getType()); + $this->assertNull($principal->getHref()); + + $principal = new Principal(Principal::HREF, 'admin'); + $this->assertEquals(Principal::HREF, $principal->getType()); + $this->assertEquals('admin/', $principal->getHref()); + + } + + /** + * @depends testSimple + * @expectedException Sabre\DAV\Exception + */ + function testNoHref() { + + $principal = new Principal(Principal::HREF); + + } + + /** + * @depends testSimple + */ + function testSerializeUnAuthenticated() { + + $prin = new Principal(Principal::UNAUTHENTICATED); + + $xml = (new DAV\Server())->xml->write('{DAV:}principal', $prin); + + $this->assertXmlStringEqualsXmlString(' +<d:principal xmlns:d="DAV:" xmlns:s="http://sabredav.org/ns"> +<d:unauthenticated/> +</d:principal>', $xml); + + } + + + /** + * @depends testSerializeUnAuthenticated + */ + function testSerializeAuthenticated() { + + $prin = new Principal(Principal::AUTHENTICATED); + $xml = (new DAV\Server())->xml->write('{DAV:}principal', $prin); + + $this->assertXmlStringEqualsXmlString(' +<d:principal xmlns:d="DAV:" xmlns:s="http://sabredav.org/ns"> +<d:authenticated/> +</d:principal>', $xml); + + } + + + /** + * @depends testSerializeUnAuthenticated + */ + function testSerializeHref() { + + $prin = new Principal(Principal::HREF, 'principals/admin'); + $xml = (new DAV\Server())->xml->write('{DAV:}principal', $prin, '/'); + + $this->assertXmlStringEqualsXmlString(' +<d:principal xmlns:d="DAV:" xmlns:s="http://sabredav.org/ns"> +<d:href>/principals/admin/</d:href> +</d:principal>', $xml); + + } + + function testUnserializeHref() { + + $xml = '<?xml version="1.0"?> +<d:principal xmlns:d="DAV:">' . +'<d:href>/principals/admin</d:href>' . +'</d:principal>'; + + $principal = $this->parse($xml); + $this->assertEquals(Principal::HREF, $principal->getType()); + $this->assertEquals('/principals/admin/', $principal->getHref()); + + } + + function testUnserializeAuthenticated() { + + $xml = '<?xml version="1.0"?> +<d:principal xmlns:d="DAV:">' . +' <d:authenticated />' . +'</d:principal>'; + + $principal = $this->parse($xml); + $this->assertEquals(Principal::AUTHENTICATED, $principal->getType()); + + } + + function testUnserializeUnauthenticated() { + + $xml = '<?xml version="1.0"?> +<d:principal xmlns:d="DAV:">' . +' <d:unauthenticated />' . +'</d:principal>'; + + $principal = $this->parse($xml); + $this->assertEquals(Principal::UNAUTHENTICATED, $principal->getType()); + + } + + /** + * @expectedException Sabre\DAV\Exception\BadRequest + */ + function testUnserializeUnknown() { + + $xml = '<?xml version="1.0"?> +<d:principal xmlns:d="DAV:">' . +' <d:foo />' . +'</d:principal>'; + + $this->parse($xml); + + } + + function parse($xml) { + + $reader = new Reader(); + $reader->elementMap['{DAV:}principal'] = 'Sabre\\DAVACL\\Xml\\Property\\Principal'; + $reader->xml($xml); + $result = $reader->parse(); + return $result['value']; + + } + + /** + * @depends testSimple + * @dataProvider htmlProvider + */ + function testToHtml($principal, $output) { + + $html = $principal->toHtml(new HtmlOutputHelper('/', [])); + + $this->assertXmlStringEqualsXmlString( + $output, + $html + ); + + } + + /** + * Provides data for the html tests + * + * @return array + */ + function htmlProvider() { + + return [ + [ + new Principal(Principal::UNAUTHENTICATED), + '<em>unauthenticated</em>', + ], + [ + new Principal(Principal::AUTHENTICATED), + '<em>authenticated</em>', + ], + [ + new Principal(Principal::ALL), + '<em>all</em>', + ], + [ + new Principal(Principal::HREF, 'principals/admin'), + '<a href="/principals/admin/">/principals/admin/</a>', + ], + + ]; + + } + +} diff --git a/vendor/sabre/dav/tests/Sabre/DAVACL/Xml/Property/SupportedPrivilegeSetTest.php b/vendor/sabre/dav/tests/Sabre/DAVACL/Xml/Property/SupportedPrivilegeSetTest.php new file mode 100644 index 000000000..749d349fc --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/DAVACL/Xml/Property/SupportedPrivilegeSetTest.php @@ -0,0 +1,103 @@ +<?php + +namespace Sabre\DAVACL\Xml\Property; + +use Sabre\DAV; +use Sabre\DAV\Browser\HtmlOutputHelper; +use Sabre\HTTP; + +class SupportedPrivilegeSetTest extends \PHPUnit_Framework_TestCase { + + function testSimple() { + + $prop = new SupportedPrivilegeSet([ + 'privilege' => '{DAV:}all', + ]); + $this->assertInstanceOf('Sabre\DAVACL\Xml\Property\SupportedPrivilegeSet', $prop); + + } + + + /** + * @depends testSimple + */ + function testSerializeSimple() { + + $prop = new SupportedPrivilegeSet([]); + + $xml = (new DAV\Server())->xml->write('{DAV:}supported-privilege-set', $prop); + + $this->assertXmlStringEqualsXmlString(' +<d:supported-privilege-set xmlns:d="DAV:" xmlns:s="http://sabredav.org/ns"> + <d:supported-privilege> + <d:privilege> + <d:all/> + </d:privilege> + </d:supported-privilege> +</d:supported-privilege-set>', $xml); + + } + + /** + * @depends testSimple + */ + function testSerializeAggregate() { + + $prop = new SupportedPrivilegeSet([ + '{DAV:}read' => [], + '{DAV:}write' => [ + 'description' => 'booh', + ] + ]); + + $xml = (new DAV\Server())->xml->write('{DAV:}supported-privilege-set', $prop); + + $this->assertXmlStringEqualsXmlString(' +<d:supported-privilege-set xmlns:d="DAV:" xmlns:s="http://sabredav.org/ns"> + <d:supported-privilege> + <d:privilege> + <d:all/> + </d:privilege> + <d:supported-privilege> + <d:privilege> + <d:read/> + </d:privilege> + </d:supported-privilege> + <d:supported-privilege> + <d:privilege> + <d:write/> + </d:privilege> + <d:description>booh</d:description> + </d:supported-privilege> + </d:supported-privilege> +</d:supported-privilege-set>', $xml); + + } + + function testToHtml() { + + $prop = new SupportedPrivilegeSet([ + '{DAV:}read' => [], + '{DAV:}write' => [ + 'description' => 'booh', + ], + ]); + $html = new HtmlOutputHelper( + '/base/', + ['DAV:' => 'd'] + ); + + $expected = <<<HTML +<ul class="tree"><li><span title="{DAV:}all">d:all</span> +<ul> +<li><span title="{DAV:}read">d:read</span></li> +<li><span title="{DAV:}write">d:write</span> booh</li> +</ul></li> +</ul> + +HTML; + + $this->assertEquals($expected, $prop->toHtml($html)); + + } +} diff --git a/vendor/sabre/dav/tests/Sabre/DAVACL/Xml/Request/AclPrincipalPropSetReportTest.php b/vendor/sabre/dav/tests/Sabre/DAVACL/Xml/Request/AclPrincipalPropSetReportTest.php new file mode 100644 index 000000000..bae682f21 --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/DAVACL/Xml/Request/AclPrincipalPropSetReportTest.php @@ -0,0 +1,30 @@ +<?php + +namespace Sabre\DAVACL\Xml\Request; + +class AclPrincipalPropSetReportTest extends \Sabre\DAV\Xml\XmlTest { + + protected $elementMap = [ + + '{DAV:}acl-principal-prop-set' => 'Sabre\DAVACL\Xml\Request\AclPrincipalPropSetReport', + + ]; + + function testDeserialize() { + + $xml = <<<XML +<?xml version="1.0" encoding="utf-8" ?> +<D:acl-principal-prop-set xmlns:D="DAV:"> + <D:prop> + <D:displayname/> + </D:prop> +</D:acl-principal-prop-set> +XML; + + $result = $this->parse($xml); + + $this->assertEquals(['{DAV:}displayname'], $result['value']->properties); + + } + +} diff --git a/vendor/sabre/dav/tests/Sabre/DAVACL/Xml/Request/PrincipalMatchReportTest.php b/vendor/sabre/dav/tests/Sabre/DAVACL/Xml/Request/PrincipalMatchReportTest.php new file mode 100644 index 000000000..1431ab349 --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/DAVACL/Xml/Request/PrincipalMatchReportTest.php @@ -0,0 +1,51 @@ +<?php + +namespace Sabre\DAVACL\Xml\Request; + +class PrincipalMatchReportTest extends \Sabre\DAV\Xml\XmlTest { + + protected $elementMap = [ + + '{DAV:}principal-match' => 'Sabre\DAVACL\Xml\Request\PrincipalMatchReport', + + ]; + + function testDeserialize() { + + $xml = <<<XML +<?xml version="1.0" encoding="utf-8" ?> + <D:principal-match xmlns:D="DAV:"> + <D:principal-property> + <D:owner/> + </D:principal-property> + </D:principal-match> +XML; + + $result = $this->parse($xml); + + $this->assertEquals(PrincipalMatchReport::PRINCIPAL_PROPERTY, $result['value']->type); + $this->assertEquals('{DAV:}owner', $result['value']->principalProperty); + + } + + function testDeserializeSelf() { + + $xml = <<<XML +<?xml version="1.0" encoding="utf-8" ?> + <D:principal-match xmlns:D="DAV:"> + <D:self /> + <D:prop> + <D:foo /> + </D:prop> + </D:principal-match> +XML; + + $result = $this->parse($xml); + + $this->assertEquals(PrincipalMatchReport::SELF, $result['value']->type); + $this->assertNull($result['value']->principalProperty); + $this->assertEquals(['{DAV:}foo'], $result['value']->properties); + + } + +} diff --git a/vendor/sabre/dav/tests/Sabre/DAVServerTest.php b/vendor/sabre/dav/tests/Sabre/DAVServerTest.php new file mode 100644 index 000000000..35f240d23 --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/DAVServerTest.php @@ -0,0 +1,306 @@ +<?php + +namespace Sabre; + +use Sabre\HTTP\Request; +use Sabre\HTTP\Response; +use Sabre\HTTP\Sapi; + +/** + * This class may be used as a basis for other webdav-related unittests. + * + * This class is supposed to provide a reasonably big framework to quickly get + * a testing environment running. + * + * @copyright Copyright (C) fruux GmbH (https://fruux.com/) + * @author Evert Pot (http://evertpot.com/) + * @license http://sabre.io/license/ Modified BSD License + */ +abstract class DAVServerTest extends \PHPUnit_Framework_TestCase { + + protected $setupCalDAV = false; + protected $setupCardDAV = false; + protected $setupACL = false; + protected $setupCalDAVSharing = false; + protected $setupCalDAVScheduling = false; + protected $setupCalDAVSubscriptions = false; + protected $setupCalDAVICSExport = false; + protected $setupLocks = false; + protected $setupFiles = false; + protected $setupSharing = false; + protected $setupPropertyStorage = false; + + /** + * An array with calendars. Every calendar should have + * - principaluri + * - uri + */ + protected $caldavCalendars = []; + protected $caldavCalendarObjects = []; + + protected $carddavAddressBooks = []; + protected $carddavCards = []; + + /** + * @var Sabre\DAV\Server + */ + protected $server; + protected $tree = []; + + protected $caldavBackend; + protected $carddavBackend; + protected $principalBackend; + protected $locksBackend; + protected $propertyStorageBackend; + + /** + * @var Sabre\CalDAV\Plugin + */ + protected $caldavPlugin; + + /** + * @var Sabre\CardDAV\Plugin + */ + protected $carddavPlugin; + + /** + * @var Sabre\DAVACL\Plugin + */ + protected $aclPlugin; + + /** + * @var Sabre\CalDAV\SharingPlugin + */ + protected $caldavSharingPlugin; + + /** + * CalDAV scheduling plugin + * + * @var CalDAV\Schedule\Plugin + */ + protected $caldavSchedulePlugin; + + /** + * @var Sabre\DAV\Auth\Plugin + */ + protected $authPlugin; + + /** + * @var Sabre\DAV\Locks\Plugin + */ + protected $locksPlugin; + + /** + * Sharing plugin. + * + * @var \Sabre\DAV\Sharing\Plugin + */ + protected $sharingPlugin; + + /* + * @var Sabre\DAV\PropertyStorage\Plugin + */ + protected $propertyStoragePlugin; + + /** + * If this string is set, we will automatically log in the user with this + * name. + */ + protected $autoLogin = null; + + function setUp() { + + $this->initializeEverything(); + + } + + function initializeEverything() { + + $this->setUpBackends(); + $this->setUpTree(); + + $this->server = new DAV\Server($this->tree); + $this->server->sapi = new HTTP\SapiMock(); + $this->server->debugExceptions = true; + + if ($this->setupCalDAV) { + $this->caldavPlugin = new CalDAV\Plugin(); + $this->server->addPlugin($this->caldavPlugin); + } + if ($this->setupCalDAVSharing || $this->setupSharing) { + $this->sharingPlugin = new DAV\Sharing\Plugin(); + $this->server->addPlugin($this->sharingPlugin); + } + if ($this->setupCalDAVSharing) { + $this->caldavSharingPlugin = new CalDAV\SharingPlugin(); + $this->server->addPlugin($this->caldavSharingPlugin); + } + if ($this->setupCalDAVScheduling) { + $this->caldavSchedulePlugin = new CalDAV\Schedule\Plugin(); + $this->server->addPlugin($this->caldavSchedulePlugin); + } + if ($this->setupCalDAVSubscriptions) { + $this->server->addPlugin(new CalDAV\Subscriptions\Plugin()); + } + if ($this->setupCalDAVICSExport) { + $this->caldavICSExportPlugin = new CalDAV\ICSExportPlugin(); + $this->server->addPlugin($this->caldavICSExportPlugin); + } + if ($this->setupCardDAV) { + $this->carddavPlugin = new CardDAV\Plugin(); + $this->server->addPlugin($this->carddavPlugin); + } + if ($this->setupLocks) { + $this->locksPlugin = new DAV\Locks\Plugin( + $this->locksBackend + ); + $this->server->addPlugin($this->locksPlugin); + } + if ($this->setupPropertyStorage) { + $this->propertyStoragePlugin = new DAV\PropertyStorage\Plugin( + $this->propertyStorageBackend + ); + $this->server->addPlugin($this->propertyStoragePlugin); + } + if ($this->autoLogin) { + $this->autoLogin($this->autoLogin); + } + if ($this->setupACL) { + $this->aclPlugin = new DAVACL\Plugin(); + if (!$this->autoLogin) { + $this->aclPlugin->allowUnauthenticatedAccess = false; + } + $this->aclPlugin->adminPrincipals = ['principals/admin']; + $this->server->addPlugin($this->aclPlugin); + } + + } + + /** + * Makes a request, and returns a response object. + * + * You can either pass an instance of Sabre\HTTP\Request, or an array, + * which will then be used as the _SERVER array. + * + * If $expectedStatus is set, we'll compare it with the HTTP status of + * the returned response. If it doesn't match, we'll immediately fail + * the test. + * + * @param array|\Sabre\HTTP\Request $request + * @param int $expectedStatus + * @return \Sabre\HTTP\Response + */ + function request($request, $expectedStatus = null) { + + if (is_array($request)) { + $request = HTTP\Request::createFromServerArray($request); + } + $response = new HTTP\ResponseMock(); + + $this->server->httpRequest = $request; + $this->server->httpResponse = $response; + $this->server->exec(); + + if ($expectedStatus) { + $responseBody = $expectedStatus !== $response->getStatus() ? $response->getBodyAsString() : ''; + $this->assertEquals($expectedStatus, $response->getStatus(), 'Incorrect HTTP status received for request. Response body: ' . $responseBody); + } + return $this->server->httpResponse; + + } + + /** + * This function takes a username and sets the server in a state where + * this user is logged in, and no longer requires an authentication check. + * + * @param string $userName + */ + function autoLogin($userName) { + $authBackend = new DAV\Auth\Backend\Mock(); + $authBackend->setPrincipal('principals/' . $userName); + $this->authPlugin = new DAV\Auth\Plugin($authBackend); + + // If the auth plugin already exists, we're removing its hooks: + if ($oldAuth = $this->server->getPlugin('auth')) { + $this->server->removeListener('beforeMethod', [$oldAuth, 'beforeMethod']); + } + $this->server->addPlugin($this->authPlugin); + + // This will trigger the actual login procedure + $this->authPlugin->beforeMethod(new Request(), new Response()); + } + + /** + * Override this to provide your own Tree for your test-case. + */ + function setUpTree() { + + if ($this->setupCalDAV) { + $this->tree[] = new CalDAV\CalendarRoot( + $this->principalBackend, + $this->caldavBackend + ); + } + if ($this->setupCardDAV) { + $this->tree[] = new CardDAV\AddressBookRoot( + $this->principalBackend, + $this->carddavBackend + ); + } + + if ($this->setupCalDAV) { + $this->tree[] = new CalDAV\Principal\Collection( + $this->principalBackend + ); + } elseif ($this->setupCardDAV || $this->setupACL) { + $this->tree[] = new DAVACL\PrincipalCollection( + $this->principalBackend + ); + } + if ($this->setupFiles) { + + $this->tree[] = new DAV\Mock\Collection('files'); + + } + + } + + function setUpBackends() { + + if ($this->setupCalDAVSharing && is_null($this->caldavBackend)) { + $this->caldavBackend = new CalDAV\Backend\MockSharing($this->caldavCalendars, $this->caldavCalendarObjects); + } + if ($this->setupCalDAVSubscriptions && is_null($this->caldavBackend)) { + $this->caldavBackend = new CalDAV\Backend\MockSubscriptionSupport($this->caldavCalendars, $this->caldavCalendarObjects); + } + if ($this->setupCalDAV && is_null($this->caldavBackend)) { + if ($this->setupCalDAVScheduling) { + $this->caldavBackend = new CalDAV\Backend\MockScheduling($this->caldavCalendars, $this->caldavCalendarObjects); + } else { + $this->caldavBackend = new CalDAV\Backend\Mock($this->caldavCalendars, $this->caldavCalendarObjects); + } + } + if ($this->setupCardDAV && is_null($this->carddavBackend)) { + $this->carddavBackend = new CardDAV\Backend\Mock($this->carddavAddressBooks, $this->carddavCards); + } + if ($this->setupCardDAV || $this->setupCalDAV || $this->setupACL) { + $this->principalBackend = new DAVACL\PrincipalBackend\Mock(); + } + if ($this->setupLocks) { + $this->locksBackend = new DAV\Locks\Backend\Mock(); + } + if ($this->setupPropertyStorage) { + $this->propertyStorageBackend = new DAV\PropertyStorage\Backend\Mock(); + } + + } + + + function assertHttpStatus($expectedStatus, HTTP\Request $req) { + + $resp = $this->request($req); + $this->assertEquals((int)$expectedStatus, (int)$resp->status, 'Incorrect HTTP status received: ' . $resp->body); + + } + +} diff --git a/vendor/sabre/dav/tests/Sabre/HTTP/ResponseMock.php b/vendor/sabre/dav/tests/Sabre/HTTP/ResponseMock.php new file mode 100644 index 000000000..eb486bf5b --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/HTTP/ResponseMock.php @@ -0,0 +1,22 @@ +<?php + +namespace Sabre\HTTP; + +/** + * HTTP Response Mock object + * + * This class exists to make the transition to sabre/http easier. + * + * @copyright Copyright (C) fruux GmbH (https://fruux.com/) + * @author Evert Pot (http://evertpot.com/) + * @license http://sabre.io/license/ Modified BSD License + */ +class ResponseMock extends Response { + + /** + * Making these public. + */ + public $body; + public $status; + +} diff --git a/vendor/sabre/dav/tests/Sabre/HTTP/SapiMock.php b/vendor/sabre/dav/tests/Sabre/HTTP/SapiMock.php new file mode 100644 index 000000000..e2888a9da --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/HTTP/SapiMock.php @@ -0,0 +1,30 @@ +<?php + +namespace Sabre\HTTP; + +/** + * HTTP Response Mock object + * + * This class exists to make the transition to sabre/http easier. + * + * @copyright Copyright (C) fruux GmbH (https://fruux.com/) + * @author Evert Pot (http://evertpot.com/) + * @license http://sabre.io/license/ Modified BSD License + */ +class SapiMock extends Sapi { + + static $sent = 0; + + /** + * Overriding this so nothing is ever echo'd. + * + * @param ResponseInterface $response + * @return void + */ + static function sendResponse(ResponseInterface $response) { + + self::$sent++; + + } + +} diff --git a/vendor/sabre/dav/tests/Sabre/TestUtil.php b/vendor/sabre/dav/tests/Sabre/TestUtil.php new file mode 100644 index 000000000..9df94915f --- /dev/null +++ b/vendor/sabre/dav/tests/Sabre/TestUtil.php @@ -0,0 +1,71 @@ +<?php + +namespace Sabre; + +class TestUtil { + + /** + * This function deletes all the contents of the temporary directory. + * + * @return void + */ + static function clearTempDir() { + + self::deleteTree(SABRE_TEMPDIR, false); + + } + + + private static function deleteTree($path, $deleteRoot = true) { + + foreach (scandir($path) as $node) { + + if ($node == '.' || $node == '..') continue; + $myPath = $path . '/' . $node; + if (is_file($myPath)) { + unlink($myPath); + } else { + self::deleteTree($myPath); + } + + } + if ($deleteRoot) { + rmdir($path); + } + + } + + static function getMySQLDB() { + + try { + $pdo = new \PDO(SABRE_MYSQLDSN, SABRE_MYSQLUSER, SABRE_MYSQLPASS); + $pdo->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION); + return $pdo; + } catch (\PDOException $e) { + return null; + } + + } + + static function getSQLiteDB() { + + $pdo = new \PDO('sqlite:' . SABRE_TEMPDIR . '/pdobackend'); + $pdo->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION); + return $pdo; + + } + + static function getPgSqlDB() { + + //try { + $pdo = new \PDO(SABRE_PGSQLDSN); + $pdo->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION); + return $pdo; + //} catch (\PDOException $e) { + // return null; + //} + + } + + +} diff --git a/vendor/sabre/dav/tests/bootstrap.php b/vendor/sabre/dav/tests/bootstrap.php new file mode 100644 index 000000000..26eb32aa2 --- /dev/null +++ b/vendor/sabre/dav/tests/bootstrap.php @@ -0,0 +1,38 @@ +<?php + +set_include_path(__DIR__ . '/../lib/' . PATH_SEPARATOR . __DIR__ . PATH_SEPARATOR . get_include_path()); + +$autoLoader = include __DIR__ . '/../vendor/autoload.php'; + +// SabreDAV tests auto loading +$autoLoader->add('Sabre\\', __DIR__); +// VObject tests auto loading +$autoLoader->addPsr4('Sabre\\VObject\\', __DIR__ . '/../vendor/sabre/vobject/tests/VObject'); +$autoLoader->addPsr4('Sabre\\Xml\\', __DIR__ . '/../vendor/sabre/xml/tests/Sabre/Xml'); + +date_default_timezone_set('UTC'); + +$config = [ + 'SABRE_TEMPDIR' => dirname(__FILE__) . '/temp/', + 'SABRE_HASSQLITE' => in_array('sqlite', PDO::getAvailableDrivers()), + 'SABRE_HASMYSQL' => in_array('mysql', PDO::getAvailableDrivers()), + 'SABRE_HASPGSQL' => in_array('pgsql', PDO::getAvailableDrivers()), + 'SABRE_MYSQLDSN' => 'mysql:host=127.0.0.1;dbname=sabredav_test', + 'SABRE_MYSQLUSER' => 'sabredav', + 'SABRE_MYSQLPASS' => '', + 'SABRE_PGSQLDSN' => 'pgsql:host=localhost;dbname=sabredav_test;user=sabredav;password=sabredav', +]; + +if (file_exists(__DIR__ . '/config.user.php')) { + include __DIR__ . '/config.user.php'; + foreach ($userConfig as $key => $value) { + $config[$key] = $value; + } +} + +foreach ($config as $key => $value) { + if (!defined($key)) define($key, $value); +} + +if (!file_exists(SABRE_TEMPDIR)) mkdir(SABRE_TEMPDIR); +if (file_exists('.sabredav')) unlink('.sabredav'); diff --git a/vendor/sabre/dav/tests/phpcs/ruleset.xml b/vendor/sabre/dav/tests/phpcs/ruleset.xml new file mode 100644 index 000000000..ec2c4c84b --- /dev/null +++ b/vendor/sabre/dav/tests/phpcs/ruleset.xml @@ -0,0 +1,57 @@ +<?xml version="1.0"?> +<ruleset name="sabre.php"> + <description>sabre.io codesniffer ruleset</description> + + <!-- Include the whole PSR-1 standard --> + <rule ref="PSR1" /> + + <!-- All PHP files MUST use the Unix LF (linefeed) line ending. --> + <rule ref="Generic.Files.LineEndings"> + <properties> + <property name="eolChar" value="\n"/> + </properties> + </rule> + + <!-- The closing ?> tag MUST be omitted from files containing only PHP. --> + <rule ref="Zend.Files.ClosingTag"/> + + <!-- There MUST NOT be trailing whitespace at the end of non-blank lines. --> + <rule ref="Squiz.WhiteSpace.SuperfluousWhitespace"> + <properties> + <property name="ignoreBlankLines" value="true"/> + </properties> + </rule> + + <!-- There MUST NOT be more than one statement per line. --> + <rule ref="Generic.Formatting.DisallowMultipleStatements"/> + + <rule ref="Generic.WhiteSpace.ScopeIndent"> + <properties> + <property name="ignoreIndentationTokens" type="array" value="T_COMMENT,T_DOC_COMMENT"/> + </properties> + </rule> + <rule ref="Generic.WhiteSpace.DisallowTabIndent"/> + + <!-- PHP keywords MUST be in lower case. --> + <rule ref="Generic.PHP.LowerCaseKeyword"/> + + <!-- The PHP constants true, false, and null MUST be in lower case. --> + <rule ref="Generic.PHP.LowerCaseConstant"/> + + <!-- <rule ref="Squiz.Scope.MethodScope"/> --> + <rule ref="Squiz.WhiteSpace.ScopeKeywordSpacing"/> + + <!-- In the argument list, there MUST NOT be a space before each comma, and there MUST be one space after each comma. --> + <!-- + <rule ref="Squiz.Functions.FunctionDeclarationArgumentSpacing"> + <properties> + <property name="equalsSpacing" value="1"/> + </properties> + </rule> + <rule ref="Squiz.Functions.FunctionDeclarationArgumentSpacing.SpacingAfterHint"> + <severity>0</severity> + </rule> + --> + <rule ref="PEAR.WhiteSpace.ScopeClosingBrace"/> + +</ruleset> diff --git a/vendor/sabre/dav/tests/phpunit.xml.dist b/vendor/sabre/dav/tests/phpunit.xml.dist new file mode 100644 index 000000000..453fabb82 --- /dev/null +++ b/vendor/sabre/dav/tests/phpunit.xml.dist @@ -0,0 +1,46 @@ +<?xml version="1.0"?> +<phpunit + colors="true" + bootstrap="bootstrap.php" + convertErrorsToExceptions="true" + convertNoticesToExceptions="true" + convertWarningsToExceptions="true" + beStrictAboutTestsThatDoNotTestAnything="true" + beStrictAboutOutputDuringTests="true" + beStrictAboutTestSize="true"> + + <testsuite name="sabre-event"> + <directory>../vendor/sabre/event/tests/</directory> + </testsuite> + <testsuite name="sabre-uri"> + <directory>../vendor/sabre/uri/tests/</directory> + </testsuite> + <testsuite name="sabre-xml"> + <directory>../vendor/sabre/xml/tests/Sabre/Xml/</directory> + </testsuite> + <testsuite name="sabre-http"> + <directory>../vendor/sabre/http/tests/HTTP</directory> + </testsuite> + <testsuite name="sabre-vobject"> + <directory>../vendor/sabre/vobject/tests/VObject</directory> + </testsuite> + + <testsuite name="sabre-dav"> + <directory>Sabre/DAV</directory> + </testsuite> + <testsuite name="sabre-davacl"> + <directory>Sabre/DAVACL</directory> + </testsuite> + <testsuite name="sabre-caldav"> + <directory>Sabre/CalDAV</directory> + </testsuite> + <testsuite name="sabre-carddav"> + <directory>Sabre/CardDAV</directory> + </testsuite> + + <filter> + <whitelist addUncoveredFilesFromWhitelist="true"> + <directory suffix=".php">../lib/</directory> + </whitelist> + </filter> +</phpunit> diff --git a/vendor/sabre/event/.gitignore b/vendor/sabre/event/.gitignore new file mode 100644 index 000000000..d06a78164 --- /dev/null +++ b/vendor/sabre/event/.gitignore @@ -0,0 +1,14 @@ +#composer +vendor +composer.lock + +#binaries +bin/sabre-cs-fixer +bin/php-cs-fixer +bin/phpunit + +#vim lock files +.*.swp + +#development stuff +tests/cov diff --git a/vendor/sabre/event/.travis.yml b/vendor/sabre/event/.travis.yml new file mode 100644 index 000000000..b6719f591 --- /dev/null +++ b/vendor/sabre/event/.travis.yml @@ -0,0 +1,26 @@ +language: php +php: + - 5.5 + - 5.6 + - 7 + - hhvm + +matrix: + allow_failures: + - php: hhvm + +env: + matrix: + - LOWEST_DEPS="" + - LOWEST_DEPS="--prefer-lowest" + +before_script: + - composer update --prefer-source $LOWEST_DEPS + +script: + - ./bin/phpunit + - ./bin/sabre-cs-fixer fix . --dry-run --diff + +sudo: false + +cache: vendor diff --git a/vendor/sabre/event/bin/.empty b/vendor/sabre/event/bin/.empty new file mode 100644 index 000000000..e69de29bb diff --git a/vendor/sabre/event/composer.json b/vendor/sabre/event/composer.json new file mode 100644 index 000000000..9a11b01aa --- /dev/null +++ b/vendor/sabre/event/composer.json @@ -0,0 +1,47 @@ +{ + "name": "sabre/event", + "description": "sabre/event is a library for lightweight event-based programming", + "keywords": [ + "Events", + "EventEmitter", + "Promise", + "Hooks", + "Plugin", + "Signal", + "Async" + ], + "homepage": "http://sabre.io/event/", + "license": "BSD-3-Clause", + "require": { + "php": ">=5.5" + }, + "authors": [ + { + "name": "Evert Pot", + "email": "me@evertpot.com", + "homepage": "http://evertpot.com/", + "role": "Developer" + } + ], + "support": { + "forum": "https://groups.google.com/group/sabredav-discuss", + "source": "https://github.com/fruux/sabre-event" + }, + "autoload": { + "psr-4": { + "Sabre\\Event\\": "lib/" + }, + "files" : [ + "lib/coroutine.php", + "lib/Loop/functions.php", + "lib/Promise/functions.php" + ] + }, + "require-dev": { + "sabre/cs": "~0.0.4", + "phpunit/phpunit" : "*" + }, + "config" : { + "bin-dir" : "bin/" + } +} diff --git a/vendor/sabre/event/examples/promise.php b/vendor/sabre/event/examples/promise.php old mode 100644 new mode 100755 diff --git a/vendor/sabre/event/examples/tail.php b/vendor/sabre/event/examples/tail.php old mode 100644 new mode 100755 diff --git a/vendor/sabre/event/tests/ContinueCallbackTest.php b/vendor/sabre/event/tests/ContinueCallbackTest.php new file mode 100644 index 000000000..c46991379 --- /dev/null +++ b/vendor/sabre/event/tests/ContinueCallbackTest.php @@ -0,0 +1,76 @@ +<?php + +namespace Sabre\Event; + +class ContinueCallbackTest extends \PHPUnit_Framework_TestCase { + + function testContinueCallBack() { + + $ee = new EventEmitter(); + + $handlerCounter = 0; + $bla = function() use (&$handlerCounter) { + $handlerCounter++; + }; + $ee->on('foo', $bla); + $ee->on('foo', $bla); + $ee->on('foo', $bla); + + $continueCounter = 0; + $r = $ee->emit('foo', [], function() use (&$continueCounter) { + $continueCounter++; + return true; + }); + $this->assertTrue($r); + $this->assertEquals(3, $handlerCounter); + $this->assertEquals(2, $continueCounter); + + } + + function testContinueCallBackBreak() { + + $ee = new EventEmitter(); + + $handlerCounter = 0; + $bla = function() use (&$handlerCounter) { + $handlerCounter++; + }; + $ee->on('foo', $bla); + $ee->on('foo', $bla); + $ee->on('foo', $bla); + + $continueCounter = 0; + $r = $ee->emit('foo', [], function() use (&$continueCounter) { + $continueCounter++; + return false; + }); + $this->assertTrue($r); + $this->assertEquals(1, $handlerCounter); + $this->assertEquals(1, $continueCounter); + + } + + function testContinueCallBackBreakByHandler() { + + $ee = new EventEmitter(); + + $handlerCounter = 0; + $bla = function() use (&$handlerCounter) { + $handlerCounter++; + return false; + }; + $ee->on('foo', $bla); + $ee->on('foo', $bla); + $ee->on('foo', $bla); + + $continueCounter = 0; + $r = $ee->emit('foo', [], function() use (&$continueCounter) { + $continueCounter++; + return false; + }); + $this->assertFalse($r); + $this->assertEquals(1, $handlerCounter); + $this->assertEquals(0, $continueCounter); + + } +} diff --git a/vendor/sabre/event/tests/CoroutineTest.php b/vendor/sabre/event/tests/CoroutineTest.php new file mode 100644 index 000000000..6e4b666b0 --- /dev/null +++ b/vendor/sabre/event/tests/CoroutineTest.php @@ -0,0 +1,262 @@ +<?php + +namespace Sabre\Event; + +class CoroutineTest extends \PHPUnit_Framework_TestCase { + + /** + * @expectedException \InvalidArgumentException + */ + function testNonGenerator() { + + coroutine(function() {}); + + } + + function testBasicCoroutine() { + + $start = 0; + + coroutine(function() use (&$start) { + + $start += 1; + yield; + + }); + + $this->assertEquals(1, $start); + + } + + function testFulfilledPromise() { + + $start = 0; + $promise = new Promise(function($fulfill, $reject) { + $fulfill(2); + }); + + coroutine(function() use (&$start, $promise) { + + $start += 1; + $start += (yield $promise); + + }); + + Loop\run(); + $this->assertEquals(3, $start); + + } + + function testRejectedPromise() { + + $start = 0; + $promise = new Promise(function($fulfill, $reject) { + $reject(2); + }); + + coroutine(function() use (&$start, $promise) { + + $start += 1; + try { + $start += (yield $promise); + // This line is unreachable, but it's our control + $start += 4; + } catch (\Exception $e) { + $start += $e->getMessage(); + } + + }); + + Loop\run(); + $this->assertEquals(3, $start); + + } + + function testRejectedPromiseException() { + + $start = 0; + $promise = new Promise(function($fulfill, $reject) { + $reject(new \LogicException('2')); + }); + + coroutine(function() use (&$start, $promise) { + + $start += 1; + try { + $start += (yield $promise); + // This line is unreachable, but it's our control + $start += 4; + } catch (\LogicException $e) { + $start += $e->getMessage(); + } + + }); + + Loop\run(); + $this->assertEquals(3, $start); + + } + + function testRejectedPromiseArray() { + + $start = 0; + $promise = new Promise(function($fulfill, $reject) { + $reject([]); + }); + + coroutine(function() use (&$start, $promise) { + + $start += 1; + try { + $start += (yield $promise); + // This line is unreachable, but it's our control + $start += 4; + } catch (\Exception $e) { + $this->assertTrue(strpos($e->getMessage(), 'Promise was rejected with') === 0); + $start += 2; + } + + })->wait(); + + $this->assertEquals(3, $start); + + } + + function testFulfilledPromiseAsync() { + + $start = 0; + $promise = new Promise(); + coroutine(function() use (&$start, $promise) { + + $start += 1; + $start += (yield $promise); + + }); + Loop\run(); + + $this->assertEquals(1, $start); + + $promise->fulfill(2); + Loop\run(); + + $this->assertEquals(3, $start); + + } + + function testRejectedPromiseAsync() { + + $start = 0; + $promise = new Promise(); + coroutine(function() use (&$start, $promise) { + + $start += 1; + try { + $start += (yield $promise); + // This line is unreachable, but it's our control + $start += 4; + } catch (\Exception $e) { + $start += $e->getMessage(); + } + + }); + + $this->assertEquals(1, $start); + + $promise->reject(new \Exception(2)); + Loop\run(); + + $this->assertEquals(3, $start); + + } + + function testCoroutineException() { + + $start = 0; + coroutine(function() use (&$start) { + + $start += 1; + $start += (yield 2); + + throw new \Exception('4'); + + })->error(function($e) use (&$start) { + + $start += $e->getMessage(); + + }); + Loop\run(); + + $this->assertEquals(7, $start); + + } + + function testDeepException() { + + $start = 0; + $promise = new Promise(); + coroutine(function() use (&$start, $promise) { + + $start += 1; + $start += (yield $promise); + + })->error(function($e) use (&$start) { + + $start += $e->getMessage(); + + }); + + $this->assertEquals(1, $start); + + $promise->reject(new \Exception(2)); + Loop\run(); + + $this->assertEquals(3, $start); + + } + + function testResolveToLastYield() { + + $ok = false; + coroutine(function() { + + yield 1; + yield 2; + $hello = 'hi'; + + })->then(function($value) use (&$ok) { + $this->assertEquals(2, $value); + $ok = true; + })->error(function($reason) { + $this->fail($reason); + }); + Loop\run(); + + $this->assertTrue($ok); + + } + + function testResolveToLastYieldPromise() { + + $ok = false; + + $promise = new Promise(); + + coroutine(function() use ($promise) { + + yield 'fail'; + yield $promise; + $hello = 'hi'; + + })->then(function($value) use (&$ok) { + $ok = $value; + $this->fail($reason); + }); + + $promise->fulfill('omg it worked'); + Loop\run(); + + $this->assertEquals('omg it worked', $ok); + + } + +} diff --git a/vendor/sabre/event/tests/EventEmitterTest.php b/vendor/sabre/event/tests/EventEmitterTest.php new file mode 100644 index 000000000..df08e9cd8 --- /dev/null +++ b/vendor/sabre/event/tests/EventEmitterTest.php @@ -0,0 +1,318 @@ +<?php + +namespace Sabre\Event; + +class EventEmitterTest extends \PHPUnit_Framework_TestCase { + + function testInit() { + + $ee = new EventEmitter(); + $this->assertInstanceOf('Sabre\\Event\\EventEmitter', $ee); + + } + + function testListeners() { + + $ee = new EventEmitter(); + + $callback1 = function() { }; + $callback2 = function() { }; + $ee->on('foo', $callback1, 200); + $ee->on('foo', $callback2, 100); + + $this->assertEquals([$callback2, $callback1], $ee->listeners('foo')); + + } + + /** + * @depends testInit + */ + function testHandleEvent() { + + $argResult = null; + + $ee = new EventEmitter(); + $ee->on('foo', function($arg) use (&$argResult) { + + $argResult = $arg; + + }); + + $this->assertTrue( + $ee->emit('foo', ['bar']) + ); + + $this->assertEquals('bar', $argResult); + + } + + /** + * @depends testHandleEvent + */ + function testCancelEvent() { + + $argResult = 0; + + $ee = new EventEmitter(); + $ee->on('foo', function($arg) use (&$argResult) { + + $argResult = 1; + return false; + + }); + $ee->on('foo', function($arg) use (&$argResult) { + + $argResult = 2; + + }); + + $this->assertFalse( + $ee->emit('foo', ['bar']) + ); + + $this->assertEquals(1, $argResult); + + } + + /** + * @depends testCancelEvent + */ + function testPriority() { + + $argResult = 0; + + $ee = new EventEmitter(); + $ee->on('foo', function($arg) use (&$argResult) { + + $argResult = 1; + return false; + + }); + $ee->on('foo', function($arg) use (&$argResult) { + + $argResult = 2; + return false; + + }, 1); + + $this->assertFalse( + $ee->emit('foo', ['bar']) + ); + + $this->assertEquals(2, $argResult); + + } + + /** + * @depends testPriority + */ + function testPriority2() { + + $result = []; + $ee = new EventEmitter(); + + $ee->on('foo', function() use (&$result) { + + $result[] = 'a'; + + }, 200); + $ee->on('foo', function() use (&$result) { + + $result[] = 'b'; + + }, 50); + $ee->on('foo', function() use (&$result) { + + $result[] = 'c'; + + }, 300); + $ee->on('foo', function() use (&$result) { + + $result[] = 'd'; + + }); + + $ee->emit('foo'); + $this->assertEquals(['b', 'd', 'a', 'c'], $result); + + } + + function testRemoveListener() { + + $result = false; + + $callBack = function() use (&$result) { + + $result = true; + + }; + + $ee = new EventEmitter(); + + $ee->on('foo', $callBack); + + $ee->emit('foo'); + $this->assertTrue($result); + $result = false; + + $this->assertTrue( + $ee->removeListener('foo', $callBack) + ); + + $ee->emit('foo'); + $this->assertFalse($result); + + } + + function testRemoveUnknownListener() { + + $result = false; + + $callBack = function() use (&$result) { + + $result = true; + + }; + + $ee = new EventEmitter(); + + $ee->on('foo', $callBack); + + $ee->emit('foo'); + $this->assertTrue($result); + $result = false; + + $this->assertFalse($ee->removeListener('bar', $callBack)); + + $ee->emit('foo'); + $this->assertTrue($result); + + } + + function testRemoveListenerTwice() { + + $result = false; + + $callBack = function() use (&$result) { + + $result = true; + + }; + + $ee = new EventEmitter(); + + $ee->on('foo', $callBack); + + $ee->emit('foo'); + $this->assertTrue($result); + $result = false; + + $this->assertTrue( + $ee->removeListener('foo', $callBack) + ); + $this->assertFalse( + $ee->removeListener('foo', $callBack) + ); + + $ee->emit('foo'); + $this->assertFalse($result); + + } + + function testRemoveAllListeners() { + + $result = false; + $callBack = function() use (&$result) { + + $result = true; + + }; + + $ee = new EventEmitter(); + $ee->on('foo', $callBack); + + $ee->emit('foo'); + $this->assertTrue($result); + $result = false; + + $ee->removeAllListeners('foo'); + + $ee->emit('foo'); + $this->assertFalse($result); + + } + + function testRemoveAllListenersNoArg() { + + $result = false; + + $callBack = function() use (&$result) { + + $result = true; + + }; + + + $ee = new EventEmitter(); + $ee->on('foo', $callBack); + + $ee->emit('foo'); + $this->assertTrue($result); + $result = false; + + $ee->removeAllListeners(); + + $ee->emit('foo'); + $this->assertFalse($result); + + } + + function testOnce() { + + $result = 0; + + $callBack = function() use (&$result) { + + $result++; + + }; + + $ee = new EventEmitter(); + $ee->once('foo', $callBack); + + $ee->emit('foo'); + $ee->emit('foo'); + + $this->assertEquals(1, $result); + + } + + /** + * @depends testCancelEvent + */ + function testPriorityOnce() { + + $argResult = 0; + + $ee = new EventEmitter(); + $ee->once('foo', function($arg) use (&$argResult) { + + $argResult = 1; + return false; + + }); + $ee->once('foo', function($arg) use (&$argResult) { + + $argResult = 2; + return false; + + }, 1); + + $this->assertFalse( + $ee->emit('foo', ['bar']) + ); + + $this->assertEquals(2, $argResult); + + } +} diff --git a/vendor/sabre/event/tests/Loop/FunctionsTest.php b/vendor/sabre/event/tests/Loop/FunctionsTest.php new file mode 100644 index 000000000..08bf306c3 --- /dev/null +++ b/vendor/sabre/event/tests/Loop/FunctionsTest.php @@ -0,0 +1,160 @@ +<?php + +namespace Sabre\Event\Loop; + +class FunctionsTest extends \PHPUnit_Framework_TestCase { + + function setUp() { + + // Always creating a fresh loop object. + instance(new Loop()); + + } + + function tearDown() { + + // Removing the global loop object. + instance(null); + + } + + function testNextTick() { + + $check = 0; + nextTick(function() use (&$check) { + + $check++; + + }); + + run(); + + $this->assertEquals(1, $check); + + } + + function testTimeout() { + + $check = 0; + setTimeout(function() use (&$check) { + + $check++; + + }, 0.02); + + run(); + + $this->assertEquals(1, $check); + + } + + function testTimeoutOrder() { + + $check = []; + setTimeout(function() use (&$check) { + + $check[] = 'a'; + + }, 0.2); + setTimeout(function() use (&$check) { + + $check[] = 'b'; + + }, 0.1); + setTimeout(function() use (&$check) { + + $check[] = 'c'; + + }, 0.3); + + run(); + + $this->assertEquals(['b', 'a', 'c'], $check); + + } + + function testSetInterval() { + + $check = 0; + $intervalId = null; + $intervalId = setInterval(function() use (&$check, &$intervalId) { + + $check++; + if ($check > 5) { + clearInterval($intervalId); + } + + }, 0.02); + + run(); + $this->assertEquals(6, $check); + + } + + function testAddWriteStream() { + + $h = fopen('php://temp', 'r+'); + addWriteStream($h, function() use ($h) { + + fwrite($h, 'hello world'); + removeWriteStream($h); + + }); + run(); + rewind($h); + $this->assertEquals('hello world', stream_get_contents($h)); + + } + + function testAddReadStream() { + + $h = fopen('php://temp', 'r+'); + fwrite($h, 'hello world'); + rewind($h); + + $result = null; + + addReadStream($h, function() use ($h, &$result) { + + $result = fgets($h); + removeReadStream($h); + + }); + run(); + $this->assertEquals('hello world', $result); + + } + + function testStop() { + + $check = 0; + setTimeout(function() use (&$check) { + $check++; + }, 200); + + nextTick(function() { + stop(); + }); + run(); + + $this->assertEquals(0, $check); + + } + + function testTick() { + + $check = 0; + setTimeout(function() use (&$check) { + $check++; + }, 1); + + nextTick(function() use (&$check) { + $check++; + }); + tick(); + + $this->assertEquals(1, $check); + + } + +} diff --git a/vendor/sabre/event/tests/Loop/LoopTest.php b/vendor/sabre/event/tests/Loop/LoopTest.php new file mode 100644 index 000000000..a9cf551bd --- /dev/null +++ b/vendor/sabre/event/tests/Loop/LoopTest.php @@ -0,0 +1,180 @@ +<?php + +namespace Sabre\Event\Loop; + +class LoopTest extends \PHPUnit_Framework_TestCase { + + function testNextTick() { + + $loop = new Loop(); + $check = 0; + $loop->nextTick(function() use (&$check) { + + $check++; + + }); + + $loop->run(); + + $this->assertEquals(1, $check); + + } + + function testTimeout() { + + $loop = new Loop(); + $check = 0; + $loop->setTimeout(function() use (&$check) { + + $check++; + + }, 0.02); + + $loop->run(); + + $this->assertEquals(1, $check); + + } + + function testTimeoutOrder() { + + $loop = new Loop(); + $check = []; + $loop->setTimeout(function() use (&$check) { + + $check[] = 'a'; + + }, 0.2); + $loop->setTimeout(function() use (&$check) { + + $check[] = 'b'; + + }, 0.1); + $loop->setTimeout(function() use (&$check) { + + $check[] = 'c'; + + }, 0.3); + + $loop->run(); + + $this->assertEquals(['b', 'a', 'c'], $check); + + } + + function testSetInterval() { + + $loop = new Loop(); + $check = 0; + $intervalId = null; + $intervalId = $loop->setInterval(function() use (&$check, &$intervalId, $loop) { + + $check++; + if ($check > 5) { + $loop->clearInterval($intervalId); + } + + }, 0.02); + + $loop->run(); + $this->assertEquals(6, $check); + + } + + function testAddWriteStream() { + + $h = fopen('php://temp', 'r+'); + $loop = new Loop(); + $loop->addWriteStream($h, function() use ($h, $loop) { + + fwrite($h, 'hello world'); + $loop->removeWriteStream($h); + + }); + $loop->run(); + rewind($h); + $this->assertEquals('hello world', stream_get_contents($h)); + + } + + function testAddReadStream() { + + $h = fopen('php://temp', 'r+'); + fwrite($h, 'hello world'); + rewind($h); + + $loop = new Loop(); + + $result = null; + + $loop->addReadStream($h, function() use ($h, $loop, &$result) { + + $result = fgets($h); + $loop->removeReadStream($h); + + }); + $loop->run(); + $this->assertEquals('hello world', $result); + + } + + function testStop() { + + $check = 0; + $loop = new Loop(); + $loop->setTimeout(function() use (&$check) { + $check++; + }, 200); + + $loop->nextTick(function() use ($loop) { + $loop->stop(); + }); + $loop->run(); + + $this->assertEquals(0, $check); + + } + + function testTick() { + + $check = 0; + $loop = new Loop(); + $loop->setTimeout(function() use (&$check) { + $check++; + }, 1); + + $loop->nextTick(function() use ($loop, &$check) { + $check++; + }); + $loop->tick(); + + $this->assertEquals(1, $check); + + } + + /** + * Here we add a new nextTick function as we're in the middle of a current + * nextTick. + */ + function testNextTickStacking() { + + $loop = new Loop(); + $check = 0; + $loop->nextTick(function() use (&$check, $loop) { + + $loop->nextTick(function() use (&$check) { + + $check++; + + }); + $check++; + + }); + + $loop->run(); + + $this->assertEquals(2, $check); + + } + +} diff --git a/vendor/sabre/event/tests/Promise/FunctionsTest.php b/vendor/sabre/event/tests/Promise/FunctionsTest.php new file mode 100644 index 000000000..51e47ae29 --- /dev/null +++ b/vendor/sabre/event/tests/Promise/FunctionsTest.php @@ -0,0 +1,184 @@ +<?php + +namespace Sabre\Event\Promise; + +use Sabre\Event\Loop; +use Sabre\Event\Promise; + +class FunctionsTest extends \PHPUnit_Framework_TestCase { + + function testAll() { + + $promise1 = new Promise(); + $promise2 = new Promise(); + + $finalValue = 0; + Promise\all([$promise1, $promise2])->then(function($value) use (&$finalValue) { + + $finalValue = $value; + + }); + + $promise1->fulfill(1); + Loop\run(); + $this->assertEquals(0, $finalValue); + + $promise2->fulfill(2); + Loop\run(); + $this->assertEquals([1, 2], $finalValue); + + } + + function testAllReject() { + + $promise1 = new Promise(); + $promise2 = new Promise(); + + $finalValue = 0; + Promise\all([$promise1, $promise2])->then( + function($value) use (&$finalValue) { + $finalValue = 'foo'; + return 'test'; + }, + function($value) use (&$finalValue) { + $finalValue = $value; + } + ); + + $promise1->reject(1); + Loop\run(); + $this->assertEquals(1, $finalValue); + $promise2->reject(2); + Loop\run(); + $this->assertEquals(1, $finalValue); + + } + + function testAllRejectThenResolve() { + + $promise1 = new Promise(); + $promise2 = new Promise(); + + $finalValue = 0; + Promise\all([$promise1, $promise2])->then( + function($value) use (&$finalValue) { + $finalValue = 'foo'; + return 'test'; + }, + function($value) use (&$finalValue) { + $finalValue = $value; + } + ); + + $promise1->reject(1); + Loop\run(); + $this->assertEquals(1, $finalValue); + $promise2->fulfill(2); + Loop\run(); + $this->assertEquals(1, $finalValue); + + } + + function testRace() { + + $promise1 = new Promise(); + $promise2 = new Promise(); + + $finalValue = 0; + Promise\race([$promise1, $promise2])->then( + function($value) use (&$finalValue) { + $finalValue = $value; + }, + function($value) use (&$finalValue) { + $finalValue = $value; + } + ); + + $promise1->fulfill(1); + Loop\run(); + $this->assertEquals(1, $finalValue); + $promise2->fulfill(2); + Loop\run(); + $this->assertEquals(1, $finalValue); + + } + + function testRaceReject() { + + $promise1 = new Promise(); + $promise2 = new Promise(); + + $finalValue = 0; + Promise\race([$promise1, $promise2])->then( + function($value) use (&$finalValue) { + $finalValue = $value; + }, + function($value) use (&$finalValue) { + $finalValue = $value; + } + ); + + $promise1->reject(1); + Loop\run(); + $this->assertEquals(1, $finalValue); + $promise2->reject(2); + Loop\run(); + $this->assertEquals(1, $finalValue); + + } + + function testResolve() { + + $finalValue = 0; + + $promise = resolve(1); + $promise->then(function($value) use (&$finalValue) { + + $finalValue = $value; + + }); + + $this->assertEquals(0, $finalValue); + Loop\run(); + $this->assertEquals(1, $finalValue); + + } + + /** + * @expectedException \Exception + */ + function testResolvePromise() { + + $finalValue = 0; + + $promise = new Promise(); + $promise->reject(new \Exception('uh oh')); + + $newPromise = resolve($promise); + $newPromise->wait(); + + } + + function testReject() { + + $finalValue = 0; + + $promise = reject(1); + $promise->then(function($value) use (&$finalValue) { + + $finalValue = 'im broken'; + + }, function($reason) use (&$finalValue) { + + $finalValue = $reason; + + }); + + $this->assertEquals(0, $finalValue); + Loop\run(); + $this->assertEquals(1, $finalValue); + + } + + +} diff --git a/vendor/sabre/event/tests/Promise/PromiseTest.php b/vendor/sabre/event/tests/Promise/PromiseTest.php new file mode 100644 index 000000000..698383978 --- /dev/null +++ b/vendor/sabre/event/tests/Promise/PromiseTest.php @@ -0,0 +1,341 @@ +<?php + +namespace Sabre\Event\Promise; + +use Sabre\Event\Loop; +use Sabre\Event\Promise; + +class PromiseTest extends \PHPUnit_Framework_TestCase { + + function testSuccess() { + + $finalValue = 0; + $promise = new Promise(); + $promise->fulfill(1); + + $promise->then(function($value) use (&$finalValue) { + $finalValue = $value + 2; + }); + Loop\run(); + + $this->assertEquals(3, $finalValue); + + } + + function testFail() { + + $finalValue = 0; + $promise = new Promise(); + $promise->reject(1); + + $promise->then(null, function($value) use (&$finalValue) { + $finalValue = $value + 2; + }); + Loop\run(); + + $this->assertEquals(3, $finalValue); + + } + + function testChain() { + + $finalValue = 0; + $promise = new Promise(); + $promise->fulfill(1); + + $promise->then(function($value) use (&$finalValue) { + $finalValue = $value + 2; + return $finalValue; + })->then(function($value) use (&$finalValue) { + $finalValue = $value + 4; + return $finalValue; + }); + Loop\run(); + + $this->assertEquals(7, $finalValue); + + } + function testChainPromise() { + + $finalValue = 0; + $promise = new Promise(); + $promise->fulfill(1); + + $subPromise = new Promise(); + + $promise->then(function($value) use ($subPromise) { + return $subPromise; + })->then(function($value) use (&$finalValue) { + $finalValue = $value + 4; + return $finalValue; + }); + + $subPromise->fulfill(2); + Loop\run(); + + $this->assertEquals(6, $finalValue); + + } + + function testPendingResult() { + + $finalValue = 0; + $promise = new Promise(); + + $promise->then(function($value) use (&$finalValue) { + $finalValue = $value + 2; + }); + + $promise->fulfill(4); + Loop\run(); + + $this->assertEquals(6, $finalValue); + + } + + function testPendingFail() { + + $finalValue = 0; + $promise = new Promise(); + + $promise->then(null, function($value) use (&$finalValue) { + $finalValue = $value + 2; + }); + + $promise->reject(4); + Loop\run(); + + $this->assertEquals(6, $finalValue); + + } + + function testExecutorSuccess() { + + $promise = (new Promise(function($success, $fail) { + + $success('hi'); + + }))->then(function($result) use (&$realResult) { + + $realResult = $result; + + }); + Loop\run(); + + $this->assertEquals('hi', $realResult); + + } + + function testExecutorFail() { + + $promise = (new Promise(function($success, $fail) { + + $fail('hi'); + + }))->then(function($result) use (&$realResult) { + + $realResult = 'incorrect'; + + }, function($reason) use (&$realResult) { + + $realResult = $reason; + + }); + Loop\run(); + + $this->assertEquals('hi', $realResult); + + } + + /** + * @expectedException \Sabre\Event\PromiseAlreadyResolvedException + */ + function testFulfillTwice() { + + $promise = new Promise(); + $promise->fulfill(1); + $promise->fulfill(1); + + } + + /** + * @expectedException \Sabre\Event\PromiseAlreadyResolvedException + */ + function testRejectTwice() { + + $promise = new Promise(); + $promise->reject(1); + $promise->reject(1); + + } + + function testFromFailureHandler() { + + $ok = 0; + $promise = new Promise(); + $promise->otherwise(function($reason) { + + $this->assertEquals('foo', $reason); + throw new \Exception('hi'); + + })->then(function() use (&$ok) { + + $ok = -1; + + }, function() use (&$ok) { + + $ok = 1; + + }); + + $this->assertEquals(0, $ok); + $promise->reject('foo'); + Loop\run(); + + $this->assertEquals(1, $ok); + + } + + function testAll() { + + $promise1 = new Promise(); + $promise2 = new Promise(); + + $finalValue = 0; + Promise::all([$promise1, $promise2])->then(function($value) use (&$finalValue) { + + $finalValue = $value; + + }); + + $promise1->fulfill(1); + Loop\run(); + $this->assertEquals(0, $finalValue); + + $promise2->fulfill(2); + Loop\run(); + $this->assertEquals([1, 2], $finalValue); + + } + + function testAllReject() { + + $promise1 = new Promise(); + $promise2 = new Promise(); + + $finalValue = 0; + Promise::all([$promise1, $promise2])->then( + function($value) use (&$finalValue) { + $finalValue = 'foo'; + return 'test'; + }, + function($value) use (&$finalValue) { + $finalValue = $value; + } + ); + + $promise1->reject(1); + Loop\run(); + $this->assertEquals(1, $finalValue); + $promise2->reject(2); + Loop\run(); + $this->assertEquals(1, $finalValue); + + } + + function testAllRejectThenResolve() { + + $promise1 = new Promise(); + $promise2 = new Promise(); + + $finalValue = 0; + Promise::all([$promise1, $promise2])->then( + function($value) use (&$finalValue) { + $finalValue = 'foo'; + return 'test'; + }, + function($value) use (&$finalValue) { + $finalValue = $value; + } + ); + + $promise1->reject(1); + Loop\run(); + $this->assertEquals(1, $finalValue); + $promise2->fulfill(2); + Loop\run(); + $this->assertEquals(1, $finalValue); + + } + + function testWaitResolve() { + + $promise = new Promise(); + Loop\nextTick(function() use ($promise) { + $promise->fulfill(1); + }); + $this->assertEquals( + 1, + $promise->wait() + ); + + } + + /** + * @expectedException \LogicException + */ + function testWaitWillNeverResolve() { + + $promise = new Promise(); + $promise->wait(); + + } + + function testWaitRejectedException() { + + $promise = new Promise(); + Loop\nextTick(function() use ($promise) { + $promise->reject(new \OutOfBoundsException('foo')); + }); + try { + $promise->wait(); + $this->fail('We did not get the expected exception'); + } catch (\Exception $e) { + $this->assertInstanceOf('OutOfBoundsException', $e); + $this->assertEquals('foo', $e->getMessage()); + } + + } + + function testWaitRejectedScalar() { + + $promise = new Promise(); + Loop\nextTick(function() use ($promise) { + $promise->reject('foo'); + }); + try { + $promise->wait(); + $this->fail('We did not get the expected exception'); + } catch (\Exception $e) { + $this->assertInstanceOf('Exception', $e); + $this->assertEquals('foo', $e->getMessage()); + } + + } + + function testWaitRejectedNonScalar() { + + $promise = new Promise(); + Loop\nextTick(function() use ($promise) { + $promise->reject([]); + }); + try { + $promise->wait(); + $this->fail('We did not get the expected exception'); + } catch (\Exception $e) { + $this->assertInstanceOf('Exception', $e); + $this->assertEquals('Promise was rejected with reason of type: array', $e->getMessage()); + } + + } +} diff --git a/vendor/sabre/event/tests/PromiseTest.php b/vendor/sabre/event/tests/PromiseTest.php new file mode 100644 index 000000000..0029d898e --- /dev/null +++ b/vendor/sabre/event/tests/PromiseTest.php @@ -0,0 +1,386 @@ +<?php + +namespace Sabre\Event; + +class PromiseTest extends \PHPUnit_Framework_TestCase { + + function testSuccess() { + + $finalValue = 0; + $promise = new Promise(); + $promise->fulfill(1); + + $promise->then(function($value) use (&$finalValue) { + $finalValue = $value + 2; + }); + Loop\run(); + + $this->assertEquals(3, $finalValue); + + } + + function testFail() { + + $finalValue = 0; + $promise = new Promise(); + $promise->reject(1); + + $promise->then(null, function($value) use (&$finalValue) { + $finalValue = $value + 2; + }); + Loop\run(); + + $this->assertEquals(3, $finalValue); + + } + + function testChain() { + + $finalValue = 0; + $promise = new Promise(); + $promise->fulfill(1); + + $promise->then(function($value) use (&$finalValue) { + $finalValue = $value + 2; + return $finalValue; + })->then(function($value) use (&$finalValue) { + $finalValue = $value + 4; + return $finalValue; + }); + Loop\run(); + + $this->assertEquals(7, $finalValue); + + } + function testChainPromise() { + + $finalValue = 0; + $promise = new Promise(); + $promise->fulfill(1); + + $subPromise = new Promise(); + + $promise->then(function($value) use ($subPromise) { + return $subPromise; + })->then(function($value) use (&$finalValue) { + $finalValue = $value + 4; + return $finalValue; + }); + + $subPromise->fulfill(2); + Loop\run(); + + $this->assertEquals(6, $finalValue); + + } + + function testPendingResult() { + + $finalValue = 0; + $promise = new Promise(); + + $promise->then(function($value) use (&$finalValue) { + $finalValue = $value + 2; + }); + + $promise->fulfill(4); + Loop\run(); + + $this->assertEquals(6, $finalValue); + + } + + function testPendingFail() { + + $finalValue = 0; + $promise = new Promise(); + + $promise->then(null, function($value) use (&$finalValue) { + $finalValue = $value + 2; + }); + + $promise->reject(4); + Loop\run(); + + $this->assertEquals(6, $finalValue); + + } + + function testExecutorSuccess() { + + $promise = (new Promise(function($success, $fail) { + + $success('hi'); + + }))->then(function($result) use (&$realResult) { + + $realResult = $result; + + }); + Loop\run(); + + $this->assertEquals('hi', $realResult); + + } + + function testExecutorFail() { + + $promise = (new Promise(function($success, $fail) { + + $fail('hi'); + + }))->then(function($result) use (&$realResult) { + + $realResult = 'incorrect'; + + }, function($reason) use (&$realResult) { + + $realResult = $reason; + + }); + Loop\run(); + + $this->assertEquals('hi', $realResult); + + } + + /** + * @expectedException \Sabre\Event\PromiseAlreadyResolvedException + */ + function testFulfillTwice() { + + $promise = new Promise(); + $promise->fulfill(1); + $promise->fulfill(1); + + } + + /** + * @expectedException \Sabre\Event\PromiseAlreadyResolvedException + */ + function testRejectTwice() { + + $promise = new Promise(); + $promise->reject(1); + $promise->reject(1); + + } + + function testFromFailureHandler() { + + $ok = 0; + $promise = new Promise(); + $promise->otherwise(function($reason) { + + $this->assertEquals('foo', $reason); + throw new \Exception('hi'); + + })->then(function() use (&$ok) { + + $ok = -1; + + }, function() use (&$ok) { + + $ok = 1; + + }); + + $this->assertEquals(0, $ok); + $promise->reject('foo'); + Loop\run(); + + $this->assertEquals(1, $ok); + + } + + function testAll() { + + $promise1 = new Promise(); + $promise2 = new Promise(); + + $finalValue = 0; + Promise::all([$promise1, $promise2])->then(function($value) use (&$finalValue) { + + $finalValue = $value; + + }); + + $promise1->fulfill(1); + Loop\run(); + $this->assertEquals(0, $finalValue); + + $promise2->fulfill(2); + Loop\run(); + $this->assertEquals([1, 2], $finalValue); + + } + + function testAllReject() { + + $promise1 = new Promise(); + $promise2 = new Promise(); + + $finalValue = 0; + Promise::all([$promise1, $promise2])->then( + function($value) use (&$finalValue) { + $finalValue = 'foo'; + return 'test'; + }, + function($value) use (&$finalValue) { + $finalValue = $value; + } + ); + + $promise1->reject(1); + Loop\run(); + $this->assertEquals(1, $finalValue); + $promise2->reject(2); + Loop\run(); + $this->assertEquals(1, $finalValue); + + } + + function testAllRejectThenResolve() { + + $promise1 = new Promise(); + $promise2 = new Promise(); + + $finalValue = 0; + Promise::all([$promise1, $promise2])->then( + function($value) use (&$finalValue) { + $finalValue = 'foo'; + return 'test'; + }, + function($value) use (&$finalValue) { + $finalValue = $value; + } + ); + + $promise1->reject(1); + Loop\run(); + $this->assertEquals(1, $finalValue); + $promise2->fulfill(2); + Loop\run(); + $this->assertEquals(1, $finalValue); + + } + + function testRace() { + + $promise1 = new Promise(); + $promise2 = new Promise(); + + $finalValue = 0; + Promise\race([$promise1, $promise2])->then( + function($value) use (&$finalValue) { + $finalValue = $value; + }, + function($value) use (&$finalValue) { + $finalValue = $value; + } + ); + + $promise1->fulfill(1); + Loop\run(); + $this->assertEquals(1, $finalValue); + $promise2->fulfill(2); + Loop\run(); + $this->assertEquals(1, $finalValue); + + } + + function testRaceReject() { + + $promise1 = new Promise(); + $promise2 = new Promise(); + + $finalValue = 0; + Promise\race([$promise1, $promise2])->then( + function($value) use (&$finalValue) { + $finalValue = $value; + }, + function($value) use (&$finalValue) { + $finalValue = $value; + } + ); + + $promise1->reject(1); + Loop\run(); + $this->assertEquals(1, $finalValue); + $promise2->reject(2); + Loop\run(); + $this->assertEquals(1, $finalValue); + + } + + function testWaitResolve() { + + $promise = new Promise(); + Loop\nextTick(function() use ($promise) { + $promise->fulfill(1); + }); + $this->assertEquals( + 1, + $promise->wait() + ); + + } + + /** + * @expectedException \LogicException + */ + function testWaitWillNeverResolve() { + + $promise = new Promise(); + $promise->wait(); + + } + + function testWaitRejectedException() { + + $promise = new Promise(); + Loop\nextTick(function() use ($promise) { + $promise->reject(new \OutOfBoundsException('foo')); + }); + try { + $promise->wait(); + $this->fail('We did not get the expected exception'); + } catch (\Exception $e) { + $this->assertInstanceOf('OutOfBoundsException', $e); + $this->assertEquals('foo', $e->getMessage()); + } + + } + + function testWaitRejectedScalar() { + + $promise = new Promise(); + Loop\nextTick(function() use ($promise) { + $promise->reject('foo'); + }); + try { + $promise->wait(); + $this->fail('We did not get the expected exception'); + } catch (\Exception $e) { + $this->assertInstanceOf('Exception', $e); + $this->assertEquals('foo', $e->getMessage()); + } + + } + + function testWaitRejectedNonScalar() { + + $promise = new Promise(); + Loop\nextTick(function() use ($promise) { + $promise->reject([]); + }); + try { + $promise->wait(); + $this->fail('We did not get the expected exception'); + } catch (\Exception $e) { + $this->assertInstanceOf('Exception', $e); + $this->assertEquals('Promise was rejected with reason of type: array', $e->getMessage()); + } + + } +} diff --git a/vendor/sabre/event/tests/benchmark/bench.php b/vendor/sabre/event/tests/benchmark/bench.php new file mode 100644 index 000000000..b1e6b1d47 --- /dev/null +++ b/vendor/sabre/event/tests/benchmark/bench.php @@ -0,0 +1,116 @@ +<?php + +use Sabre\Event\EventEmitter; + +include __DIR__ . '/../../vendor/autoload.php'; + +abstract class BenchMark { + + protected $startTime; + protected $iterations = 10000; + protected $totalTime; + + function setUp() { + + } + + abstract function test(); + + function go() { + + $this->setUp(); + $this->startTime = microtime(true); + $this->test(); + $this->totalTime = microtime(true) - $this->startTime; + return $this->totalTime; + + } + +} + +class OneCallBack extends BenchMark { + + protected $emitter; + protected $iterations = 100000; + + function setUp() { + + $this->emitter = new EventEmitter(); + $this->emitter->on('foo', function() { + // NOOP + }); + + } + + function test() { + + for ($i = 0;$i < $this->iterations;$i++) { + $this->emitter->emit('foo', []); + } + + } + +} + +class ManyCallBacks extends BenchMark { + + protected $emitter; + + function setUp() { + + $this->emitter = new EventEmitter(); + for ($i = 0;$i < 100;$i++) { + $this->emitter->on('foo', function() { + // NOOP + }); + } + + } + + function test() { + + for ($i = 0;$i < $this->iterations;$i++) { + $this->emitter->emit('foo', []); + } + + } + +} + +class ManyPrioritizedCallBacks extends BenchMark { + + protected $emitter; + + function setUp() { + + $this->emitter = new EventEmitter(); + for ($i = 0;$i < 100;$i++) { + $this->emitter->on('foo', function() { + }, 1000 - $i); + } + + } + + function test() { + + for ($i = 0;$i < $this->iterations;$i++) { + $this->emitter->emit('foo', []); + } + + } + +} + +$tests = [ + 'OneCallBack', + 'ManyCallBacks', + 'ManyPrioritizedCallBacks', +]; + +foreach ($tests as $test) { + + $testObj = new $test(); + $result = $testObj->go(); + echo $test . " " . $result . "\n"; + +} diff --git a/vendor/sabre/http/.gitignore b/vendor/sabre/http/.gitignore new file mode 100644 index 000000000..8c97686fb --- /dev/null +++ b/vendor/sabre/http/.gitignore @@ -0,0 +1,15 @@ +# Composer +vendor/ +composer.lock + +# Tests +tests/cov/ + +# Composer binaries +bin/phpunit +bin/phpcs +bin/php-cs-fixer +bin/sabre-cs-fixer + +# Vim +.*.swp diff --git a/vendor/sabre/http/.travis.yml b/vendor/sabre/http/.travis.yml new file mode 100644 index 000000000..9e4964b9d --- /dev/null +++ b/vendor/sabre/http/.travis.yml @@ -0,0 +1,28 @@ +language: php +php: + - 5.4 + - 5.5 + - 5.6 + - 7 + - 7.1 + - hhvm + +matrix: + fast_finish: true + allow_failures: + - php: hhvm + +env: + matrix: + - PREFER_LOWEST="" + - PREFER_LOWEST="--prefer-lowest" + + +before_script: + - rm -f ~/.phpenv/versions/$(phpenv version-name)/etc/conf.d/xdebug.ini +# - composer self-update + - composer update --prefer-source $PREFER_LOWEST + +script: + - ./bin/phpunit --configuration tests/phpunit.xml + - ./bin/sabre-cs-fixer fix . --dry-run --diff diff --git a/vendor/sabre/http/bin/.empty b/vendor/sabre/http/bin/.empty new file mode 100644 index 000000000..e69de29bb diff --git a/vendor/sabre/http/composer.json b/vendor/sabre/http/composer.json new file mode 100644 index 000000000..507d5d28d --- /dev/null +++ b/vendor/sabre/http/composer.json @@ -0,0 +1,44 @@ +{ + "name": "sabre/http", + "description" : "The sabre/http library provides utilities for dealing with http requests and responses. ", + "keywords" : [ "HTTP" ], + "homepage" : "https://github.com/fruux/sabre-http", + "license" : "BSD-3-Clause", + "require" : { + "php" : ">=5.4", + "ext-mbstring" : "*", + "ext-ctype" : "*", + "sabre/event" : ">=1.0.0,<4.0.0", + "sabre/uri" : "~1.0" + }, + "require-dev" : { + "phpunit/phpunit" : "~4.3", + "sabre/cs" : "~0.0.1" + }, + "suggest" : { + "ext-curl" : " to make http requests with the Client class" + }, + "authors" : [ + { + "name" : "Evert Pot", + "email" : "me@evertpot.com", + "homepage" : "http://evertpot.com/", + "role" : "Developer" + } + ], + "support" : { + "forum" : "https://groups.google.com/group/sabredav-discuss", + "source" : "https://github.com/fruux/sabre-http" + }, + "autoload" : { + "files" : [ + "lib/functions.php" + ], + "psr-4" : { + "Sabre\\HTTP\\" : "lib/" + } + }, + "config" : { + "bin-dir" : "bin/" + } +} diff --git a/vendor/sabre/http/tests/HTTP/Auth/AWSTest.php b/vendor/sabre/http/tests/HTTP/Auth/AWSTest.php new file mode 100644 index 000000000..650761aca --- /dev/null +++ b/vendor/sabre/http/tests/HTTP/Auth/AWSTest.php @@ -0,0 +1,235 @@ +<?php + +namespace Sabre\HTTP\Auth; + +use Sabre\HTTP\Request; +use Sabre\HTTP\Response; + +class AWSTest extends \PHPUnit_Framework_TestCase { + + /** + * @var Sabre\HTTP\Response + */ + private $response; + + /** + * @var Sabre\HTTP\Request + */ + private $request; + + /** + * @var Sabre\HTTP\Auth\AWS + */ + private $auth; + + const REALM = 'SabreDAV unittest'; + + function setUp() { + + $this->response = new Response(); + $this->request = new Request(); + $this->auth = new AWS(self::REALM, $this->request, $this->response); + + } + + function testNoHeader() { + + $this->request->setMethod('GET'); + $result = $this->auth->init(); + + $this->assertFalse($result, 'No AWS Authorization header was supplied, so we should have gotten false'); + $this->assertEquals(AWS::ERR_NOAWSHEADER, $this->auth->errorCode); + + } + + function testIncorrectContentMD5() { + + $accessKey = 'accessKey'; + $secretKey = 'secretKey'; + + $this->request->setMethod('GET'); + $this->request->setHeaders([ + 'Authorization' => "AWS $accessKey:sig", + 'Content-MD5' => 'garbage', + ]); + $this->request->setUrl('/'); + + $this->auth->init(); + $result = $this->auth->validate($secretKey); + + $this->assertFalse($result); + $this->assertEquals(AWS::ERR_MD5CHECKSUMWRONG, $this->auth->errorCode); + + } + + function testNoDate() { + + $accessKey = 'accessKey'; + $secretKey = 'secretKey'; + $content = 'thisisthebody'; + $contentMD5 = base64_encode(md5($content, true)); + + $this->request->setMethod('POST'); + $this->request->setHeaders([ + 'Authorization' => "AWS $accessKey:sig", + 'Content-MD5' => $contentMD5, + ]); + $this->request->setUrl('/'); + $this->request->setBody($content); + + $this->auth->init(); + $result = $this->auth->validate($secretKey); + + $this->assertFalse($result); + $this->assertEquals(AWS::ERR_INVALIDDATEFORMAT, $this->auth->errorCode); + + } + + function testFutureDate() { + + $accessKey = 'accessKey'; + $secretKey = 'secretKey'; + $content = 'thisisthebody'; + $contentMD5 = base64_encode(md5($content, true)); + + $date = new \DateTime('@' . (time() + (60 * 20))); + $date->setTimeZone(new \DateTimeZone('GMT')); + $date = $date->format('D, d M Y H:i:s \\G\\M\\T'); + + $this->request->setMethod('POST'); + $this->request->setHeaders([ + 'Authorization' => "AWS $accessKey:sig", + 'Content-MD5' => $contentMD5, + 'Date' => $date, + ]); + + $this->request->setBody($content); + + $this->auth->init(); + $result = $this->auth->validate($secretKey); + + $this->assertFalse($result); + $this->assertEquals(AWS::ERR_REQUESTTIMESKEWED, $this->auth->errorCode); + + } + + function testPastDate() { + + $accessKey = 'accessKey'; + $secretKey = 'secretKey'; + $content = 'thisisthebody'; + $contentMD5 = base64_encode(md5($content, true)); + + $date = new \DateTime('@' . (time() - (60 * 20))); + $date->setTimeZone(new \DateTimeZone('GMT')); + $date = $date->format('D, d M Y H:i:s \\G\\M\\T'); + + $this->request->setMethod('POST'); + $this->request->setHeaders([ + 'Authorization' => "AWS $accessKey:sig", + 'Content-MD5' => $contentMD5, + 'Date' => $date, + ]); + + $this->request->setBody($content); + + $this->auth->init(); + $result = $this->auth->validate($secretKey); + + $this->assertFalse($result); + $this->assertEquals(AWS::ERR_REQUESTTIMESKEWED, $this->auth->errorCode); + + } + + function testIncorrectSignature() { + + $accessKey = 'accessKey'; + $secretKey = 'secretKey'; + $content = 'thisisthebody'; + + $contentMD5 = base64_encode(md5($content, true)); + + $date = new \DateTime('now'); + $date->setTimeZone(new \DateTimeZone('GMT')); + $date = $date->format('D, d M Y H:i:s \\G\\M\\T'); + + $this->request->setUrl('/'); + $this->request->setMethod('POST'); + $this->request->setHeaders([ + 'Authorization' => "AWS $accessKey:sig", + 'Content-MD5' => $contentMD5, + 'X-amz-date' => $date, + ]); + $this->request->setBody($content); + + $this->auth->init(); + $result = $this->auth->validate($secretKey); + + $this->assertFalse($result); + $this->assertEquals(AWS::ERR_INVALIDSIGNATURE, $this->auth->errorCode); + + } + + function testValidRequest() { + + $accessKey = 'accessKey'; + $secretKey = 'secretKey'; + $content = 'thisisthebody'; + $contentMD5 = base64_encode(md5($content, true)); + + $date = new \DateTime('now'); + $date->setTimeZone(new \DateTimeZone('GMT')); + $date = $date->format('D, d M Y H:i:s \\G\\M\\T'); + + + $sig = base64_encode($this->hmacsha1($secretKey, + "POST\n$contentMD5\n\n$date\nx-amz-date:$date\n/evert" + )); + + $this->request->setUrl('/evert'); + $this->request->setMethod('POST'); + $this->request->setHeaders([ + 'Authorization' => "AWS $accessKey:$sig", + 'Content-MD5' => $contentMD5, + 'X-amz-date' => $date, + ]); + + $this->request->setBody($content); + + $this->auth->init(); + $result = $this->auth->validate($secretKey); + + $this->assertTrue($result, 'Signature did not validate, got errorcode ' . $this->auth->errorCode); + $this->assertEquals($accessKey, $this->auth->getAccessKey()); + + } + + function test401() { + + $this->auth->requireLogin(); + $test = preg_match('/^AWS$/', $this->response->getHeader('WWW-Authenticate'), $matches); + $this->assertTrue($test == true, 'The WWW-Authenticate response didn\'t match our pattern'); + + } + + /** + * Generates an HMAC-SHA1 signature + * + * @param string $key + * @param string $message + * @return string + */ + private function hmacsha1($key, $message) { + + $blocksize = 64; + if (strlen($key) > $blocksize) + $key = pack('H*', sha1($key)); + $key = str_pad($key, $blocksize, chr(0x00)); + $ipad = str_repeat(chr(0x36), $blocksize); + $opad = str_repeat(chr(0x5c), $blocksize); + $hmac = pack('H*', sha1(($key ^ $opad) . pack('H*', sha1(($key ^ $ipad) . $message)))); + return $hmac; + + } + +} diff --git a/vendor/sabre/http/tests/HTTP/Auth/BasicTest.php b/vendor/sabre/http/tests/HTTP/Auth/BasicTest.php new file mode 100644 index 000000000..2a236f58b --- /dev/null +++ b/vendor/sabre/http/tests/HTTP/Auth/BasicTest.php @@ -0,0 +1,69 @@ +<?php + +namespace Sabre\HTTP\Auth; + +use Sabre\HTTP\Request; +use Sabre\HTTP\Response; + +class BasicTest extends \PHPUnit_Framework_TestCase { + + function testGetCredentials() { + + $request = new Request('GET', '/', [ + 'Authorization' => 'Basic ' . base64_encode('user:pass:bla') + ]); + + $basic = new Basic('Dagger', $request, new Response()); + + $this->assertEquals([ + 'user', + 'pass:bla', + ], $basic->getCredentials()); + + } + + function testGetInvalidCredentialsColonMissing() { + + $request = new Request('GET', '/', [ + 'Authorization' => 'Basic ' . base64_encode('userpass') + ]); + + $basic = new Basic('Dagger', $request, new Response()); + + $this->assertNull($basic->getCredentials()); + + } + + function testGetCredentialsNoheader() { + + $request = new Request('GET', '/', []); + $basic = new Basic('Dagger', $request, new Response()); + + $this->assertNull($basic->getCredentials()); + + } + + function testGetCredentialsNotBasic() { + + $request = new Request('GET', '/', [ + 'Authorization' => 'QBasic ' . base64_encode('user:pass:bla') + ]); + $basic = new Basic('Dagger', $request, new Response()); + + $this->assertNull($basic->getCredentials()); + + } + + function testRequireLogin() { + + $response = new Response(); + $basic = new Basic('Dagger', new Request(), $response); + + $basic->requireLogin(); + + $this->assertEquals('Basic realm="Dagger", charset="UTF-8"', $response->getHeader('WWW-Authenticate')); + $this->assertEquals(401, $response->getStatus()); + + } + +} diff --git a/vendor/sabre/http/tests/HTTP/Auth/BearerTest.php b/vendor/sabre/http/tests/HTTP/Auth/BearerTest.php new file mode 100644 index 000000000..ee2e9e0bd --- /dev/null +++ b/vendor/sabre/http/tests/HTTP/Auth/BearerTest.php @@ -0,0 +1,57 @@ +<?php + +namespace Sabre\HTTP\Auth; + +use Sabre\HTTP\Request; +use Sabre\HTTP\Response; + +class BearerTest extends \PHPUnit_Framework_TestCase { + + function testGetToken() { + + $request = new Request('GET', '/', [ + 'Authorization' => 'Bearer 12345' + ]); + + $bearer = new Bearer('Dagger', $request, new Response()); + + $this->assertEquals( + '12345', + $bearer->getToken() + ); + + } + + function testGetCredentialsNoheader() { + + $request = new Request('GET', '/', []); + $bearer = new Bearer('Dagger', $request, new Response()); + + $this->assertNull($bearer->getToken()); + + } + + function testGetCredentialsNotBearer() { + + $request = new Request('GET', '/', [ + 'Authorization' => 'QBearer 12345' + ]); + $bearer = new Bearer('Dagger', $request, new Response()); + + $this->assertNull($bearer->getToken()); + + } + + function testRequireLogin() { + + $response = new Response(); + $bearer = new Bearer('Dagger', new Request(), $response); + + $bearer->requireLogin(); + + $this->assertEquals('Bearer realm="Dagger"', $response->getHeader('WWW-Authenticate')); + $this->assertEquals(401, $response->getStatus()); + + } + +} diff --git a/vendor/sabre/http/tests/HTTP/Auth/DigestTest.php b/vendor/sabre/http/tests/HTTP/Auth/DigestTest.php new file mode 100644 index 000000000..ffb69c76d --- /dev/null +++ b/vendor/sabre/http/tests/HTTP/Auth/DigestTest.php @@ -0,0 +1,191 @@ +<?php + +namespace Sabre\HTTP\Auth; + +use Sabre\HTTP\Request; +use Sabre\HTTP\Response; + +class DigestTest extends \PHPUnit_Framework_TestCase { + + /** + * @var Sabre\HTTP\Response + */ + private $response; + + /** + * request + * + * @var Sabre\HTTP\Request + */ + private $request; + + /** + * @var Sabre\HTTP\Auth\Digest + */ + private $auth; + + const REALM = 'SabreDAV unittest'; + + function setUp() { + + $this->response = new Response(); + $this->request = new Request(); + $this->auth = new Digest(self::REALM, $this->request, $this->response); + + + } + + function testDigest() { + + list($nonce, $opaque) = $this->getServerTokens(); + + $username = 'admin'; + $password = 12345; + $nc = '00002'; + $cnonce = uniqid(); + + $digestHash = md5( + md5($username . ':' . self::REALM . ':' . $password) . ':' . + $nonce . ':' . + $nc . ':' . + $cnonce . ':' . + 'auth:' . + md5('GET' . ':' . '/') + ); + + $this->request->setMethod('GET'); + $this->request->setHeader('Authorization', 'Digest username="' . $username . '", realm="' . self::REALM . '", nonce="' . $nonce . '", uri="/", response="' . $digestHash . '", opaque="' . $opaque . '", qop=auth,nc=' . $nc . ',cnonce="' . $cnonce . '"'); + + $this->auth->init(); + + $this->assertEquals($username, $this->auth->getUsername()); + $this->assertEquals(self::REALM, $this->auth->getRealm()); + $this->assertTrue($this->auth->validateA1(md5($username . ':' . self::REALM . ':' . $password)), 'Authentication is deemed invalid through validateA1'); + $this->assertTrue($this->auth->validatePassword($password), 'Authentication is deemed invalid through validatePassword'); + + } + + function testInvalidDigest() { + + list($nonce, $opaque) = $this->getServerTokens(); + + $username = 'admin'; + $password = 12345; + $nc = '00002'; + $cnonce = uniqid(); + + $digestHash = md5( + md5($username . ':' . self::REALM . ':' . $password) . ':' . + $nonce . ':' . + $nc . ':' . + $cnonce . ':' . + 'auth:' . + md5('GET' . ':' . '/') + ); + + $this->request->setMethod('GET'); + $this->request->setHeader('Authorization', 'Digest username="' . $username . '", realm="' . self::REALM . '", nonce="' . $nonce . '", uri="/", response="' . $digestHash . '", opaque="' . $opaque . '", qop=auth,nc=' . $nc . ',cnonce="' . $cnonce . '"'); + + $this->auth->init(); + + $this->assertFalse($this->auth->validateA1(md5($username . ':' . self::REALM . ':' . ($password . 'randomness'))), 'Authentication is deemed invalid through validateA1'); + + } + + function testInvalidDigest2() { + + $this->request->setMethod('GET'); + $this->request->setHeader('Authorization', 'basic blablabla'); + + $this->auth->init(); + $this->assertFalse($this->auth->validateA1(md5('user:realm:password'))); + + } + + + function testDigestAuthInt() { + + $this->auth->setQOP(Digest::QOP_AUTHINT); + list($nonce, $opaque) = $this->getServerTokens(Digest::QOP_AUTHINT); + + $username = 'admin'; + $password = 12345; + $nc = '00003'; + $cnonce = uniqid(); + + $digestHash = md5( + md5($username . ':' . self::REALM . ':' . $password) . ':' . + $nonce . ':' . + $nc . ':' . + $cnonce . ':' . + 'auth-int:' . + md5('POST' . ':' . '/' . ':' . md5('body')) + ); + + $this->request->setMethod('POST'); + $this->request->setHeader('Authorization', 'Digest username="' . $username . '", realm="' . self::REALM . '", nonce="' . $nonce . '", uri="/", response="' . $digestHash . '", opaque="' . $opaque . '", qop=auth-int,nc=' . $nc . ',cnonce="' . $cnonce . '"'); + $this->request->setBody('body'); + + $this->auth->init(); + + $this->assertTrue($this->auth->validateA1(md5($username . ':' . self::REALM . ':' . $password)), 'Authentication is deemed invalid through validateA1'); + + } + + function testDigestAuthBoth() { + + $this->auth->setQOP(Digest::QOP_AUTHINT | Digest::QOP_AUTH); + list($nonce, $opaque) = $this->getServerTokens(Digest::QOP_AUTHINT | Digest::QOP_AUTH); + + $username = 'admin'; + $password = 12345; + $nc = '00003'; + $cnonce = uniqid(); + + $digestHash = md5( + md5($username . ':' . self::REALM . ':' . $password) . ':' . + $nonce . ':' . + $nc . ':' . + $cnonce . ':' . + 'auth-int:' . + md5('POST' . ':' . '/' . ':' . md5('body')) + ); + + $this->request->setMethod('POST'); + $this->request->setHeader('Authorization', 'Digest username="' . $username . '", realm="' . self::REALM . '", nonce="' . $nonce . '", uri="/", response="' . $digestHash . '", opaque="' . $opaque . '", qop=auth-int,nc=' . $nc . ',cnonce="' . $cnonce . '"'); + $this->request->setBody('body'); + + $this->auth->init(); + + $this->assertTrue($this->auth->validateA1(md5($username . ':' . self::REALM . ':' . $password)), 'Authentication is deemed invalid through validateA1'); + + } + + + private function getServerTokens($qop = Digest::QOP_AUTH) { + + $this->auth->requireLogin(); + + switch ($qop) { + case Digest::QOP_AUTH : $qopstr = 'auth'; break; + case Digest::QOP_AUTHINT : $qopstr = 'auth-int'; break; + default : $qopstr = 'auth,auth-int'; break; + } + + $test = preg_match('/Digest realm="' . self::REALM . '",qop="' . $qopstr . '",nonce="([0-9a-f]*)",opaque="([0-9a-f]*)"/', + $this->response->getHeader('WWW-Authenticate'), $matches); + + $this->assertTrue($test == true, 'The WWW-Authenticate response didn\'t match our pattern. We received: ' . $this->response->getHeader('WWW-Authenticate')); + + $nonce = $matches[1]; + $opaque = $matches[2]; + + // Reset our environment + $this->setUp(); + $this->auth->setQOP($qop); + + return [$nonce,$opaque]; + + } + +} diff --git a/vendor/sabre/http/tests/HTTP/ClientTest.php b/vendor/sabre/http/tests/HTTP/ClientTest.php new file mode 100644 index 000000000..ea25907df --- /dev/null +++ b/vendor/sabre/http/tests/HTTP/ClientTest.php @@ -0,0 +1,474 @@ +<?php + +namespace Sabre\HTTP; + +class ClientTest extends \PHPUnit_Framework_TestCase { + + function testCreateCurlSettingsArrayGET() { + + $client = new ClientMock(); + $client->addCurlSetting(CURLOPT_POSTREDIR, 0); + + $request = new Request('GET', 'http://example.org/', ['X-Foo' => 'bar']); + + $settings = [ + CURLOPT_RETURNTRANSFER => true, + CURLOPT_HEADER => true, + CURLOPT_POSTREDIR => 0, + CURLOPT_HTTPHEADER => ['X-Foo: bar'], + CURLOPT_NOBODY => false, + CURLOPT_URL => 'http://example.org/', + CURLOPT_CUSTOMREQUEST => 'GET', + CURLOPT_POSTFIELDS => '', + CURLOPT_PUT => false, + CURLOPT_USERAGENT => 'sabre-http/' . Version::VERSION . ' (http://sabre.io/)', + ]; + + // FIXME: CURLOPT_PROTOCOLS and CURLOPT_REDIR_PROTOCOLS are currently unsupported by HHVM + // at least if this unit test fails in the future we know it is :) + if (defined('HHVM_VERSION') === false) { + $settings[CURLOPT_PROTOCOLS] = CURLPROTO_HTTP | CURLPROTO_HTTPS; + $settings[CURLOPT_REDIR_PROTOCOLS] = CURLPROTO_HTTP | CURLPROTO_HTTPS; + } + + + $this->assertEquals($settings, $client->createCurlSettingsArray($request)); + + } + + function testCreateCurlSettingsArrayHEAD() { + + $client = new ClientMock(); + $request = new Request('HEAD', 'http://example.org/', ['X-Foo' => 'bar']); + + + $settings = [ + CURLOPT_RETURNTRANSFER => true, + CURLOPT_HEADER => true, + CURLOPT_NOBODY => true, + CURLOPT_CUSTOMREQUEST => 'HEAD', + CURLOPT_HTTPHEADER => ['X-Foo: bar'], + CURLOPT_URL => 'http://example.org/', + CURLOPT_POSTFIELDS => '', + CURLOPT_PUT => false, + CURLOPT_USERAGENT => 'sabre-http/' . Version::VERSION . ' (http://sabre.io/)', + ]; + + // FIXME: CURLOPT_PROTOCOLS and CURLOPT_REDIR_PROTOCOLS are currently unsupported by HHVM + // at least if this unit test fails in the future we know it is :) + if (defined('HHVM_VERSION') === false) { + $settings[CURLOPT_PROTOCOLS] = CURLPROTO_HTTP | CURLPROTO_HTTPS; + $settings[CURLOPT_REDIR_PROTOCOLS] = CURLPROTO_HTTP | CURLPROTO_HTTPS; + } + + $this->assertEquals($settings, $client->createCurlSettingsArray($request)); + + } + + function testCreateCurlSettingsArrayGETAfterHEAD() { + + $client = new ClientMock(); + $request = new Request('HEAD', 'http://example.org/', ['X-Foo' => 'bar']); + + // Parsing the settings for this method, and discarding the result. + // This will cause the client to automatically persist previous + // settings and will help us detect problems. + $client->createCurlSettingsArray($request); + + // This is the real request. + $request = new Request('GET', 'http://example.org/', ['X-Foo' => 'bar']); + + $settings = [ + CURLOPT_CUSTOMREQUEST => 'GET', + CURLOPT_RETURNTRANSFER => true, + CURLOPT_HEADER => true, + CURLOPT_HTTPHEADER => ['X-Foo: bar'], + CURLOPT_NOBODY => false, + CURLOPT_URL => 'http://example.org/', + CURLOPT_POSTFIELDS => '', + CURLOPT_PUT => false, + CURLOPT_USERAGENT => 'sabre-http/' . Version::VERSION . ' (http://sabre.io/)', + ]; + + // FIXME: CURLOPT_PROTOCOLS and CURLOPT_REDIR_PROTOCOLS are currently unsupported by HHVM + // at least if this unit test fails in the future we know it is :) + if (defined('HHVM_VERSION') === false) { + $settings[CURLOPT_PROTOCOLS] = CURLPROTO_HTTP | CURLPROTO_HTTPS; + $settings[CURLOPT_REDIR_PROTOCOLS] = CURLPROTO_HTTP | CURLPROTO_HTTPS; + } + + $this->assertEquals($settings, $client->createCurlSettingsArray($request)); + + } + + function testCreateCurlSettingsArrayPUTStream() { + + $client = new ClientMock(); + + $h = fopen('php://memory', 'r+'); + fwrite($h, 'booh'); + $request = new Request('PUT', 'http://example.org/', ['X-Foo' => 'bar'], $h); + + $settings = [ + CURLOPT_RETURNTRANSFER => true, + CURLOPT_HEADER => true, + CURLOPT_PUT => true, + CURLOPT_INFILE => $h, + CURLOPT_NOBODY => false, + CURLOPT_CUSTOMREQUEST => 'PUT', + CURLOPT_HTTPHEADER => ['X-Foo: bar'], + CURLOPT_URL => 'http://example.org/', + CURLOPT_USERAGENT => 'sabre-http/' . Version::VERSION . ' (http://sabre.io/)', + ]; + + // FIXME: CURLOPT_PROTOCOLS and CURLOPT_REDIR_PROTOCOLS are currently unsupported by HHVM + // at least if this unit test fails in the future we know it is :) + if (defined('HHVM_VERSION') === false) { + $settings[CURLOPT_PROTOCOLS] = CURLPROTO_HTTP | CURLPROTO_HTTPS; + $settings[CURLOPT_REDIR_PROTOCOLS] = CURLPROTO_HTTP | CURLPROTO_HTTPS; + } + + $this->assertEquals($settings, $client->createCurlSettingsArray($request)); + + } + + function testCreateCurlSettingsArrayPUTString() { + + $client = new ClientMock(); + $request = new Request('PUT', 'http://example.org/', ['X-Foo' => 'bar'], 'boo'); + + $settings = [ + CURLOPT_RETURNTRANSFER => true, + CURLOPT_HEADER => true, + CURLOPT_NOBODY => false, + CURLOPT_POSTFIELDS => 'boo', + CURLOPT_CUSTOMREQUEST => 'PUT', + CURLOPT_HTTPHEADER => ['X-Foo: bar'], + CURLOPT_URL => 'http://example.org/', + CURLOPT_USERAGENT => 'sabre-http/' . Version::VERSION . ' (http://sabre.io/)', + ]; + + // FIXME: CURLOPT_PROTOCOLS and CURLOPT_REDIR_PROTOCOLS are currently unsupported by HHVM + // at least if this unit test fails in the future we know it is :) + if (defined('HHVM_VERSION') === false) { + $settings[CURLOPT_PROTOCOLS] = CURLPROTO_HTTP | CURLPROTO_HTTPS; + $settings[CURLOPT_REDIR_PROTOCOLS] = CURLPROTO_HTTP | CURLPROTO_HTTPS; + } + + $this->assertEquals($settings, $client->createCurlSettingsArray($request)); + + } + + function testSend() { + + $client = new ClientMock(); + $request = new Request('GET', 'http://example.org/'); + + $client->on('doRequest', function($request, &$response) { + $response = new Response(200); + }); + + $response = $client->send($request); + + $this->assertEquals(200, $response->getStatus()); + + } + + function testSendClientError() { + + $client = new ClientMock(); + $request = new Request('GET', 'http://example.org/'); + + $client->on('doRequest', function($request, &$response) { + throw new ClientException('aaah', 1); + }); + $called = false; + $client->on('exception', function() use (&$called) { + $called = true; + }); + + try { + $client->send($request); + $this->fail('send() should have thrown an exception'); + } catch (ClientException $e) { + + } + $this->assertTrue($called); + + } + + function testSendHttpError() { + + $client = new ClientMock(); + $request = new Request('GET', 'http://example.org/'); + + $client->on('doRequest', function($request, &$response) { + $response = new Response(404); + }); + $called = 0; + $client->on('error', function() use (&$called) { + $called++; + }); + $client->on('error:404', function() use (&$called) { + $called++; + }); + + $client->send($request); + $this->assertEquals(2, $called); + + } + + function testSendRetry() { + + $client = new ClientMock(); + $request = new Request('GET', 'http://example.org/'); + + $called = 0; + $client->on('doRequest', function($request, &$response) use (&$called) { + $called++; + if ($called < 3) { + $response = new Response(404); + } else { + $response = new Response(200); + } + }); + + $errorCalled = 0; + $client->on('error', function($request, $response, &$retry, $retryCount) use (&$errorCalled) { + + $errorCalled++; + $retry = true; + + }); + + $response = $client->send($request); + $this->assertEquals(3, $called); + $this->assertEquals(2, $errorCalled); + $this->assertEquals(200, $response->getStatus()); + + } + + function testHttpErrorException() { + + $client = new ClientMock(); + $client->setThrowExceptions(true); + $request = new Request('GET', 'http://example.org/'); + + $client->on('doRequest', function($request, &$response) { + $response = new Response(404); + }); + + try { + $client->send($request); + $this->fail('An exception should have been thrown'); + } catch (ClientHttpException $e) { + $this->assertEquals(404, $e->getHttpStatus()); + $this->assertInstanceOf('Sabre\HTTP\Response', $e->getResponse()); + } + + } + + function testParseCurlResult() { + + $client = new ClientMock(); + $client->on('curlStuff', function(&$return) { + + $return = [ + [ + 'header_size' => 33, + 'http_code' => 200, + ], + 0, + '', + ]; + + }); + + $body = "HTTP/1.1 200 OK\r\nHeader1:Val1\r\n\r\nFoo"; + $result = $client->parseCurlResult($body, 'foobar'); + + $this->assertEquals(Client::STATUS_SUCCESS, $result['status']); + $this->assertEquals(200, $result['http_code']); + $this->assertEquals(200, $result['response']->getStatus()); + $this->assertEquals(['Header1' => ['Val1']], $result['response']->getHeaders()); + $this->assertEquals('Foo', $result['response']->getBodyAsString()); + + } + + function testParseCurlError() { + + $client = new ClientMock(); + $client->on('curlStuff', function(&$return) { + + $return = [ + [], + 1, + 'Curl error', + ]; + + }); + + $body = "HTTP/1.1 200 OK\r\nHeader1:Val1\r\n\r\nFoo"; + $result = $client->parseCurlResult($body, 'foobar'); + + $this->assertEquals(Client::STATUS_CURLERROR, $result['status']); + $this->assertEquals(1, $result['curl_errno']); + $this->assertEquals('Curl error', $result['curl_errmsg']); + + } + + function testDoRequest() { + + $client = new ClientMock(); + $request = new Request('GET', 'http://example.org/'); + $client->on('curlExec', function(&$return) { + + $return = "HTTP/1.1 200 OK\r\nHeader1:Val1\r\n\r\nFoo"; + + }); + $client->on('curlStuff', function(&$return) { + + $return = [ + [ + 'header_size' => 33, + 'http_code' => 200, + ], + 0, + '', + ]; + + }); + $response = $client->doRequest($request); + $this->assertEquals(200, $response->getStatus()); + $this->assertEquals(['Header1' => ['Val1']], $response->getHeaders()); + $this->assertEquals('Foo', $response->getBodyAsString()); + + } + + function testDoRequestCurlError() { + + $client = new ClientMock(); + $request = new Request('GET', 'http://example.org/'); + $client->on('curlExec', function(&$return) { + + $return = ""; + + }); + $client->on('curlStuff', function(&$return) { + + $return = [ + [], + 1, + 'Curl error', + ]; + + }); + + try { + $response = $client->doRequest($request); + $this->fail('This should have thrown an exception'); + } catch (ClientException $e) { + $this->assertEquals(1, $e->getCode()); + $this->assertEquals('Curl error', $e->getMessage()); + } + + } + +} + +class ClientMock extends Client { + + protected $persistedSettings = []; + + /** + * Making this method public. + * + * We are also going to persist all settings this method generates. While + * the underlying object doesn't behave exactly the same, it helps us + * simulate what curl does internally, and helps us identify problems with + * settings that are set by _some_ methods and not correctly reset by other + * methods after subsequent use. + * forces + */ + function createCurlSettingsArray(RequestInterface $request) { + + $settings = parent::createCurlSettingsArray($request); + $settings = $settings + $this->persistedSettings; + $this->persistedSettings = $settings; + return $settings; + + } + /** + * Making this method public. + */ + function parseCurlResult($response, $curlHandle) { + + return parent::parseCurlResult($response, $curlHandle); + + } + + /** + * This method is responsible for performing a single request. + * + * @param RequestInterface $request + * @return ResponseInterface + */ + function doRequest(RequestInterface $request) { + + $response = null; + $this->emit('doRequest', [$request, &$response]); + + // If nothing modified $response, we're using the default behavior. + if (is_null($response)) { + return parent::doRequest($request); + } else { + return $response; + } + + } + + /** + * Returns a bunch of information about a curl request. + * + * This method exists so it can easily be overridden and mocked. + * + * @param resource $curlHandle + * @return array + */ + protected function curlStuff($curlHandle) { + + $return = null; + $this->emit('curlStuff', [&$return]); + + // If nothing modified $return, we're using the default behavior. + if (is_null($return)) { + return parent::curlStuff($curlHandle); + } else { + return $return; + } + + } + + /** + * Calls curl_exec + * + * This method exists so it can easily be overridden and mocked. + * + * @param resource $curlHandle + * @return string + */ + protected function curlExec($curlHandle) { + + $return = null; + $this->emit('curlExec', [&$return]); + + // If nothing modified $return, we're using the default behavior. + if (is_null($return)) { + return parent::curlExec($curlHandle); + } else { + return $return; + } + + } + +} diff --git a/vendor/sabre/http/tests/HTTP/FunctionsTest.php b/vendor/sabre/http/tests/HTTP/FunctionsTest.php new file mode 100644 index 000000000..a107d1f00 --- /dev/null +++ b/vendor/sabre/http/tests/HTTP/FunctionsTest.php @@ -0,0 +1,121 @@ +<?php + +namespace Sabre\HTTP; + +class FunctionsTest extends \PHPUnit_Framework_TestCase { + + /** + * @dataProvider getHeaderValuesData + */ + function testGetHeaderValues($input, $output) { + + $this->assertEquals( + $output, + getHeaderValues($input) + ); + + } + + function getHeaderValuesData() { + + return [ + [ + "a", + ["a"] + ], + [ + "a,b", + ["a", "b"] + ], + [ + "a, b", + ["a", "b"] + ], + [ + ["a, b"], + ["a", "b"] + ], + [ + ["a, b", "c", "d,e"], + ["a", "b", "c", "d", "e"] + ], + ]; + + } + + /** + * @dataProvider preferData + */ + function testPrefer($input, $output) { + + $this->assertEquals( + $output, + parsePrefer($input) + ); + + } + + function preferData() { + + return [ + [ + 'foo; bar', + ['foo' => true] + ], + [ + 'foo; bar=""', + ['foo' => true] + ], + [ + 'foo=""; bar', + ['foo' => true] + ], + [ + 'FOO', + ['foo' => true] + ], + [ + 'respond-async', + ['respond-async' => true] + ], + [ + + ['respond-async, wait=100', 'handling=lenient'], + ['respond-async' => true, 'wait' => 100, 'handling' => 'lenient'] + ], + [ + + ['respond-async, wait=100, handling=lenient'], + ['respond-async' => true, 'wait' => 100, 'handling' => 'lenient'] + ], + // Old values + [ + + 'return-asynch, return-representation', + ['respond-async' => true, 'return' => 'representation'], + ], + [ + + 'return-minimal', + ['return' => 'minimal'], + ], + [ + + 'strict', + ['handling' => 'strict'], + ], + [ + + 'lenient', + ['handling' => 'lenient'], + ], + // Invalid token + [ + ['foo=%bar%'], + [], + ] + ]; + + } + +} diff --git a/vendor/sabre/http/tests/HTTP/MessageDecoratorTest.php b/vendor/sabre/http/tests/HTTP/MessageDecoratorTest.php new file mode 100644 index 000000000..a4052c60c --- /dev/null +++ b/vendor/sabre/http/tests/HTTP/MessageDecoratorTest.php @@ -0,0 +1,93 @@ +<?php + +namespace Sabre\HTTP; + +class MessageDecoratorTest extends \PHPUnit_Framework_TestCase { + + protected $inner; + protected $outer; + + function setUp() { + + $this->inner = new Request(); + $this->outer = new RequestDecorator($this->inner); + + } + + function testBody() { + + $this->outer->setBody('foo'); + $this->assertEquals('foo', stream_get_contents($this->inner->getBodyAsStream())); + $this->assertEquals('foo', stream_get_contents($this->outer->getBodyAsStream())); + $this->assertEquals('foo', $this->inner->getBodyAsString()); + $this->assertEquals('foo', $this->outer->getBodyAsString()); + $this->assertEquals('foo', $this->inner->getBody()); + $this->assertEquals('foo', $this->outer->getBody()); + + } + + function testHeaders() { + + $this->outer->setHeaders([ + 'a' => 'b', + ]); + + $this->assertEquals(['a' => ['b']], $this->inner->getHeaders()); + $this->assertEquals(['a' => ['b']], $this->outer->getHeaders()); + + $this->outer->setHeaders([ + 'c' => 'd', + ]); + + $this->assertEquals(['a' => ['b'], 'c' => ['d']], $this->inner->getHeaders()); + $this->assertEquals(['a' => ['b'], 'c' => ['d']], $this->outer->getHeaders()); + + $this->outer->addHeaders([ + 'e' => 'f', + ]); + + $this->assertEquals(['a' => ['b'], 'c' => ['d'], 'e' => ['f']], $this->inner->getHeaders()); + $this->assertEquals(['a' => ['b'], 'c' => ['d'], 'e' => ['f']], $this->outer->getHeaders()); + } + + function testHeader() { + + $this->assertFalse($this->outer->hasHeader('a')); + $this->assertFalse($this->inner->hasHeader('a')); + $this->outer->setHeader('a', 'c'); + $this->assertTrue($this->outer->hasHeader('a')); + $this->assertTrue($this->inner->hasHeader('a')); + + $this->assertEquals('c', $this->inner->getHeader('A')); + $this->assertEquals('c', $this->outer->getHeader('A')); + + $this->outer->addHeader('A', 'd'); + + $this->assertEquals( + ['c', 'd'], + $this->inner->getHeaderAsArray('A') + ); + $this->assertEquals( + ['c', 'd'], + $this->outer->getHeaderAsArray('A') + ); + + $success = $this->outer->removeHeader('a'); + + $this->assertTrue($success); + $this->assertNull($this->inner->getHeader('A')); + $this->assertNull($this->outer->getHeader('A')); + + $this->assertFalse($this->outer->removeHeader('i-dont-exist')); + } + + function testHttpVersion() { + + $this->outer->setHttpVersion('1.0'); + + $this->assertEquals('1.0', $this->inner->getHttpVersion()); + $this->assertEquals('1.0', $this->outer->getHttpVersion()); + + } + +} diff --git a/vendor/sabre/http/tests/HTTP/MessageTest.php b/vendor/sabre/http/tests/HTTP/MessageTest.php new file mode 100644 index 000000000..cb5aadc41 --- /dev/null +++ b/vendor/sabre/http/tests/HTTP/MessageTest.php @@ -0,0 +1,246 @@ +<?php + +namespace Sabre\HTTP; + +class MessageTest extends \PHPUnit_Framework_TestCase { + + function testConstruct() { + + $message = new MessageMock(); + $this->assertInstanceOf('Sabre\HTTP\Message', $message); + + } + + function testStreamBody() { + + $body = 'foo'; + $h = fopen('php://memory', 'r+'); + fwrite($h, $body); + rewind($h); + + $message = new MessageMock(); + $message->setBody($h); + + $this->assertEquals($body, $message->getBodyAsString()); + rewind($h); + $this->assertEquals($body, stream_get_contents($message->getBodyAsStream())); + rewind($h); + $this->assertEquals($body, stream_get_contents($message->getBody())); + + } + + function testStringBody() { + + $body = 'foo'; + + $message = new MessageMock(); + $message->setBody($body); + + $this->assertEquals($body, $message->getBodyAsString()); + $this->assertEquals($body, stream_get_contents($message->getBodyAsStream())); + $this->assertEquals($body, $message->getBody()); + + } + + /** + * It's possible that streams contains more data than the Content-Length. + * + * The request object should make sure to never emit more than + * Content-Length, if Content-Length is set. + * + * This is in particular useful when respoding to range requests with + * streams that represent files on the filesystem, as it's possible to just + * seek the stream to a certain point, set the content-length and let the + * request object do the rest. + */ + function testLongStreamToStringBody() { + + $body = fopen('php://memory', 'r+'); + fwrite($body, 'abcdefg'); + fseek($body, 2); + + $message = new MessageMock(); + $message->setBody($body); + $message->setHeader('Content-Length', '4'); + + $this->assertEquals( + 'cdef', + $message->getBodyAsString() + ); + + } + + /** + * Some clients include a content-length header, but the header is empty. + * This is definitely broken behavior, but we should support it. + */ + function testEmptyContentLengthHeader() { + + $body = fopen('php://memory', 'r+'); + fwrite($body, 'abcdefg'); + fseek($body, 2); + + $message = new MessageMock(); + $message->setBody($body); + $message->setHeader('Content-Length', ''); + + $this->assertEquals( + 'cdefg', + $message->getBodyAsString() + ); + + } + + + function testGetEmptyBodyStream() { + + $message = new MessageMock(); + $body = $message->getBodyAsStream(); + + $this->assertEquals('', stream_get_contents($body)); + + } + + function testGetEmptyBodyString() { + + $message = new MessageMock(); + $body = $message->getBodyAsString(); + + $this->assertEquals('', $body); + + } + + function testHeaders() { + + $message = new MessageMock(); + $message->setHeader('X-Foo', 'bar'); + + // Testing caselessness + $this->assertEquals('bar', $message->getHeader('X-Foo')); + $this->assertEquals('bar', $message->getHeader('x-fOO')); + + $this->assertTrue( + $message->removeHeader('X-FOO') + ); + $this->assertNull($message->getHeader('X-Foo')); + $this->assertFalse( + $message->removeHeader('X-FOO') + ); + + } + + function testSetHeaders() { + + $message = new MessageMock(); + + $headers = [ + 'X-Foo' => ['1'], + 'X-Bar' => ['2'], + ]; + + $message->setHeaders($headers); + $this->assertEquals($headers, $message->getHeaders()); + + $message->setHeaders([ + 'X-Foo' => ['3', '4'], + 'X-Bar' => '5', + ]); + + $expected = [ + 'X-Foo' => ['3','4'], + 'X-Bar' => ['5'], + ]; + + $this->assertEquals($expected, $message->getHeaders()); + + } + + function testAddHeaders() { + + $message = new MessageMock(); + + $headers = [ + 'X-Foo' => ['1'], + 'X-Bar' => ['2'], + ]; + + $message->addHeaders($headers); + $this->assertEquals($headers, $message->getHeaders()); + + $message->addHeaders([ + 'X-Foo' => ['3', '4'], + 'X-Bar' => '5', + ]); + + $expected = [ + 'X-Foo' => ['1','3','4'], + 'X-Bar' => ['2','5'], + ]; + + $this->assertEquals($expected, $message->getHeaders()); + + } + + function testSendBody() { + + $message = new MessageMock(); + + // String + $message->setBody('foo'); + + // Stream + $h = fopen('php://memory', 'r+'); + fwrite($h, 'bar'); + rewind($h); + $message->setBody($h); + + $body = $message->getBody(); + rewind($body); + + $this->assertEquals('bar', stream_get_contents($body)); + + } + + function testMultipleHeaders() { + + $message = new MessageMock(); + $message->setHeader('a', '1'); + $message->addHeader('A', '2'); + + $this->assertEquals( + "1,2", + $message->getHeader('A') + ); + $this->assertEquals( + "1,2", + $message->getHeader('a') + ); + + $this->assertEquals( + ['1', '2'], + $message->getHeaderAsArray('a') + ); + $this->assertEquals( + ['1', '2'], + $message->getHeaderAsArray('A') + ); + $this->assertEquals( + [], + $message->getHeaderAsArray('B') + ); + + } + + function testHasHeaders() { + + $message = new MessageMock(); + + $this->assertFalse($message->hasHeader('X-Foo')); + $message->setHeader('X-Foo', 'Bar'); + $this->assertTrue($message->hasHeader('X-Foo')); + + } + +} + +class MessageMock extends Message { } diff --git a/vendor/sabre/http/tests/HTTP/RequestDecoratorTest.php b/vendor/sabre/http/tests/HTTP/RequestDecoratorTest.php new file mode 100644 index 000000000..08af48749 --- /dev/null +++ b/vendor/sabre/http/tests/HTTP/RequestDecoratorTest.php @@ -0,0 +1,112 @@ +<?php + +namespace Sabre\HTTP; + +class RequestDecoratorTest extends \PHPUnit_Framework_TestCase { + + protected $inner; + protected $outer; + + function setUp() { + + $this->inner = new Request(); + $this->outer = new RequestDecorator($this->inner); + + } + + function testMethod() { + + $this->outer->setMethod('FOO'); + $this->assertEquals('FOO', $this->inner->getMethod()); + $this->assertEquals('FOO', $this->outer->getMethod()); + + } + + function testUrl() { + + $this->outer->setUrl('/foo'); + $this->assertEquals('/foo', $this->inner->getUrl()); + $this->assertEquals('/foo', $this->outer->getUrl()); + + } + + function testAbsoluteUrl() { + + $this->outer->setAbsoluteUrl('http://example.org/foo'); + $this->assertEquals('http://example.org/foo', $this->inner->getAbsoluteUrl()); + $this->assertEquals('http://example.org/foo', $this->outer->getAbsoluteUrl()); + + } + + function testBaseUrl() { + + $this->outer->setBaseUrl('/foo'); + $this->assertEquals('/foo', $this->inner->getBaseUrl()); + $this->assertEquals('/foo', $this->outer->getBaseUrl()); + + } + + function testPath() { + + $this->outer->setBaseUrl('/foo'); + $this->outer->setUrl('/foo/bar'); + $this->assertEquals('bar', $this->inner->getPath()); + $this->assertEquals('bar', $this->outer->getPath()); + + } + + function testQueryParams() { + + $this->outer->setUrl('/foo?a=b&c=d&e'); + $expected = [ + 'a' => 'b', + 'c' => 'd', + 'e' => null, + ]; + + $this->assertEquals($expected, $this->inner->getQueryParameters()); + $this->assertEquals($expected, $this->outer->getQueryParameters()); + + } + + function testPostData() { + + $postData = [ + 'a' => 'b', + 'c' => 'd', + 'e' => null, + ]; + + $this->outer->setPostData($postData); + $this->assertEquals($postData, $this->inner->getPostData()); + $this->assertEquals($postData, $this->outer->getPostData()); + + } + + + function testServerData() { + + $serverData = [ + 'HTTPS' => 'On', + ]; + + $this->outer->setRawServerData($serverData); + $this->assertEquals('On', $this->inner->getRawServerValue('HTTPS')); + $this->assertEquals('On', $this->outer->getRawServerValue('HTTPS')); + + $this->assertNull($this->inner->getRawServerValue('FOO')); + $this->assertNull($this->outer->getRawServerValue('FOO')); + } + + function testToString() { + + $this->inner->setMethod('POST'); + $this->inner->setUrl('/foo/bar/'); + $this->inner->setBody('foo'); + $this->inner->setHeader('foo', 'bar'); + + $this->assertEquals((string)$this->inner, (string)$this->outer); + + } + +} diff --git a/vendor/sabre/http/tests/HTTP/RequestTest.php b/vendor/sabre/http/tests/HTTP/RequestTest.php new file mode 100644 index 000000000..e3daab4d3 --- /dev/null +++ b/vendor/sabre/http/tests/HTTP/RequestTest.php @@ -0,0 +1,167 @@ +<?php + +namespace Sabre\HTTP; + +class RequestTest extends \PHPUnit_Framework_TestCase { + + function testConstruct() { + + $request = new Request('GET', '/foo', [ + 'User-Agent' => 'Evert', + ]); + $this->assertEquals('GET', $request->getMethod()); + $this->assertEquals('/foo', $request->getUrl()); + $this->assertEquals([ + 'User-Agent' => ['Evert'], + ], $request->getHeaders()); + + } + + function testGetQueryParameters() { + + $request = new Request('GET', '/foo?a=b&c&d=e'); + $this->assertEquals([ + 'a' => 'b', + 'c' => null, + 'd' => 'e', + ], $request->getQueryParameters()); + + } + + function testGetQueryParametersNoData() { + + $request = new Request('GET', '/foo'); + $this->assertEquals([], $request->getQueryParameters()); + + } + + /** + * @backupGlobals + */ + function testCreateFromPHPRequest() { + + $_SERVER['REQUEST_METHOD'] = 'PUT'; + + $request = Sapi::getRequest(); + $this->assertEquals('PUT', $request->getMethod()); + + } + + function testGetAbsoluteUrl() { + + $s = [ + 'HTTP_HOST' => 'sabredav.org', + 'REQUEST_URI' => '/foo' + ]; + + $r = Sapi::createFromServerArray($s); + + $this->assertEquals('http://sabredav.org/foo', $r->getAbsoluteUrl()); + + $s = [ + 'HTTP_HOST' => 'sabredav.org', + 'REQUEST_URI' => '/foo', + 'HTTPS' => 'on', + ]; + + $r = Sapi::createFromServerArray($s); + + $this->assertEquals('https://sabredav.org/foo', $r->getAbsoluteUrl()); + + } + + function testGetPostData() { + + $post = [ + 'bla' => 'foo', + ]; + $r = new Request(); + $r->setPostData($post); + $this->assertEquals($post, $r->getPostData()); + + } + + function testGetPath() { + + $request = new Request(); + $request->setBaseUrl('/foo'); + $request->setUrl('/foo/bar/'); + + $this->assertEquals('bar', $request->getPath()); + + } + + function testGetPathStrippedQuery() { + + $request = new Request(); + $request->setBaseUrl('/foo'); + $request->setUrl('/foo/bar/?a=b'); + + $this->assertEquals('bar', $request->getPath()); + + } + + function testGetPathMissingSlash() { + + $request = new Request(); + $request->setBaseUrl('/foo/'); + $request->setUrl('/foo'); + + $this->assertEquals('', $request->getPath()); + + } + + /** + * @expectedException \LogicException + */ + function testGetPathOutsideBaseUrl() { + + $request = new Request(); + $request->setBaseUrl('/foo/'); + $request->setUrl('/bar/'); + + $request->getPath(); + + } + + function testToString() { + + $request = new Request('PUT', '/foo/bar', ['Content-Type' => 'text/xml']); + $request->setBody('foo'); + + $expected = <<<HI +PUT /foo/bar HTTP/1.1\r +Content-Type: text/xml\r +\r +foo +HI; + $this->assertEquals($expected, (string)$request); + + } + + function testToStringAuthorization() { + + $request = new Request('PUT', '/foo/bar', ['Content-Type' => 'text/xml', 'Authorization' => 'Basic foobar']); + $request->setBody('foo'); + + $expected = <<<HI +PUT /foo/bar HTTP/1.1\r +Content-Type: text/xml\r +Authorization: Basic REDACTED\r +\r +foo +HI; + $this->assertEquals($expected, (string)$request); + + } + + /** + * @expectedException \InvalidArgumentException + */ + function testConstructorWithArray() { + + $request = new Request([]); + + } + +} diff --git a/vendor/sabre/http/tests/HTTP/ResponseDecoratorTest.php b/vendor/sabre/http/tests/HTTP/ResponseDecoratorTest.php new file mode 100644 index 000000000..838953b31 --- /dev/null +++ b/vendor/sabre/http/tests/HTTP/ResponseDecoratorTest.php @@ -0,0 +1,37 @@ +<?php + +namespace Sabre\HTTP; + +class ResponseDecoratorTest extends \PHPUnit_Framework_TestCase { + + protected $inner; + protected $outer; + + function setUp() { + + $this->inner = new Response(); + $this->outer = new ResponseDecorator($this->inner); + + } + + function testStatus() { + + $this->outer->setStatus(201); + $this->assertEquals(201, $this->inner->getStatus()); + $this->assertEquals(201, $this->outer->getStatus()); + $this->assertEquals('Created', $this->inner->getStatusText()); + $this->assertEquals('Created', $this->outer->getStatusText()); + + } + + function testToString() { + + $this->inner->setStatus(201); + $this->inner->setBody('foo'); + $this->inner->setHeader('foo', 'bar'); + + $this->assertEquals((string)$this->inner, (string)$this->outer); + + } + +} diff --git a/vendor/sabre/http/tests/HTTP/ResponseTest.php b/vendor/sabre/http/tests/HTTP/ResponseTest.php new file mode 100644 index 000000000..117551bb9 --- /dev/null +++ b/vendor/sabre/http/tests/HTTP/ResponseTest.php @@ -0,0 +1,48 @@ +<?php + +namespace Sabre\HTTP; + +class ResponseTest extends \PHPUnit_Framework_TestCase { + + function testConstruct() { + + $response = new Response(200, ['Content-Type' => 'text/xml']); + $this->assertEquals(200, $response->getStatus()); + $this->assertEquals('OK', $response->getStatusText()); + + } + + function testSetStatus() { + + $response = new Response(); + $response->setStatus('402 Where\'s my money?'); + $this->assertEquals(402, $response->getStatus()); + $this->assertEquals('Where\'s my money?', $response->getStatusText()); + + } + + /** + * @expectedException InvalidArgumentException + */ + function testInvalidStatus() { + + $response = new Response(1000); + + } + + function testToString() { + + $response = new Response(200, ['Content-Type' => 'text/xml']); + $response->setBody('foo'); + + $expected = <<<HI +HTTP/1.1 200 OK\r +Content-Type: text/xml\r +\r +foo +HI; + $this->assertEquals($expected, (string)$response); + + } + +} diff --git a/vendor/sabre/http/tests/HTTP/SapiTest.php b/vendor/sabre/http/tests/HTTP/SapiTest.php new file mode 100644 index 000000000..158ce2171 --- /dev/null +++ b/vendor/sabre/http/tests/HTTP/SapiTest.php @@ -0,0 +1,167 @@ +<?php + +namespace Sabre\HTTP; + +class SapiTest extends \PHPUnit_Framework_TestCase { + + function testConstructFromServerArray() { + + $request = Sapi::createFromServerArray([ + 'REQUEST_URI' => '/foo', + 'REQUEST_METHOD' => 'GET', + 'HTTP_USER_AGENT' => 'Evert', + 'CONTENT_TYPE' => 'text/xml', + 'CONTENT_LENGTH' => '400', + 'SERVER_PROTOCOL' => 'HTTP/1.0', + ]); + + $this->assertEquals('GET', $request->getMethod()); + $this->assertEquals('/foo', $request->getUrl()); + $this->assertEquals([ + 'User-Agent' => ['Evert'], + 'Content-Type' => ['text/xml'], + 'Content-Length' => ['400'], + ], $request->getHeaders()); + + $this->assertEquals('1.0', $request->getHttpVersion()); + + $this->assertEquals('400', $request->getRawServerValue('CONTENT_LENGTH')); + $this->assertNull($request->getRawServerValue('FOO')); + + } + + function testConstructPHPAuth() { + + $request = Sapi::createFromServerArray([ + 'REQUEST_URI' => '/foo', + 'REQUEST_METHOD' => 'GET', + 'PHP_AUTH_USER' => 'user', + 'PHP_AUTH_PW' => 'pass', + ]); + + $this->assertEquals('GET', $request->getMethod()); + $this->assertEquals('/foo', $request->getUrl()); + $this->assertEquals([ + 'Authorization' => ['Basic ' . base64_encode('user:pass')], + ], $request->getHeaders()); + + } + + function testConstructPHPAuthDigest() { + + $request = Sapi::createFromServerArray([ + 'REQUEST_URI' => '/foo', + 'REQUEST_METHOD' => 'GET', + 'PHP_AUTH_DIGEST' => 'blabla', + ]); + + $this->assertEquals('GET', $request->getMethod()); + $this->assertEquals('/foo', $request->getUrl()); + $this->assertEquals([ + 'Authorization' => ['Digest blabla'], + ], $request->getHeaders()); + + } + + function testConstructRedirectAuth() { + + $request = Sapi::createFromServerArray([ + 'REQUEST_URI' => '/foo', + 'REQUEST_METHOD' => 'GET', + 'REDIRECT_HTTP_AUTHORIZATION' => 'Basic bla', + ]); + + $this->assertEquals('GET', $request->getMethod()); + $this->assertEquals('/foo', $request->getUrl()); + $this->assertEquals([ + 'Authorization' => ['Basic bla'], + ], $request->getHeaders()); + + } + + /** + * @runInSeparateProcess + * + * Unfortunately we have no way of testing if the HTTP response code got + * changed. + */ + function testSend() { + + if (!function_exists('xdebug_get_headers')) { + $this->markTestSkipped('XDebug needs to be installed for this test to run'); + } + + $response = new Response(204, ['Content-Type' => 'text/xml;charset=UTF-8']); + + // Second Content-Type header. Normally this doesn't make sense. + $response->addHeader('Content-Type', 'application/xml'); + $response->setBody('foo'); + + ob_start(); + + Sapi::sendResponse($response); + $headers = xdebug_get_headers(); + + $result = ob_get_clean(); + header_remove(); + + $this->assertEquals( + [ + "Content-Type: text/xml;charset=UTF-8", + "Content-Type: application/xml", + ], + $headers + ); + + $this->assertEquals('foo', $result); + + } + + /** + * @runInSeparateProcess + * @depends testSend + */ + function testSendLimitedByContentLengthString() { + + $response = new Response(200); + + $response->addHeader('Content-Length', 19); + $response->setBody('Send this sentence. Ignore this one.'); + + ob_start(); + + Sapi::sendResponse($response); + + $result = ob_get_clean(); + header_remove(); + + $this->assertEquals('Send this sentence.', $result); + + } + + /** + * @runInSeparateProcess + * @depends testSend + */ + function testSendLimitedByContentLengthStream() { + + $response = new Response(200, ['Content-Length' => 19]); + + $body = fopen('php://memory', 'w'); + fwrite($body, 'Ignore this. Send this sentence. Ignore this too.'); + rewind($body); + fread($body, 13); + $response->setBody($body); + + ob_start(); + + Sapi::sendResponse($response); + + $result = ob_get_clean(); + header_remove(); + + $this->assertEquals('Send this sentence.', $result); + + } + +} diff --git a/vendor/sabre/http/tests/HTTP/URLUtilTest.php b/vendor/sabre/http/tests/HTTP/URLUtilTest.php new file mode 100644 index 000000000..a2d65a5e3 --- /dev/null +++ b/vendor/sabre/http/tests/HTTP/URLUtilTest.php @@ -0,0 +1,187 @@ +<?php + +namespace Sabre\HTTP; + +class URLUtilTest extends \PHPUnit_Framework_TestCase{ + + function testEncodePath() { + + $str = ''; + for ($i = 0;$i < 128;$i++) $str .= chr($i); + + $newStr = URLUtil::encodePath($str); + + $this->assertEquals( + '%00%01%02%03%04%05%06%07%08%09%0a%0b%0c%0d%0e%0f' . + '%10%11%12%13%14%15%16%17%18%19%1a%1b%1c%1d%1e%1f' . + '%20%21%22%23%24%25%26%27()%2a%2b%2c-./' . + '0123456789:%3b%3c%3d%3e%3f' . + '@ABCDEFGHIJKLMNO' . + 'PQRSTUVWXYZ%5b%5c%5d%5e_' . + '%60abcdefghijklmno' . + 'pqrstuvwxyz%7b%7c%7d~%7f', + $newStr); + + $this->assertEquals($str, URLUtil::decodePath($newStr)); + + } + + function testEncodePathSegment() { + + $str = ''; + for ($i = 0;$i < 128;$i++) $str .= chr($i); + + $newStr = URLUtil::encodePathSegment($str); + + // Note: almost exactly the same as the last test, with the + // exception of the encoding of / (ascii code 2f) + $this->assertEquals( + '%00%01%02%03%04%05%06%07%08%09%0a%0b%0c%0d%0e%0f' . + '%10%11%12%13%14%15%16%17%18%19%1a%1b%1c%1d%1e%1f' . + '%20%21%22%23%24%25%26%27()%2a%2b%2c-.%2f' . + '0123456789:%3b%3c%3d%3e%3f' . + '@ABCDEFGHIJKLMNO' . + 'PQRSTUVWXYZ%5b%5c%5d%5e_' . + '%60abcdefghijklmno' . + 'pqrstuvwxyz%7b%7c%7d~%7f', + $newStr); + + $this->assertEquals($str, URLUtil::decodePathSegment($newStr)); + + } + + function testDecode() { + + $str = 'Hello%20Test+Test2.txt'; + $newStr = URLUtil::decodePath($str); + $this->assertEquals('Hello Test+Test2.txt', $newStr); + + } + + /** + * @depends testDecode + */ + function testDecodeUmlaut() { + + $str = 'Hello%C3%BC.txt'; + $newStr = URLUtil::decodePath($str); + $this->assertEquals("Hello\xC3\xBC.txt", $newStr); + + } + + /** + * @depends testDecodeUmlaut + */ + function testDecodeUmlautLatin1() { + + $str = 'Hello%FC.txt'; + $newStr = URLUtil::decodePath($str); + $this->assertEquals("Hello\xC3\xBC.txt", $newStr); + + } + + /** + * This testcase was sent by a bug reporter + * + * @depends testDecode + */ + function testDecodeAccentsWindows7() { + + $str = '/webdav/%C3%A0fo%C3%B3'; + $newStr = URLUtil::decodePath($str); + $this->assertEquals(strtolower($str), URLUtil::encodePath($newStr)); + + } + + function testSplitPath() { + + $strings = [ + + // input // expected result + '/foo/bar' => ['/foo','bar'], + '/foo/bar/' => ['/foo','bar'], + 'foo/bar/' => ['foo','bar'], + 'foo/bar' => ['foo','bar'], + 'foo/bar/baz' => ['foo/bar','baz'], + 'foo/bar/baz/' => ['foo/bar','baz'], + 'foo' => ['','foo'], + 'foo/' => ['','foo'], + '/foo/' => ['','foo'], + '/foo' => ['','foo'], + '' => [null,null], + + // UTF-8 + "/\xC3\xA0fo\xC3\xB3/bar" => ["/\xC3\xA0fo\xC3\xB3",'bar'], + "/\xC3\xA0foo/b\xC3\xBCr/" => ["/\xC3\xA0foo","b\xC3\xBCr"], + "foo/\xC3\xA0\xC3\xBCr" => ["foo","\xC3\xA0\xC3\xBCr"], + + ]; + + foreach ($strings as $input => $expected) { + + $output = URLUtil::splitPath($input); + $this->assertEquals($expected, $output, 'The expected output for \'' . $input . '\' was incorrect'); + + + } + + } + + /** + * @dataProvider resolveData + */ + function testResolve($base, $update, $expected) { + + $this->assertEquals( + $expected, + URLUtil::resolve($base, $update) + ); + + } + + function resolveData() { + + return [ + [ + 'http://example.org/foo/baz', + '/bar', + 'http://example.org/bar', + ], + [ + 'https://example.org/foo', + '//example.net/', + 'https://example.net/', + ], + [ + 'https://example.org/foo', + '?a=b', + 'https://example.org/foo?a=b', + ], + [ + '//example.org/foo', + '?a=b', + '//example.org/foo?a=b', + ], + // Ports and fragments + [ + 'https://example.org:81/foo#hey', + '?a=b#c=d', + 'https://example.org:81/foo?a=b#c=d', + ], + // Relative.. in-directory paths + [ + 'http://example.org/foo/bar', + 'bar2', + 'http://example.org/foo/bar2', + ], + // Now the base path ended with a slash + [ + 'http://example.org/foo/bar/', + 'bar2/bar3', + 'http://example.org/foo/bar/bar2/bar3', + ], + ]; + + } + +} diff --git a/vendor/sabre/http/tests/HTTP/UtilTest.php b/vendor/sabre/http/tests/HTTP/UtilTest.php new file mode 100644 index 000000000..5659bdd2e --- /dev/null +++ b/vendor/sabre/http/tests/HTTP/UtilTest.php @@ -0,0 +1,206 @@ +<?php + +namespace Sabre\HTTP; + +class UtilTest extends \PHPUnit_Framework_TestCase { + + function testParseHTTPDate() { + + $times = [ + 'Wed, 13 Oct 2010 10:26:00 GMT', + 'Wednesday, 13-Oct-10 10:26:00 GMT', + 'Wed Oct 13 10:26:00 2010', + ]; + + $expected = 1286965560; + + foreach ($times as $time) { + $result = Util::parseHTTPDate($time); + $this->assertEquals($expected, $result->format('U')); + } + + $result = Util::parseHTTPDate('Wed Oct 6 10:26:00 2010'); + $this->assertEquals(1286360760, $result->format('U')); + + } + + function testParseHTTPDateFail() { + + $times = [ + //random string + 'NOW', + // not-GMT timezone + 'Wednesday, 13-Oct-10 10:26:00 UTC', + // No space before the 6 + 'Wed Oct 6 10:26:00 2010', + // Invalid day + 'Wed Oct 0 10:26:00 2010', + 'Wed Oct 32 10:26:00 2010', + 'Wed, 0 Oct 2010 10:26:00 GMT', + 'Wed, 32 Oct 2010 10:26:00 GMT', + 'Wednesday, 32-Oct-10 10:26:00 GMT', + // Invalid hour + 'Wed, 13 Oct 2010 24:26:00 GMT', + 'Wednesday, 13-Oct-10 24:26:00 GMT', + 'Wed Oct 13 24:26:00 2010', + ]; + + foreach ($times as $time) { + $this->assertFalse(Util::parseHTTPDate($time), 'We used the string: ' . $time); + } + + } + + function testTimezones() { + + $default = date_default_timezone_get(); + date_default_timezone_set('Europe/Amsterdam'); + + $this->testParseHTTPDate(); + + date_default_timezone_set($default); + + } + + function testToHTTPDate() { + + $dt = new \DateTime('2011-12-10 12:00:00 +0200'); + + $this->assertEquals( + 'Sat, 10 Dec 2011 10:00:00 GMT', + Util::toHTTPDate($dt) + ); + + } + + /** + * @dataProvider negotiateData + */ + function testNegotiate($acceptHeader, $available, $expected) { + + $this->assertEquals( + $expected, + Util::negotiate($acceptHeader, $available) + ); + + } + + function negotiateData() { + + return [ + [ // simple + 'application/xml', + ['application/xml'], + 'application/xml', + ], + [ // no header + null, + ['application/xml'], + 'application/xml', + ], + [ // 2 options + 'application/json', + ['application/xml', 'application/json'], + 'application/json', + ], + [ // 2 choices + 'application/json, application/xml', + ['application/xml'], + 'application/xml', + ], + [ // quality + 'application/xml;q=0.2, application/json', + ['application/xml', 'application/json'], + 'application/json', + ], + [ // wildcard + 'image/jpeg, image/png, */*', + ['application/xml', 'application/json'], + 'application/xml', + ], + [ // wildcard + quality + 'image/jpeg, image/png; q=0.5, */*', + ['application/xml', 'application/json', 'image/png'], + 'application/xml', + ], + [ // no match + 'image/jpeg', + ['application/xml'], + null, + ], + [ // This is used in sabre/dav + 'text/vcard; version=4.0', + [ + // Most often used mime-type. Version 3 + 'text/x-vcard', + // The correct standard mime-type. Defaults to version 3 as + // well. + 'text/vcard', + // vCard 4 + 'text/vcard; version=4.0', + // vCard 3 + 'text/vcard; version=3.0', + // jCard + 'application/vcard+json', + ], + 'text/vcard; version=4.0', + + ], + [ // rfc7231 example 1 + 'audio/*; q=0.2, audio/basic', + [ + 'audio/pcm', + 'audio/basic', + ], + 'audio/basic', + ], + [ // Lower quality after + 'audio/pcm; q=0.2, audio/basic; q=0.1', + [ + 'audio/pcm', + 'audio/basic', + ], + 'audio/pcm', + ], + [ // Random parameter, should be ignored + 'audio/pcm; hello; q=0.2, audio/basic; q=0.1', + [ + 'audio/pcm', + 'audio/basic', + ], + 'audio/pcm', + ], + [ // No whitepace after type, should pick the one that is the most specific. + 'text/vcard;version=3.0, text/vcard', + [ + 'text/vcard', + 'text/vcard; version=3.0' + ], + 'text/vcard; version=3.0', + ], + [ // Same as last one, but order is different + 'text/vcard, text/vcard;version=3.0', + [ + 'text/vcard; version=3.0', + 'text/vcard', + ], + 'text/vcard; version=3.0', + ], + [ // Charset should be ignored here. + 'text/vcard; charset=utf-8; version=3.0, text/vcard', + [ + 'text/vcard', + 'text/vcard; version=3.0' + ], + 'text/vcard; version=3.0', + ], + [ // Undefined offset issue. + 'text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2', + ['application/xml', 'application/json', 'image/png'], + 'application/xml', + ], + + ]; + + } +} diff --git a/vendor/sabre/http/tests/bootstrap.php b/vendor/sabre/http/tests/bootstrap.php new file mode 100644 index 000000000..74931b6f1 --- /dev/null +++ b/vendor/sabre/http/tests/bootstrap.php @@ -0,0 +1,8 @@ +<?php + +date_default_timezone_set('UTC'); + +ini_set('error_reporting', E_ALL | E_STRICT | E_DEPRECATED); + +// Composer autoloader +include __DIR__ . '/../vendor/autoload.php'; diff --git a/vendor/sabre/http/tests/phpcs/ruleset.xml b/vendor/sabre/http/tests/phpcs/ruleset.xml new file mode 100644 index 000000000..ec2c4c84b --- /dev/null +++ b/vendor/sabre/http/tests/phpcs/ruleset.xml @@ -0,0 +1,57 @@ +<?xml version="1.0"?> +<ruleset name="sabre.php"> + <description>sabre.io codesniffer ruleset</description> + + <!-- Include the whole PSR-1 standard --> + <rule ref="PSR1" /> + + <!-- All PHP files MUST use the Unix LF (linefeed) line ending. --> + <rule ref="Generic.Files.LineEndings"> + <properties> + <property name="eolChar" value="\n"/> + </properties> + </rule> + + <!-- The closing ?> tag MUST be omitted from files containing only PHP. --> + <rule ref="Zend.Files.ClosingTag"/> + + <!-- There MUST NOT be trailing whitespace at the end of non-blank lines. --> + <rule ref="Squiz.WhiteSpace.SuperfluousWhitespace"> + <properties> + <property name="ignoreBlankLines" value="true"/> + </properties> + </rule> + + <!-- There MUST NOT be more than one statement per line. --> + <rule ref="Generic.Formatting.DisallowMultipleStatements"/> + + <rule ref="Generic.WhiteSpace.ScopeIndent"> + <properties> + <property name="ignoreIndentationTokens" type="array" value="T_COMMENT,T_DOC_COMMENT"/> + </properties> + </rule> + <rule ref="Generic.WhiteSpace.DisallowTabIndent"/> + + <!-- PHP keywords MUST be in lower case. --> + <rule ref="Generic.PHP.LowerCaseKeyword"/> + + <!-- The PHP constants true, false, and null MUST be in lower case. --> + <rule ref="Generic.PHP.LowerCaseConstant"/> + + <!-- <rule ref="Squiz.Scope.MethodScope"/> --> + <rule ref="Squiz.WhiteSpace.ScopeKeywordSpacing"/> + + <!-- In the argument list, there MUST NOT be a space before each comma, and there MUST be one space after each comma. --> + <!-- + <rule ref="Squiz.Functions.FunctionDeclarationArgumentSpacing"> + <properties> + <property name="equalsSpacing" value="1"/> + </properties> + </rule> + <rule ref="Squiz.Functions.FunctionDeclarationArgumentSpacing.SpacingAfterHint"> + <severity>0</severity> + </rule> + --> + <rule ref="PEAR.WhiteSpace.ScopeClosingBrace"/> + +</ruleset> diff --git a/vendor/sabre/http/tests/phpunit.xml b/vendor/sabre/http/tests/phpunit.xml new file mode 100644 index 000000000..32d701a37 --- /dev/null +++ b/vendor/sabre/http/tests/phpunit.xml @@ -0,0 +1,18 @@ +<phpunit + colors="true" + bootstrap="bootstrap.php" + convertErrorsToExceptions="true" + convertNoticesToExceptions="true" + convertWarningsToExceptions="true" + strict="true" + > + <testsuite name="Sabre_HTTP"> + <directory>HTTP/</directory> + </testsuite> + + <filter> + <whitelist addUncoveredFilesFromWhitelist="true"> + <directory suffix=".php">../lib/</directory> + </whitelist> + </filter> +</phpunit> diff --git a/vendor/sabre/uri/.gitignore b/vendor/sabre/uri/.gitignore new file mode 100644 index 000000000..19d1affd4 --- /dev/null +++ b/vendor/sabre/uri/.gitignore @@ -0,0 +1,13 @@ +# Composer +vendor/ +composer.lock + +# Tests +tests/cov/ + +# Composer binaries +bin/phpunit +bin/phpcs + +# Vim +.*.swp diff --git a/vendor/sabre/uri/.travis.yml b/vendor/sabre/uri/.travis.yml new file mode 100644 index 000000000..75c8270df --- /dev/null +++ b/vendor/sabre/uri/.travis.yml @@ -0,0 +1,14 @@ +language: php +php: + - 5.4 + - 5.5 + - 5.6 + - 7 + - 7.1 + +script: + - ./bin/phpunit --configuration tests/phpunit.xml.dist + - ./bin/sabre-cs-fixer fix lib/ --dry-run --diff + +before_script: composer install --dev + diff --git a/vendor/sabre/uri/composer.json b/vendor/sabre/uri/composer.json new file mode 100644 index 000000000..49d69e723 --- /dev/null +++ b/vendor/sabre/uri/composer.json @@ -0,0 +1,41 @@ +{ + "name": "sabre/uri", + "description": "Functions for making sense out of URIs.", + "keywords": [ + "URI", + "URL", + "rfc3986" + ], + "homepage": "http://sabre.io/uri/", + "license": "BSD-3-Clause", + "require": { + "php": ">=5.4.7" + }, + "authors": [ + { + "name": "Evert Pot", + "email": "me@evertpot.com", + "homepage": "http://evertpot.com/", + "role": "Developer" + } + ], + "support": { + "forum": "https://groups.google.com/group/sabredav-discuss", + "source": "https://github.com/fruux/sabre-uri" + }, + "autoload": { + "files" : [ + "lib/functions.php" + ], + "psr-4" : { + "Sabre\\Uri\\" : "lib/" + } + }, + "require-dev": { + "sabre/cs": "~1.0.0", + "phpunit/phpunit" : ">=4.0,<6.0" + }, + "config" : { + "bin-dir" : "bin/" + } +} diff --git a/vendor/sabre/uri/tests/BuildTest.php b/vendor/sabre/uri/tests/BuildTest.php new file mode 100644 index 000000000..ae4b4ba27 --- /dev/null +++ b/vendor/sabre/uri/tests/BuildTest.php @@ -0,0 +1,41 @@ +<?php + +namespace Sabre\Uri; + +class BuildTest extends \PHPUnit_Framework_TestCase{ + + /** + * @dataProvider buildUriData + */ + function testBuild($value) { + + $this->assertEquals( + $value, + build(parse_url($value)) + ); + + } + + function buildUriData() { + + return [ + ['http://example.org/'], + ['http://example.org/foo/bar'], + ['//example.org/foo/bar'], + ['/foo/bar'], + ['http://example.org:81/'], + ['http://user@example.org:81/'], + ['http://example.org:81/hi?a=b'], + ['http://example.org:81/hi?a=b#c=d'], + // [ '//example.org:81/hi?a=b#c=d'], // Currently fails due to a + // PHP bug. + ['/hi?a=b#c=d'], + ['?a=b#c=d'], + ['#c=d'], + ['file:///etc/hosts'], + ['file://localhost/etc/hosts'], + ]; + + } + +} diff --git a/vendor/sabre/uri/tests/NormalizeTest.php b/vendor/sabre/uri/tests/NormalizeTest.php new file mode 100644 index 000000000..4dbe94320 --- /dev/null +++ b/vendor/sabre/uri/tests/NormalizeTest.php @@ -0,0 +1,42 @@ +<?php + +namespace Sabre\Uri; + +class NormalizeTest extends \PHPUnit_Framework_TestCase{ + + /** + * @dataProvider normalizeData + */ + function testNormalize($in, $out) { + + $this->assertEquals( + $out, + normalize($in) + ); + + } + + function normalizeData() { + + return [ + ['http://example.org/', 'http://example.org/'], + ['HTTP://www.EXAMPLE.com/', 'http://www.example.com/'], + ['http://example.org/%7Eevert', 'http://example.org/~evert'], + ['http://example.org/./evert', 'http://example.org/evert'], + ['http://example.org/../evert', 'http://example.org/evert'], + ['http://example.org/foo/../evert', 'http://example.org/evert'], + ['/%41', '/A'], + ['/%3F', '/%3F'], + ['/%3f', '/%3F'], + ['http://example.org', 'http://example.org/'], + ['http://example.org:/', 'http://example.org/'], + ['http://example.org:80/', 'http://example.org/'], + // See issue #6. parse_url corrupts strings like this, but only on + // macs. + //[ 'http://example.org/有词法别名.zh','http://example.org/%E6%9C%89%E8%AF%8D%E6%B3%95%E5%88%AB%E5%90%8D.zh'], + + ]; + + } + +} diff --git a/vendor/sabre/uri/tests/ParseTest.php b/vendor/sabre/uri/tests/ParseTest.php new file mode 100644 index 000000000..d797c2c08 --- /dev/null +++ b/vendor/sabre/uri/tests/ParseTest.php @@ -0,0 +1,193 @@ +<?php + +namespace Sabre\Uri; + +class ParseTest extends \PHPUnit_Framework_TestCase{ + + /** + * @dataProvider parseData + */ + function testParse($in, $out) { + + $this->assertEquals( + $out, + parse($in) + ); + + } + + /** + * @dataProvider parseData + */ + function testParseFallback($in, $out) { + + $result = _parse_fallback($in); + $result = $result + [ + 'scheme' => null, + 'host' => null, + 'path' => null, + 'port' => null, + 'user' => null, + 'query' => null, + 'fragment' => null, + ]; + + $this->assertEquals( + $out, + $result + ); + + } + + function parseData() { + + return [ + [ + 'http://example.org/hello?foo=bar#test', + [ + 'scheme' => 'http', + 'host' => 'example.org', + 'path' => '/hello', + 'port' => null, + 'user' => null, + 'query' => 'foo=bar', + 'fragment' => 'test' + ] + ], + // See issue #6. parse_url corrupts strings like this, but only on + // macs. + [ + 'http://example.org/有词法别名.zh', + [ + 'scheme' => 'http', + 'host' => 'example.org', + 'path' => '/%E6%9C%89%E8%AF%8D%E6%B3%95%E5%88%AB%E5%90%8D.zh', + 'port' => null, + 'user' => null, + 'query' => null, + 'fragment' => null + ] + ], + [ + 'ftp://user:password@ftp.example.org/', + [ + 'scheme' => 'ftp', + 'host' => 'ftp.example.org', + 'path' => '/', + 'port' => null, + 'user' => 'user', + 'pass' => 'password', + 'query' => null, + 'fragment' => null, + ] + ], + // See issue #9, parse_url doesn't like colons followed by numbers even + // though they are allowed since RFC 3986 + [ + 'http://example.org/hello:12?foo=bar#test', + [ + 'scheme' => 'http', + 'host' => 'example.org', + 'path' => '/hello:12', + 'port' => null, + 'user' => null, + 'query' => 'foo=bar', + 'fragment' => 'test' + ] + ], + [ + '/path/to/colon:34', + [ + 'scheme' => null, + 'host' => null, + 'path' => '/path/to/colon:34', + 'port' => null, + 'user' => null, + 'query' => null, + 'fragment' => null, + ] + ], + // File scheme + [ + 'file:///foo/bar', + [ + 'scheme' => 'file', + 'host' => '', + 'path' => '/foo/bar', + 'port' => null, + 'user' => null, + 'query' => null, + 'fragment' => null, + ] + ], + // Weird scheme with triple-slash. See Issue #11. + [ + 'vfs:///somefile', + [ + 'scheme' => 'vfs', + 'host' => '', + 'path' => '/somefile', + 'port' => null, + 'user' => null, + 'query' => null, + 'fragment' => null, + ] + ], + // Examples from RFC3986 + [ + 'ldap://[2001:db8::7]/c=GB?objectClass?one', + [ + 'scheme' => 'ldap', + 'host' => '[2001:db8::7]', + 'path' => '/c=GB', + 'port' => null, + 'user' => null, + 'query' => 'objectClass?one', + 'fragment' => null, + ] + ], + [ + 'news:comp.infosystems.www.servers.unix', + [ + 'scheme' => 'news', + 'host' => null, + 'path' => 'comp.infosystems.www.servers.unix', + 'port' => null, + 'user' => null, + 'query' => null, + 'fragment' => null, + ] + ], + // Port + [ + 'http://example.org:8080/', + [ + 'scheme' => 'http', + 'host' => 'example.org', + 'path' => '/', + 'port' => 8080, + 'user' => null, + 'query' => null, + 'fragment' => null, + ] + ], + // Parial url + [ + '#foo', + [ + 'scheme' => null, + 'host' => null, + 'path' => null, + 'port' => null, + 'user' => null, + 'query' => null, + 'fragment' => 'foo', + ] + + ] + + ]; + + } + +} diff --git a/vendor/sabre/uri/tests/ResolveTest.php b/vendor/sabre/uri/tests/ResolveTest.php new file mode 100644 index 000000000..f0d123512 --- /dev/null +++ b/vendor/sabre/uri/tests/ResolveTest.php @@ -0,0 +1,99 @@ +<?php + +namespace Sabre\Uri; + +class ResolveTest extends \PHPUnit_Framework_TestCase{ + + /** + * @dataProvider resolveData + */ + function testResolve($base, $update, $expected) { + + $this->assertEquals( + $expected, + resolve($base, $update) + ); + + } + + function resolveData() { + + return [ + [ + 'http://example.org/foo/baz', + '/bar', + 'http://example.org/bar', + ], + [ + 'https://example.org/foo', + '//example.net/', + 'https://example.net/', + ], + [ + 'https://example.org/foo', + '?a=b', + 'https://example.org/foo?a=b', + ], + [ + '//example.org/foo', + '?a=b', + '//example.org/foo?a=b', + ], + // Ports and fragments + [ + 'https://example.org:81/foo#hey', + '?a=b#c=d', + 'https://example.org:81/foo?a=b#c=d', + ], + // Relative.. in-directory paths + [ + 'http://example.org/foo/bar', + 'bar2', + 'http://example.org/foo/bar2', + ], + // Now the base path ended with a slash + [ + 'http://example.org/foo/bar/', + 'bar2/bar3', + 'http://example.org/foo/bar/bar2/bar3', + ], + // .. and . + [ + 'http://example.org/foo/bar/', + '../bar2/.././/bar3/', + 'http://example.org/foo//bar3/', + ], + // Only updating the fragment + [ + 'https://example.org/foo?a=b', + '#comments', + 'https://example.org/foo?a=b#comments', + ], + // Switching to mailto! + [ + 'https://example.org/foo?a=b', + 'mailto:foo@example.org', + 'mailto:foo@example.org', + ], + // Resolving empty path + [ + 'http://www.example.org', + '#foo', + 'http://www.example.org/#foo', + ], + // Another fragment test + [ + 'http://example.org/path.json', + '#', + 'http://example.org/path.json', + ], + [ + 'http://www.example.com', + '#', + 'http://www.example.com/', + ] + ]; + + } + +} diff --git a/vendor/sabre/uri/tests/SplitTest.php b/vendor/sabre/uri/tests/SplitTest.php new file mode 100644 index 000000000..2d73c9b25 --- /dev/null +++ b/vendor/sabre/uri/tests/SplitTest.php @@ -0,0 +1,41 @@ +<?php + +namespace Sabre\Uri; + +class SplitTest extends \PHPUnit_Framework_TestCase{ + + function testSplit() { + + $strings = [ + + // input // expected result + '/foo/bar' => ['/foo','bar'], + '/foo/bar/' => ['/foo','bar'], + 'foo/bar/' => ['foo','bar'], + 'foo/bar' => ['foo','bar'], + 'foo/bar/baz' => ['foo/bar','baz'], + 'foo/bar/baz/' => ['foo/bar','baz'], + 'foo' => ['','foo'], + 'foo/' => ['','foo'], + '/foo/' => ['','foo'], + '/foo' => ['','foo'], + '' => [null,null], + + // UTF-8 + "/\xC3\xA0fo\xC3\xB3/bar" => ["/\xC3\xA0fo\xC3\xB3",'bar'], + "/\xC3\xA0foo/b\xC3\xBCr/" => ["/\xC3\xA0foo","b\xC3\xBCr"], + "foo/\xC3\xA0\xC3\xBCr" => ["foo","\xC3\xA0\xC3\xBCr"], + + ]; + + foreach ($strings as $input => $expected) { + + $output = split($input); + $this->assertEquals($expected, $output, 'The expected output for \'' . $input . '\' was incorrect'); + + + } + + } + +} diff --git a/vendor/sabre/uri/tests/phpcs/ruleset.xml b/vendor/sabre/uri/tests/phpcs/ruleset.xml new file mode 100644 index 000000000..ec2c4c84b --- /dev/null +++ b/vendor/sabre/uri/tests/phpcs/ruleset.xml @@ -0,0 +1,57 @@ +<?xml version="1.0"?> +<ruleset name="sabre.php"> + <description>sabre.io codesniffer ruleset</description> + + <!-- Include the whole PSR-1 standard --> + <rule ref="PSR1" /> + + <!-- All PHP files MUST use the Unix LF (linefeed) line ending. --> + <rule ref="Generic.Files.LineEndings"> + <properties> + <property name="eolChar" value="\n"/> + </properties> + </rule> + + <!-- The closing ?> tag MUST be omitted from files containing only PHP. --> + <rule ref="Zend.Files.ClosingTag"/> + + <!-- There MUST NOT be trailing whitespace at the end of non-blank lines. --> + <rule ref="Squiz.WhiteSpace.SuperfluousWhitespace"> + <properties> + <property name="ignoreBlankLines" value="true"/> + </properties> + </rule> + + <!-- There MUST NOT be more than one statement per line. --> + <rule ref="Generic.Formatting.DisallowMultipleStatements"/> + + <rule ref="Generic.WhiteSpace.ScopeIndent"> + <properties> + <property name="ignoreIndentationTokens" type="array" value="T_COMMENT,T_DOC_COMMENT"/> + </properties> + </rule> + <rule ref="Generic.WhiteSpace.DisallowTabIndent"/> + + <!-- PHP keywords MUST be in lower case. --> + <rule ref="Generic.PHP.LowerCaseKeyword"/> + + <!-- The PHP constants true, false, and null MUST be in lower case. --> + <rule ref="Generic.PHP.LowerCaseConstant"/> + + <!-- <rule ref="Squiz.Scope.MethodScope"/> --> + <rule ref="Squiz.WhiteSpace.ScopeKeywordSpacing"/> + + <!-- In the argument list, there MUST NOT be a space before each comma, and there MUST be one space after each comma. --> + <!-- + <rule ref="Squiz.Functions.FunctionDeclarationArgumentSpacing"> + <properties> + <property name="equalsSpacing" value="1"/> + </properties> + </rule> + <rule ref="Squiz.Functions.FunctionDeclarationArgumentSpacing.SpacingAfterHint"> + <severity>0</severity> + </rule> + --> + <rule ref="PEAR.WhiteSpace.ScopeClosingBrace"/> + +</ruleset> diff --git a/vendor/sabre/uri/tests/phpunit.xml.dist b/vendor/sabre/uri/tests/phpunit.xml.dist new file mode 100644 index 000000000..338d24d3c --- /dev/null +++ b/vendor/sabre/uri/tests/phpunit.xml.dist @@ -0,0 +1,18 @@ +<phpunit + colors="true" + bootstrap="../vendor/autoload.php" + convertErrorsToExceptions="true" + convertNoticesToExceptions="true" + convertWarningsToExceptions="true" + strict="true" + > + <testsuite name="sabre-uri"> + <directory>.</directory> + </testsuite> + + <filter> + <whitelist addUncoveredFilesFromWhitelist="true"> + <directory suffix=".php">../lib/</directory> + </whitelist> + </filter> +</phpunit> diff --git a/vendor/sabre/vobject/.gitignore b/vendor/sabre/vobject/.gitignore new file mode 100644 index 000000000..f723749ef --- /dev/null +++ b/vendor/sabre/vobject/.gitignore @@ -0,0 +1,23 @@ +# Composer stuff +vendor/ +composer.lock +tests/cov/ +tests/temp + +#vim +.*.swp + +#binaries +bin/phpunit +bin/phpcs +bin/php-cs-fixer +bin/sabre-cs-fixer +bin/hoa + +# Development stuff +testdata/ +.php_cs.cache +.idea + +# OS X +.DS_Store diff --git a/vendor/sabre/vobject/.php_cs.dist b/vendor/sabre/vobject/.php_cs.dist new file mode 100644 index 000000000..8d61ee259 --- /dev/null +++ b/vendor/sabre/vobject/.php_cs.dist @@ -0,0 +1,12 @@ +<?php + +$config = PhpCsFixer\Config::create(); +$config->getFinder() + ->exclude('vendor') + ->in(__DIR__); +$config->setRules([ + '@PSR1' => true, + '@Symfony' =>true +]); + +return $config; \ No newline at end of file diff --git a/vendor/sabre/vobject/.travis.yml b/vendor/sabre/vobject/.travis.yml new file mode 100644 index 000000000..a36b67c47 --- /dev/null +++ b/vendor/sabre/vobject/.travis.yml @@ -0,0 +1,31 @@ +language: php +php: + - 5.5 + - 5.6 + - 7.0 + - 7.1 + - 7.2 + - 7.3 + - 7.4 + +matrix: + fast_finish: true + allow_failures: + - php: 5.5 + +install: + - if [[ $TRAVIS_PHP_VERSION =~ ^7\.1|7\.2|7\.3|7\.4$ ]]; then wget https://github.com/phpstan/phpstan/releases/download/0.12.5/phpstan.phar; fi + +before_script: + - composer install + +script: + - if [[ $TRAVIS_PHP_VERSION =~ ^7\.1|7\.2|7\.3|7\.4$ ]]; then php phpstan.phar analyse -c phpstan.neon lib tests; fi + - ./bin/phpunit --configuration tests/phpunit.xml --coverage-clover=coverage.xml + +after_success: + - bash <(curl -s https://codecov.io/bash) + +cache: + directories: + - $HOME/.composer/cache diff --git a/vendor/sabre/vobject/bin/bench.php b/vendor/sabre/vobject/bin/bench.php old mode 100644 new mode 100755 diff --git a/vendor/sabre/vobject/bin/fetch_windows_zones.php b/vendor/sabre/vobject/bin/fetch_windows_zones.php old mode 100644 new mode 100755 diff --git a/vendor/sabre/vobject/bin/generate_vcards b/vendor/sabre/vobject/bin/generate_vcards old mode 100644 new mode 100755 diff --git a/vendor/sabre/vobject/bin/generateicalendardata.php b/vendor/sabre/vobject/bin/generateicalendardata.php old mode 100644 new mode 100755 diff --git a/vendor/sabre/vobject/bin/mergeduplicates.php b/vendor/sabre/vobject/bin/mergeduplicates.php old mode 100644 new mode 100755 diff --git a/vendor/sabre/vobject/bin/vobject b/vendor/sabre/vobject/bin/vobject old mode 100644 new mode 100755 diff --git a/vendor/sabre/vobject/composer.json b/vendor/sabre/vobject/composer.json new file mode 100644 index 000000000..bd7892464 --- /dev/null +++ b/vendor/sabre/vobject/composer.json @@ -0,0 +1,91 @@ +{ + "name": "sabre/vobject", + "description" : "The VObject library for PHP allows you to easily parse and manipulate iCalendar and vCard objects", + "keywords" : [ + "iCalendar", + "iCal", + "vCalendar", + "vCard", + "jCard", + "jCal", + "ics", + "vcf", + "xCard", + "xCal", + "freebusy", + "recurrence", + "availability", + "rfc2425", + "rfc2426", + "rfc2739", + "rfc4770", + "rfc5545", + "rfc5546", + "rfc6321", + "rfc6350", + "rfc6351", + "rfc6474", + "rfc6638", + "rfc6715", + "rfc6868" + ], + "homepage" : "http://sabre.io/vobject/", + "license" : "BSD-3-Clause", + "require" : { + "php" : ">=5.5", + "ext-mbstring" : "*", + "sabre/xml" : ">=1.5 <3.0" + }, + "require-dev" : { + "phpunit/phpunit" : "> 4.8.35, <6.0.0" + }, + "suggest" : { + "hoa/bench" : "If you would like to run the benchmark scripts" + }, + "authors" : [ + { + "name" : "Evert Pot", + "email" : "me@evertpot.com", + "homepage" : "http://evertpot.com/", + "role" : "Developer" + }, + { + "name" : "Dominik Tobschall", + "email" : "dominik@fruux.com", + "homepage" : "http://tobschall.de/", + "role" : "Developer" + }, + { + "name" : "Ivan Enderlin", + "email" : "ivan.enderlin@hoa-project.net", + "homepage" : "http://mnt.io/", + "role" : "Developer" + } + ], + "support" : { + "forum" : "https://groups.google.com/group/sabredav-discuss", + "source" : "https://github.com/fruux/sabre-vobject" + }, + "autoload" : { + "psr-4" : { + "Sabre\\VObject\\" : "lib/" + } + }, + "autoload-dev" : { + "psr-4" : { + "Sabre\\VObject\\" : "tests/VObject" + } + }, + "bin" : [ + "bin/vobject", + "bin/generate_vcards" + ], + "extra" : { + "branch-alias" : { + "dev-master" : "4.0.x-dev" + } + }, + "config" : { + "bin-dir" : "bin" + } +} diff --git a/vendor/sabre/vobject/tests/VObject/AttachIssueTest.php b/vendor/sabre/vobject/tests/VObject/AttachIssueTest.php new file mode 100644 index 000000000..fb2b8b037 --- /dev/null +++ b/vendor/sabre/vobject/tests/VObject/AttachIssueTest.php @@ -0,0 +1,22 @@ +<?php + +namespace Sabre\VObject; + +use PHPUnit\Framework\TestCase; + +class AttachIssueTest extends TestCase +{ + public function testRead() + { + $event = <<<ICS +BEGIN:VCALENDAR\r +BEGIN:VEVENT\r +ATTACH;FMTTYPE=;ENCODING=:Zm9v\r +END:VEVENT\r +END:VCALENDAR\r + +ICS; + $obj = Reader::read($event); + $this->assertEquals($event, $obj->serialize()); + } +} diff --git a/vendor/sabre/vobject/tests/VObject/BirthdayCalendarGeneratorTest.php b/vendor/sabre/vobject/tests/VObject/BirthdayCalendarGeneratorTest.php new file mode 100644 index 000000000..6e4f89a4c --- /dev/null +++ b/vendor/sabre/vobject/tests/VObject/BirthdayCalendarGeneratorTest.php @@ -0,0 +1,548 @@ +<?php + +namespace Sabre\VObject; + +use PHPUnit\Framework\TestCase; + +class BirthdayCalendarGeneratorTest extends TestCase +{ + use PHPUnitAssertions; + + public function testVcardStringWithValidBirthday() + { + $generator = new BirthdayCalendarGenerator(); + $input = <<<VCF +BEGIN:VCARD +VERSION:3.0 +N:Gump;Forrest;;Mr. +FN:Forrest Gump +BDAY:19850407 +UID:foo +END:VCARD +VCF; + + $expected = <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +BEGIN:VEVENT +UID:**ANY** +DTSTAMP:**ANY** +SUMMARY:Forrest Gump's Birthday +DTSTART;VALUE=DATE:19850407 +RRULE:FREQ=YEARLY +TRANSP:TRANSPARENT +X-SABRE-BDAY;X-SABRE-VCARD-UID=foo;X-SABRE-VCARD-FN=Forrest Gump:BDAY +END:VEVENT +END:VCALENDAR +ICS; + + $generator->setObjects($input); + $output = $generator->getResult(); + + $this->assertVObjectEqualsVObject( + $expected, + $output + ); + } + + public function testArrayOfVcardStringsWithValidBirthdays() + { + $generator = new BirthdayCalendarGenerator(); + $input = []; + + $input[] = <<<VCF +BEGIN:VCARD +VERSION:3.0 +N:Gump;Forrest;;Mr. +FN:Forrest Gump +BDAY:19850407 +UID:foo +END:VCARD +VCF; + + $input[] = <<<VCF +BEGIN:VCARD +VERSION:3.0 +N:Doe;John;;Mr. +FN:John Doe +BDAY:19820210 +UID:bar +END:VCARD +VCF; + + $expected = <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +BEGIN:VEVENT +UID:**ANY** +DTSTAMP:**ANY** +SUMMARY:Forrest Gump's Birthday +DTSTART;VALUE=DATE:19850407 +RRULE:FREQ=YEARLY +TRANSP:TRANSPARENT +X-SABRE-BDAY;X-SABRE-VCARD-UID=foo;X-SABRE-VCARD-FN=Forrest Gump:BDAY +END:VEVENT +BEGIN:VEVENT +UID:**ANY** +DTSTAMP:**ANY** +SUMMARY:John Doe's Birthday +DTSTART;VALUE=DATE:19820210 +RRULE:FREQ=YEARLY +TRANSP:TRANSPARENT +X-SABRE-BDAY;X-SABRE-VCARD-UID=bar;X-SABRE-VCARD-FN=John Doe:BDAY +END:VEVENT +END:VCALENDAR +ICS; + + $generator->setObjects($input); + $output = $generator->getResult(); + + $this->assertVObjectEqualsVObject( + $expected, + $output + ); + } + + public function testArrayOfVcardStringsWithValidBirthdaysViaConstructor() + { + $input = []; + + $input[] = <<<VCF +BEGIN:VCARD +VERSION:3.0 +N:Gump;Forrest;;Mr. +FN:Forrest Gump +BDAY:19850407 +UID:foo +END:VCARD +VCF; + + $input[] = <<<VCF +BEGIN:VCARD +VERSION:3.0 +N:Doe;John;;Mr. +FN:John Doe +BDAY:19820210 +UID:bar +END:VCARD +VCF; + + $generator = new BirthdayCalendarGenerator($input); + + $expected = <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +BEGIN:VEVENT +UID:**ANY** +DTSTAMP:**ANY** +SUMMARY:Forrest Gump's Birthday +DTSTART;VALUE=DATE:19850407 +RRULE:FREQ=YEARLY +TRANSP:TRANSPARENT +X-SABRE-BDAY;X-SABRE-VCARD-UID=foo;X-SABRE-VCARD-FN=Forrest Gump:BDAY +END:VEVENT +BEGIN:VEVENT +UID:**ANY** +DTSTAMP:**ANY** +SUMMARY:John Doe's Birthday +DTSTART;VALUE=DATE:19820210 +RRULE:FREQ=YEARLY +TRANSP:TRANSPARENT +X-SABRE-BDAY;X-SABRE-VCARD-UID=bar;X-SABRE-VCARD-FN=John Doe:BDAY +END:VEVENT +END:VCALENDAR +ICS; + + $generator->setObjects($input); + $output = $generator->getResult(); + + $this->assertVObjectEqualsVObject( + $expected, + $output + ); + } + + public function testVcardObjectWithValidBirthday() + { + $generator = new BirthdayCalendarGenerator(); + $input = <<<VCF +BEGIN:VCARD +VERSION:3.0 +N:Gump;Forrest;;Mr. +FN:Forrest Gump +BDAY:19850407 +UID:foo +END:VCARD +VCF; + + $input = Reader::read($input); + + $expected = <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +BEGIN:VEVENT +UID:**ANY** +DTSTAMP:**ANY** +SUMMARY:Forrest Gump's Birthday +DTSTART;VALUE=DATE:19850407 +RRULE:FREQ=YEARLY +TRANSP:TRANSPARENT +X-SABRE-BDAY;X-SABRE-VCARD-UID=foo;X-SABRE-VCARD-FN=Forrest Gump:BDAY +END:VEVENT +END:VCALENDAR +ICS; + + $generator->setObjects($input); + $output = $generator->getResult(); + + $this->assertVObjectEqualsVObject( + $expected, + $output + ); + } + + public function testArrayOfVcardObjectsWithValidBirthdays() + { + $generator = new BirthdayCalendarGenerator(); + $input = []; + + $input[] = <<<VCF +BEGIN:VCARD +VERSION:3.0 +N:Gump;Forrest;;Mr. +FN:Forrest Gump +BDAY:19850407 +UID:foo +END:VCARD +VCF; + + $input[] = <<<VCF +BEGIN:VCARD +VERSION:3.0 +N:Doe;John;;Mr. +FN:John Doe +BDAY:19820210 +UID:bar +END:VCARD +VCF; + + foreach ($input as $key => $value) { + $input[$key] = Reader::read($value); + } + + $expected = <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +BEGIN:VEVENT +UID:**ANY** +DTSTAMP:**ANY** +SUMMARY:Forrest Gump's Birthday +DTSTART;VALUE=DATE:19850407 +RRULE:FREQ=YEARLY +TRANSP:TRANSPARENT +X-SABRE-BDAY;X-SABRE-VCARD-UID=foo;X-SABRE-VCARD-FN=Forrest Gump:BDAY +END:VEVENT +BEGIN:VEVENT +UID:**ANY** +DTSTAMP:**ANY** +SUMMARY:John Doe's Birthday +DTSTART;VALUE=DATE:19820210 +RRULE:FREQ=YEARLY +TRANSP:TRANSPARENT +X-SABRE-BDAY;X-SABRE-VCARD-UID=bar;X-SABRE-VCARD-FN=John Doe:BDAY +END:VEVENT +END:VCALENDAR +ICS; + + $generator->setObjects($input); + $output = $generator->getResult(); + + $this->assertVObjectEqualsVObject( + $expected, + $output + ); + } + + public function testVcardStringWithValidBirthdayWithXAppleOmitYear() + { + $generator = new BirthdayCalendarGenerator(); + $input = <<<VCF +BEGIN:VCARD +VERSION:3.0 +N:Gump;Forrest;;Mr. +FN:Forrest Gump +BDAY;X-APPLE-OMIT-YEAR=1604:1604-04-07 +UID:foo +END:VCARD +VCF; + + $expected = <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +BEGIN:VEVENT +UID:**ANY** +DTSTAMP:**ANY** +SUMMARY:Forrest Gump's Birthday +DTSTART;VALUE=DATE:20000407 +RRULE:FREQ=YEARLY +TRANSP:TRANSPARENT +X-SABRE-BDAY;X-SABRE-VCARD-UID=foo;X-SABRE-VCARD-FN=Forrest Gump;X-SABRE-OMIT-YEAR=2000:BDAY +END:VEVENT +END:VCALENDAR +ICS; + + $generator->setObjects($input); + $output = $generator->getResult(); + + $this->assertVObjectEqualsVObject( + $expected, + $output + ); + } + + public function testVcardStringWithValidBirthdayWithoutYear() + { + $generator = new BirthdayCalendarGenerator(); + $input = <<<VCF +BEGIN:VCARD +VERSION:4.0 +N:Gump;Forrest;;Mr. +FN:Forrest Gump +BDAY:--04-07 +UID:foo +END:VCARD +VCF; + + $expected = <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +BEGIN:VEVENT +UID:**ANY** +DTSTAMP:**ANY** +SUMMARY:Forrest Gump's Birthday +DTSTART;VALUE=DATE:20000407 +RRULE:FREQ=YEARLY +TRANSP:TRANSPARENT +X-SABRE-BDAY;X-SABRE-VCARD-UID=foo;X-SABRE-VCARD-FN=Forrest Gump;X-SABRE-OMIT-YEAR=2000:BDAY +END:VEVENT +END:VCALENDAR +ICS; + + $generator->setObjects($input); + $output = $generator->getResult(); + + $this->assertVObjectEqualsVObject( + $expected, + $output + ); + } + + public function testVcardStringWithInvalidBirthday() + { + $generator = new BirthdayCalendarGenerator(); + $input = <<<VCF +BEGIN:VCARD +VERSION:3.0 +N:Gump;Forrest;;Mr. +FN:Forrest Gump +BDAY:foo +X-SABRE-BDAY;X-SABRE-VCARD-UID=foo;X-SABRE-VCARD-FN=Forrest Gump:BDAY +END:VCARD +VCF; + + $expected = <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +END:VCALENDAR +ICS; + + $generator->setObjects($input); + $output = $generator->getResult(); + + $this->assertVObjectEqualsVObject( + $expected, + $output + ); + } + + public function testVcardStringWithNoBirthday() + { + $generator = new BirthdayCalendarGenerator(); + $input = <<<VCF +BEGIN:VCARD +VERSION:3.0 +N:Gump;Forrest;;Mr. +FN:Forrest Gump +UID:foo +END:VCARD +VCF; + + $expected = <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +END:VCALENDAR +ICS; + + $generator->setObjects($input); + $output = $generator->getResult(); + + $this->assertVObjectEqualsVObject( + $expected, + $output + ); + } + + public function testVcardStringWithValidBirthdayLocalized() + { + $generator = new BirthdayCalendarGenerator(); + $input = <<<VCF +BEGIN:VCARD +VERSION:3.0 +N:Gump;Forrest;;Mr. +FN:Forrest Gump +BDAY:19850407 +UID:foo +END:VCARD +VCF; + + $expected = <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +BEGIN:VEVENT +UID:**ANY** +DTSTAMP:**ANY** +SUMMARY:Forrest Gump's Geburtstag +DTSTART;VALUE=DATE:19850407 +RRULE:FREQ=YEARLY +TRANSP:TRANSPARENT +X-SABRE-BDAY;X-SABRE-VCARD-UID=foo;X-SABRE-VCARD-FN=Forrest Gump:BDAY +END:VEVENT +END:VCALENDAR +ICS; + + $generator->setObjects($input); + $generator->setFormat('%1$s\'s Geburtstag'); + $output = $generator->getResult(); + + $this->assertVObjectEqualsVObject( + $expected, + $output + ); + } + + public function testVcardStringWithEmptyBirthdayProperty() + { + $generator = new BirthdayCalendarGenerator(); + $input = <<<VCF +BEGIN:VCARD +VERSION:3.0 +N:Gump;Forrest;;Mr. +FN:Forrest Gump +BDAY: +UID:foo +END:VCARD +VCF; + + $expected = <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +END:VCALENDAR +ICS; + + $generator->setObjects($input); + $output = $generator->getResult(); + + $this->assertVObjectEqualsVObject( + $expected, + $output + ); + } + + /** + * @expectedException \Sabre\VObject\ParseException + */ + public function testParseException() + { + $generator = new BirthdayCalendarGenerator(); + $input = <<<EOT +BEGIN:FOO +FOO:Bar +END:FOO +EOT; + + $generator->setObjects($input); + } + + /** + * @expectedException \InvalidArgumentException + */ + public function testInvalidArgumentException() + { + $generator = new BirthdayCalendarGenerator(); + $input = <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +BEGIN:VEVENT +SUMMARY:Foo +DTSTART;VALUE=DATE:19850407 +END:VEVENT +END:VCALENDAR +ICS; + + $generator->setObjects($input); + } + + /** + * @expectedException \InvalidArgumentException + */ + public function testInvalidArgumentExceptionForPartiallyInvalidArray() + { + $generator = new BirthdayCalendarGenerator(); + $input = []; + + $input[] = <<<VCF +BEGIN:VCARD +VERSION:3.0 +N:Gump;Forrest;;Mr. +FN:Forrest Gump +BDAY:19850407 +UID:foo +END:VCARD +VCF; + $calendar = new Component\VCalendar(); + + $input = $calendar->add('VEVENT', [ + 'SUMMARY' => 'Foo', + 'DTSTART' => new \DateTime('NOW'), + ]); + + $generator->setObjects($input); + } + + public function testBrokenVcardWithoutFN() + { + $generator = new BirthdayCalendarGenerator(); + $input = <<<VCF +BEGIN:VCARD +VERSION:3.0 +N:Gump;Forrest;;Mr. +BDAY:19850407 +UID:foo +END:VCARD +VCF; + + $expected = <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +END:VCALENDAR +ICS; + + $generator->setObjects($input); + $output = $generator->getResult(); + + $this->assertVObjectEqualsVObject( + $expected, + $output + ); + } +} diff --git a/vendor/sabre/vobject/tests/VObject/CliTest.php b/vendor/sabre/vobject/tests/VObject/CliTest.php new file mode 100644 index 000000000..cae424d96 --- /dev/null +++ b/vendor/sabre/vobject/tests/VObject/CliTest.php @@ -0,0 +1,620 @@ +<?php + +namespace Sabre\VObject; + +use PHPUnit\Framework\TestCase; + +/** + * Tests the cli. + * + * Warning: these tests are very rudimentary. + */ +class CliTest extends TestCase +{ + /** @var CliMock */ + private $cli; + + public function setUp() + { + $this->cli = new CliMock(); + $this->cli->stderr = fopen('php://memory', 'r+'); + $this->cli->stdout = fopen('php://memory', 'r+'); + } + + public function testInvalidArg() + { + $this->assertEquals( + 1, + $this->cli->main(['vobject', '--hi']) + ); + rewind($this->cli->stderr); + $this->assertTrue(strlen(stream_get_contents($this->cli->stderr)) > 100); + } + + public function testQuiet() + { + $this->assertEquals( + 1, + $this->cli->main(['vobject', '-q']) + ); + $this->assertTrue($this->cli->quiet); + + rewind($this->cli->stderr); + $this->assertEquals(0, strlen(stream_get_contents($this->cli->stderr))); + } + + public function testHelp() + { + $this->assertEquals( + 0, + $this->cli->main(['vobject', '-h']) + ); + rewind($this->cli->stderr); + $this->assertTrue(strlen(stream_get_contents($this->cli->stderr)) > 100); + } + + public function testFormat() + { + $this->assertEquals( + 1, + $this->cli->main(['vobject', '--format=jcard']) + ); + + rewind($this->cli->stderr); + $this->assertTrue(strlen(stream_get_contents($this->cli->stderr)) > 100); + + $this->assertEquals('jcard', $this->cli->format); + } + + public function testFormatInvalid() + { + $this->assertEquals( + 1, + $this->cli->main(['vobject', '--format=foo']) + ); + + rewind($this->cli->stderr); + $this->assertTrue(strlen(stream_get_contents($this->cli->stderr)) > 100); + + $this->assertNull($this->cli->format); + } + + public function testInputFormatInvalid() + { + $this->assertEquals( + 1, + $this->cli->main(['vobject', '--inputformat=foo']) + ); + + rewind($this->cli->stderr); + $this->assertTrue(strlen(stream_get_contents($this->cli->stderr)) > 100); + + $this->assertNull($this->cli->format); + } + + public function testNoInputFile() + { + $this->assertEquals( + 1, + $this->cli->main(['vobject', 'color']) + ); + + rewind($this->cli->stderr); + $this->assertTrue(strlen(stream_get_contents($this->cli->stderr)) > 100); + } + + public function testTooManyArgs() + { + $this->assertEquals( + 1, + $this->cli->main(['vobject', 'color', 'a', 'b', 'c']) + ); + } + + public function testUnknownCommand() + { + $this->assertEquals( + 1, + $this->cli->main(['vobject', 'foo', '-']) + ); + } + + public function testConvertJson() + { + $inputStream = fopen('php://memory', 'r+'); + + fwrite($inputStream, <<<ICS +BEGIN:VCARD +VERSION:3.0 +FN:Cowboy Henk +END:VCARD +ICS + ); + rewind($inputStream); + $this->cli->stdin = $inputStream; + + $this->assertEquals( + 0, + $this->cli->main(['vobject', 'convert', '--format=json', '-']) + ); + + rewind($this->cli->stdout); + $version = Version::VERSION; + $this->assertEquals( + '["vcard",[["version",{},"text","4.0"],["prodid",{},"text","-\/\/Sabre\/\/Sabre VObject '.$version.'\/\/EN"],["fn",{},"text","Cowboy Henk"]]]', + stream_get_contents($this->cli->stdout) + ); + } + + public function testConvertJCardPretty() + { + if (version_compare(PHP_VERSION, '5.4.0') < 0) { + $this->markTestSkipped('This test required PHP 5.4.0'); + } + + $inputStream = fopen('php://memory', 'r+'); + + fwrite($inputStream, <<<ICS +BEGIN:VCARD +VERSION:3.0 +FN:Cowboy Henk +END:VCARD +ICS + ); + rewind($inputStream); + $this->cli->stdin = $inputStream; + + $this->assertEquals( + 0, + $this->cli->main(['vobject', 'convert', '--format=jcard', '--pretty', '-']) + ); + + rewind($this->cli->stdout); + + // PHP 5.5.12 changed the output + + $expected = <<<JCARD +[ + "vcard", + [ + [ + "versi +JCARD; + + $this->assertStringStartsWith( + $expected, + stream_get_contents($this->cli->stdout) + ); + } + + public function testConvertJCalFail() + { + $inputStream = fopen('php://memory', 'r+'); + + fwrite($inputStream, <<<ICS +BEGIN:VCARD +VERSION:3.0 +FN:Cowboy Henk +END:VCARD +ICS + ); + rewind($inputStream); + $this->cli->stdin = $inputStream; + + $this->assertEquals( + 2, + $this->cli->main(['vobject', 'convert', '--format=jcal', '--inputformat=mimedir', '-']) + ); + } + + public function testConvertMimeDir() + { + $inputStream = fopen('php://memory', 'r+'); + + fwrite($inputStream, <<<JCARD +[ + "vcard", + [ + [ + "version", + { + + }, + "text", + "4.0" + ], + [ + "prodid", + { + + }, + "text", + "-\/\/Sabre\/\/Sabre VObject 3.1.0\/\/EN" + ], + [ + "fn", + { + + }, + "text", + "Cowboy Henk" + ] + ] +] +JCARD + ); + rewind($inputStream); + $this->cli->stdin = $inputStream; + + $this->assertEquals( + 0, + $this->cli->main(['vobject', 'convert', '--format=mimedir', '--inputformat=json', '--pretty', '-']) + ); + + rewind($this->cli->stdout); + $expected = <<<VCF +BEGIN:VCARD +VERSION:4.0 +PRODID:-//Sabre//Sabre VObject 3.1.0//EN +FN:Cowboy Henk +END:VCARD + +VCF; + + $this->assertEquals( + strtr($expected, ["\n" => "\r\n"]), + stream_get_contents($this->cli->stdout) + ); + } + + public function testConvertDefaultFormats() + { + $outputFile = SABRE_TEMPDIR.'bar.json'; + + $this->assertEquals( + 2, + $this->cli->main(['vobject', 'convert', 'foo.json', $outputFile]) + ); + + $this->assertEquals('json', $this->cli->inputFormat); + $this->assertEquals('json', $this->cli->format); + } + + public function testConvertDefaultFormats2() + { + $outputFile = SABRE_TEMPDIR.'bar.ics'; + + $this->assertEquals( + 2, + $this->cli->main(['vobject', 'convert', 'foo.ics', $outputFile]) + ); + + $this->assertEquals('mimedir', $this->cli->inputFormat); + $this->assertEquals('mimedir', $this->cli->format); + } + + public function testVCard3040() + { + $inputStream = fopen('php://memory', 'r+'); + + fwrite($inputStream, <<<VCARD +BEGIN:VCARD +VERSION:3.0 +PRODID:-//Sabre//Sabre VObject 3.1.0//EN +FN:Cowboy Henk +END:VCARD + +VCARD + ); + rewind($inputStream); + $this->cli->stdin = $inputStream; + + $this->assertEquals( + 0, + $this->cli->main(['vobject', 'convert', '--format=vcard40', '--pretty', '-']) + ); + + rewind($this->cli->stdout); + + $version = Version::VERSION; + $expected = <<<VCF +BEGIN:VCARD +VERSION:4.0 +PRODID:-//Sabre//Sabre VObject $version//EN +FN:Cowboy Henk +END:VCARD + +VCF; + + $this->assertEquals( + strtr($expected, ["\n" => "\r\n"]), + stream_get_contents($this->cli->stdout) + ); + } + + public function testVCard4030() + { + $inputStream = fopen('php://memory', 'r+'); + + fwrite($inputStream, <<<VCARD +BEGIN:VCARD +VERSION:4.0 +PRODID:-//Sabre//Sabre VObject 3.1.0//EN +FN:Cowboy Henk +END:VCARD + +VCARD + ); + rewind($inputStream); + $this->cli->stdin = $inputStream; + + $this->assertEquals( + 0, + $this->cli->main(['vobject', 'convert', '--format=vcard30', '--pretty', '-']) + ); + + $version = Version::VERSION; + + rewind($this->cli->stdout); + $expected = <<<VCF +BEGIN:VCARD +VERSION:3.0 +PRODID:-//Sabre//Sabre VObject $version//EN +FN:Cowboy Henk +END:VCARD + +VCF; + + $this->assertEquals( + strtr($expected, ["\n" => "\r\n"]), + stream_get_contents($this->cli->stdout) + ); + } + + public function testVCard4021() + { + $inputStream = fopen('php://memory', 'r+'); + + fwrite($inputStream, <<<VCARD +BEGIN:VCARD +VERSION:4.0 +PRODID:-//Sabre//Sabre VObject 3.1.0//EN +FN:Cowboy Henk +END:VCARD + +VCARD + ); + rewind($inputStream); + $this->cli->stdin = $inputStream; + + $this->assertEquals( + 2, + $this->cli->main(['vobject', 'convert', '--format=vcard21', '--pretty', '-']) + ); + } + + public function testValidate() + { + $inputStream = fopen('php://memory', 'r+'); + + fwrite($inputStream, <<<VCARD +BEGIN:VCARD +VERSION:4.0 +PRODID:-//Sabre//Sabre VObject 3.1.0//EN +UID:foo +FN:Cowboy Henk +END:VCARD + +VCARD + ); + rewind($inputStream); + $this->cli->stdin = $inputStream; + $result = $this->cli->main(['vobject', 'validate', '-']); + + $this->assertEquals( + 0, + $result + ); + } + + public function testValidateFail() + { + $inputStream = fopen('php://memory', 'r+'); + + fwrite($inputStream, <<<VCARD +BEGIN:VCALENDAR +VERSION:2.0 +END:VCARD + +VCARD + ); + rewind($inputStream); + $this->cli->stdin = $inputStream; + // vCard 2.0 is not supported yet, so this returns a failure. + $this->assertEquals( + 2, + $this->cli->main(['vobject', 'validate', '-']) + ); + } + + public function testValidateFail2() + { + $inputStream = fopen('php://memory', 'r+'); + + fwrite($inputStream, <<<VCARD +BEGIN:VCALENDAR +VERSION:5.0 +END:VCALENDAR + +VCARD + ); + rewind($inputStream); + $this->cli->stdin = $inputStream; + + $this->assertEquals( + 2, + $this->cli->main(['vobject', 'validate', '-']) + ); + } + + public function testRepair() + { + $inputStream = fopen('php://memory', 'r+'); + + fwrite($inputStream, <<<VCARD +BEGIN:VCARD +VERSION:5.0 +END:VCARD + +VCARD + ); + rewind($inputStream); + $this->cli->stdin = $inputStream; + + $this->assertEquals( + 2, + $this->cli->main(['vobject', 'repair', '-']) + ); + + rewind($this->cli->stdout); + $this->assertRegExp("/^BEGIN:VCARD\r\nVERSION:2.1\r\nUID:[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\r\nEND:VCARD\r\n$/", stream_get_contents($this->cli->stdout)); + } + + public function testRepairNothing() + { + $inputStream = fopen('php://memory', 'r+'); + + fwrite($inputStream, <<<VCARD +BEGIN:VCALENDAR +VERSION:2.0 +PRODID:-//Sabre//Sabre VObject 3.1.0//EN +BEGIN:VEVENT +UID:foo +DTSTAMP:20140122T233226Z +DTSTART:20140101T120000Z +END:VEVENT +END:VCALENDAR + +VCARD + ); + rewind($inputStream); + $this->cli->stdin = $inputStream; + + $result = $this->cli->main(['vobject', 'repair', '-']); + + rewind($this->cli->stderr); + $error = stream_get_contents($this->cli->stderr); + + $this->assertEquals( + 0, + $result, + "This should have been error free. stderr output:\n".$error + ); + } + + /** + * Note: this is a very shallow test, doesn't dig into the actual output, + * but just makes sure there's no errors thrown. + * + * The colorizer is not a critical component, it's mostly a debugging tool. + */ + public function testColorCalendar() + { + $inputStream = fopen('php://memory', 'r+'); + + $version = Version::VERSION; + + /* + * This object is not valid, but it's designed to hit every part of the + * colorizer source. + */ + fwrite($inputStream, <<<VCARD +BEGIN:VCALENDAR +VERSION:2.0 +PRODID:-//Sabre//Sabre VObject {$version}//EN +BEGIN:VTIMEZONE +END:VTIMEZONE +BEGIN:VEVENT +ATTENDEE;RSVP=TRUE:mailto:foo@example.org +REQUEST-STATUS:5;foo +ATTACH:blabla +END:VEVENT +END:VCALENDAR + +VCARD + ); + rewind($inputStream); + $this->cli->stdin = $inputStream; + + $result = $this->cli->main(['vobject', 'color', '-']); + + rewind($this->cli->stderr); + $error = stream_get_contents($this->cli->stderr); + + $this->assertEquals( + 0, + $result, + "This should have been error free. stderr output:\n".$error + ); + } + + /** + * Note: this is a very shallow test, doesn't dig into the actual output, + * but just makes sure there's no errors thrown. + * + * The colorizer is not a critical component, it's mostly a debugging tool. + */ + public function testColorVCard() + { + $inputStream = fopen('php://memory', 'r+'); + + $version = Version::VERSION; + + /* + * This object is not valid, but it's designed to hit every part of the + * colorizer source. + */ + fwrite($inputStream, <<<VCARD +BEGIN:VCARD +VERSION:4.0 +PRODID:-//Sabre//Sabre VObject {$version}//EN +ADR:1;2;3;4a,4b;5;6 +group.TEL:123454768 +END:VCARD + +VCARD + ); + rewind($inputStream); + $this->cli->stdin = $inputStream; + + $result = $this->cli->main(['vobject', 'color', '-']); + + rewind($this->cli->stderr); + $error = stream_get_contents($this->cli->stderr); + + $this->assertEquals( + 0, + $result, + "This should have been error free. stderr output:\n".$error + ); + } +} + +class CliMock extends Cli +{ + public $quiet = false; + + public $format; + + public $pretty; + + public $stdin; + + public $stdout; + + public $stderr; + + public $inputFormat; + + public $outputFormat; +} diff --git a/vendor/sabre/vobject/tests/VObject/Component/AvailableTest.php b/vendor/sabre/vobject/tests/VObject/Component/AvailableTest.php new file mode 100644 index 000000000..55292424e --- /dev/null +++ b/vendor/sabre/vobject/tests/VObject/Component/AvailableTest.php @@ -0,0 +1,71 @@ +<?php + +namespace Sabre\VObject\Component; + +use DateTimeImmutable; +use DateTimeZone; +use PHPUnit\Framework\TestCase; +use Sabre\VObject\Reader; + +/** + * We use `RFCxxx` has a placeholder for the + * https://tools.ietf.org/html/draft-daboo-calendar-availability-05 name. + */ +class AvailableTest extends TestCase +{ + public function testAvailableComponent() + { + $vcal = <<<VCAL +BEGIN:VCALENDAR +BEGIN:AVAILABLE +END:AVAILABLE +END:VCALENDAR +VCAL; + $document = Reader::read($vcal); + $this->assertInstanceOf(__NAMESPACE__.'\Available', $document->AVAILABLE); + } + + public function testGetEffectiveStartEnd() + { + $vcal = <<<VCAL +BEGIN:VCALENDAR +BEGIN:AVAILABLE +DTSTART:20150717T162200Z +DTEND:20150717T172200Z +END:AVAILABLE +END:VCALENDAR +VCAL; + + $document = Reader::read($vcal); + $tz = new DateTimeZone('UTC'); + $this->assertEquals( + [ + new DateTimeImmutable('2015-07-17 16:22:00', $tz), + new DateTimeImmutable('2015-07-17 17:22:00', $tz), + ], + $document->AVAILABLE->getEffectiveStartEnd() + ); + } + + public function testGetEffectiveStartEndDuration() + { + $vcal = <<<VCAL +BEGIN:VCALENDAR +BEGIN:AVAILABLE +DTSTART:20150717T162200Z +DURATION:PT1H +END:AVAILABLE +END:VCALENDAR +VCAL; + + $document = Reader::read($vcal); + $tz = new DateTimeZone('UTC'); + $this->assertEquals( + [ + new DateTimeImmutable('2015-07-17 16:22:00', $tz), + new DateTimeImmutable('2015-07-17 17:22:00', $tz), + ], + $document->AVAILABLE->getEffectiveStartEnd() + ); + } +} diff --git a/vendor/sabre/vobject/tests/VObject/Component/VAlarmTest.php b/vendor/sabre/vobject/tests/VObject/Component/VAlarmTest.php new file mode 100644 index 000000000..1e7a55ad7 --- /dev/null +++ b/vendor/sabre/vobject/tests/VObject/Component/VAlarmTest.php @@ -0,0 +1,172 @@ +<?php + +namespace Sabre\VObject\Component; + +use DateTime; +use PHPUnit\Framework\TestCase; +use Sabre\VObject\Reader; + +class VAlarmTest extends TestCase +{ + /** + * @dataProvider timeRangeTestData + */ + public function testInTimeRange(VAlarm $valarm, $start, $end, $outcome) + { + $this->assertEquals($outcome, $valarm->isInTimeRange($start, $end)); + } + + public function timeRangeTestData() + { + $tests = []; + + $calendar = new VCalendar(); + + // Hard date and time + $valarm1 = $calendar->createComponent('VALARM'); + $valarm1->add( + $calendar->createProperty('TRIGGER', '20120312T130000Z', ['VALUE' => 'DATE-TIME']) + ); + + $tests[] = [$valarm1, new DateTime('2012-03-01 01:00:00'), new DateTime('2012-04-01 01:00:00'), true]; + $tests[] = [$valarm1, new DateTime('2012-03-01 01:00:00'), new DateTime('2012-03-10 01:00:00'), false]; + + // Relation to start time of event + $valarm2 = $calendar->createComponent('VALARM'); + $valarm2->add( + $calendar->createProperty('TRIGGER', '-P1D', ['VALUE' => 'DURATION']) + ); + + $vevent2 = $calendar->createComponent('VEVENT'); + $vevent2->DTSTART = '20120313T130000Z'; + $vevent2->add($valarm2); + + $tests[] = [$valarm2, new DateTime('2012-03-01 01:00:00'), new DateTime('2012-04-01 01:00:00'), true]; + $tests[] = [$valarm2, new DateTime('2012-03-01 01:00:00'), new DateTime('2012-03-10 01:00:00'), false]; + + // Relation to end time of event + $valarm3 = $calendar->createComponent('VALARM'); + $valarm3->add($calendar->createProperty('TRIGGER', '-P1D', ['VALUE' => 'DURATION', 'RELATED' => 'END'])); + + $vevent3 = $calendar->createComponent('VEVENT'); + $vevent3->DTSTART = '20120301T130000Z'; + $vevent3->DTEND = '20120401T130000Z'; + $vevent3->add($valarm3); + + $tests[] = [$valarm3, new DateTime('2012-02-25 01:00:00'), new DateTime('2012-03-05 01:00:00'), false]; + $tests[] = [$valarm3, new DateTime('2012-03-25 01:00:00'), new DateTime('2012-04-05 01:00:00'), true]; + + // Relation to end time of todo + $valarm4 = $calendar->createComponent('VALARM'); + $valarm4->TRIGGER = '-P1D'; + $valarm4->TRIGGER['VALUE'] = 'DURATION'; + $valarm4->TRIGGER['RELATED'] = 'END'; + + $vtodo4 = $calendar->createComponent('VTODO'); + $vtodo4->DTSTART = '20120301T130000Z'; + $vtodo4->DUE = '20120401T130000Z'; + $vtodo4->add($valarm4); + + $tests[] = [$valarm4, new DateTime('2012-02-25 01:00:00'), new DateTime('2012-03-05 01:00:00'), false]; + $tests[] = [$valarm4, new DateTime('2012-03-25 01:00:00'), new DateTime('2012-04-05 01:00:00'), true]; + + // Relation to start time of event + repeat + $valarm5 = $calendar->createComponent('VALARM'); + $valarm5->TRIGGER = '-P1D'; + $valarm5->TRIGGER['VALUE'] = 'DURATION'; + $valarm5->REPEAT = 10; + $valarm5->DURATION = 'P1D'; + + $vevent5 = $calendar->createComponent('VEVENT'); + $vevent5->DTSTART = '20120301T130000Z'; + $vevent5->add($valarm5); + + $tests[] = [$valarm5, new DateTime('2012-03-09 01:00:00'), new DateTime('2012-03-10 01:00:00'), true]; + + // Relation to start time of event + duration, but no repeat + $valarm6 = $calendar->createComponent('VALARM'); + $valarm6->TRIGGER = '-P1D'; + $valarm6->TRIGGER['VALUE'] = 'DURATION'; + $valarm6->DURATION = 'P1D'; + + $vevent6 = $calendar->createComponent('VEVENT'); + $vevent6->DTSTART = '20120313T130000Z'; + $vevent6->add($valarm6); + + $tests[] = [$valarm6, new DateTime('2012-03-01 01:00:00'), new DateTime('2012-04-01 01:00:00'), true]; + $tests[] = [$valarm6, new DateTime('2012-03-01 01:00:00'), new DateTime('2012-03-10 01:00:00'), false]; + + // Relation to end time of event (DURATION instead of DTEND) + $valarm7 = $calendar->createComponent('VALARM'); + $valarm7->TRIGGER = '-P1D'; + $valarm7->TRIGGER['VALUE'] = 'DURATION'; + $valarm7->TRIGGER['RELATED'] = 'END'; + + $vevent7 = $calendar->createComponent('VEVENT'); + $vevent7->DTSTART = '20120301T130000Z'; + $vevent7->DURATION = 'P30D'; + $vevent7->add($valarm7); + + $tests[] = [$valarm7, new DateTime('2012-02-25 01:00:00'), new DateTime('2012-03-05 01:00:00'), false]; + $tests[] = [$valarm7, new DateTime('2012-03-25 01:00:00'), new DateTime('2012-04-05 01:00:00'), true]; + + // Relation to end time of event (No DTEND or DURATION) + $valarm7 = $calendar->createComponent('VALARM'); + $valarm7->TRIGGER = '-P1D'; + $valarm7->TRIGGER['VALUE'] = 'DURATION'; + $valarm7->TRIGGER['RELATED'] = 'END'; + + $vevent7 = $calendar->createComponent('VEVENT'); + $vevent7->DTSTART = '20120301T130000Z'; + $vevent7->add($valarm7); + + $tests[] = [$valarm7, new DateTime('2012-02-25 01:00:00'), new DateTime('2012-03-05 01:00:00'), true]; + $tests[] = [$valarm7, new DateTime('2012-03-25 01:00:00'), new DateTime('2012-04-05 01:00:00'), false]; + + return $tests; + } + + /** + * @expectedException \Sabre\VObject\InvalidDataException + */ + public function testInTimeRangeInvalidComponent() + { + $calendar = new VCalendar(); + $valarm = $calendar->createComponent('VALARM'); + $valarm->TRIGGER = '-P1D'; + $valarm->TRIGGER['RELATED'] = 'END'; + + $vjournal = $calendar->createComponent('VJOURNAL'); + $vjournal->add($valarm); + + $valarm->isInTimeRange(new DateTime('2012-02-25 01:00:00'), new DateTime('2012-03-05 01:00:00')); + } + + /** + * This bug was found and reported on the mailing list. + */ + public function testInTimeRangeBuggy() + { + $input = <<<BLA +BEGIN:VCALENDAR +BEGIN:VTODO +DTSTAMP:20121003T064931Z +UID:b848cb9a7bb16e464a06c222ca1f8102@examle.com +STATUS:NEEDS-ACTION +DUE:20121005T000000Z +SUMMARY:Task 1 +CATEGORIES:AlarmCategory +BEGIN:VALARM +TRIGGER:-PT10M +ACTION:DISPLAY +DESCRIPTION:Task 1 +END:VALARM +END:VTODO +END:VCALENDAR +BLA; + + $vobj = Reader::read($input); + + $this->assertTrue($vobj->VTODO->VALARM->isInTimeRange(new \DateTime('2012-10-01 00:00:00'), new \DateTime('2012-11-01 00:00:00'))); + } +} diff --git a/vendor/sabre/vobject/tests/VObject/Component/VAvailabilityTest.php b/vendor/sabre/vobject/tests/VObject/Component/VAvailabilityTest.php new file mode 100644 index 000000000..b6b9a2b80 --- /dev/null +++ b/vendor/sabre/vobject/tests/VObject/Component/VAvailabilityTest.php @@ -0,0 +1,474 @@ +<?php + +namespace Sabre\VObject\Component; + +use DateTimeImmutable; +use DateTimeZone; +use PHPUnit\Framework\TestCase; +use Sabre\VObject; +use Sabre\VObject\Reader; + +/** + * We use `RFCxxx` has a placeholder for the + * https://tools.ietf.org/html/draft-daboo-calendar-availability-05 name. + */ +class VAvailabilityTest extends TestCase +{ + public function testVAvailabilityComponent() + { + $vcal = <<<VCAL +BEGIN:VCALENDAR +BEGIN:VAVAILABILITY +END:VAVAILABILITY +END:VCALENDAR +VCAL; + $document = Reader::read($vcal); + + $this->assertInstanceOf(__NAMESPACE__.'\VAvailability', $document->VAVAILABILITY); + } + + public function testGetEffectiveStartEnd() + { + $vcal = <<<VCAL +BEGIN:VCALENDAR +BEGIN:VAVAILABILITY +DTSTART:20150717T162200Z +DTEND:20150717T172200Z +END:VAVAILABILITY +END:VCALENDAR +VCAL; + + $document = Reader::read($vcal); + $tz = new DateTimeZone('UTC'); + $this->assertEquals( + [ + new DateTimeImmutable('2015-07-17 16:22:00', $tz), + new DateTimeImmutable('2015-07-17 17:22:00', $tz), + ], + $document->VAVAILABILITY->getEffectiveStartEnd() + ); + } + + public function testGetEffectiveStartDuration() + { + $vcal = <<<VCAL +BEGIN:VCALENDAR +BEGIN:VAVAILABILITY +DTSTART:20150717T162200Z +DURATION:PT1H +END:VAVAILABILITY +END:VCALENDAR +VCAL; + + $document = Reader::read($vcal); + $tz = new DateTimeZone('UTC'); + $this->assertEquals( + [ + new DateTimeImmutable('2015-07-17 16:22:00', $tz), + new DateTimeImmutable('2015-07-17 17:22:00', $tz), + ], + $document->VAVAILABILITY->getEffectiveStartEnd() + ); + } + + public function testGetEffectiveStartEndUnbound() + { + $vcal = <<<VCAL +BEGIN:VCALENDAR +BEGIN:VAVAILABILITY +END:VAVAILABILITY +END:VCALENDAR +VCAL; + + $document = Reader::read($vcal); + $this->assertEquals( + [ + null, + null, + ], + $document->VAVAILABILITY->getEffectiveStartEnd() + ); + } + + public function testIsInTimeRangeUnbound() + { + $vcal = <<<VCAL +BEGIN:VCALENDAR +BEGIN:VAVAILABILITY +END:VAVAILABILITY +END:VCALENDAR +VCAL; + + $document = Reader::read($vcal); + $this->assertTrue( + $document->VAVAILABILITY->isInTimeRange(new DateTimeImmutable('2015-07-17'), new DateTimeImmutable('2015-07-18')) + ); + } + + public function testIsInTimeRangeOutside() + { + $vcal = <<<VCAL +BEGIN:VCALENDAR +BEGIN:VAVAILABILITY +DTSTART:20140101T000000Z +DTEND:20140102T000000Z +END:VAVAILABILITY +END:VCALENDAR +VCAL; + + $document = Reader::read($vcal); + $this->assertFalse( + $document->VAVAILABILITY->isInTimeRange(new DateTimeImmutable('2015-07-17'), new DateTimeImmutable('2015-07-18')) + ); + } + + public function testRFCxxxSection3_1_availabilityprop_required() + { + // UID and DTSTAMP are present. + $this->assertIsValid(Reader::read( +<<<VCAL +BEGIN:VCALENDAR +VERSION:2.0 +PRODID:-//id +BEGIN:VAVAILABILITY +UID:foo@test +DTSTAMP:20111005T133225Z +END:VAVAILABILITY +END:VCALENDAR +VCAL + )); + + // UID and DTSTAMP are missing. + $this->assertIsNotValid(Reader::read( +<<<VCAL +BEGIN:VCALENDAR +VERSION:2.0 +PRODID:-//id +BEGIN:VAVAILABILITY +END:VAVAILABILITY +END:VCALENDAR +VCAL + )); + + // DTSTAMP is missing. + $this->assertIsNotValid(Reader::read( +<<<VCAL +BEGIN:VCALENDAR +VERSION:2.0 +PRODID:-//id +BEGIN:VAVAILABILITY +UID:foo@test +END:VAVAILABILITY +END:VCALENDAR +VCAL + )); + + // UID is missing. + $this->assertIsNotValid(Reader::read( +<<<VCAL +BEGIN:VCALENDAR +VERSION:2.0 +PRODID:-//id +BEGIN:VAVAILABILITY +DTSTAMP:20111005T133225Z +END:VAVAILABILITY +END:VCALENDAR +VCAL + )); + } + + public function testRFCxxxSection3_1_availabilityprop_optional_once() + { + $properties = [ + 'BUSYTYPE:BUSY', + 'CLASS:PUBLIC', + 'CREATED:20111005T135125Z', + 'DESCRIPTION:Long bla bla', + 'DTSTART:20111005T020000', + 'LAST-MODIFIED:20111005T135325Z', + 'ORGANIZER:mailto:foo@example.com', + 'PRIORITY:1', + 'SEQUENCE:0', + 'SUMMARY:Bla bla', + 'URL:http://example.org/', + ]; + + // They are all present, only once. + $this->assertIsValid(Reader::read($this->template($properties))); + + // We duplicate each one to see if it fails. + foreach ($properties as $property) { + $this->assertIsNotValid(Reader::read($this->template([ + $property, + $property, + ]))); + } + } + + public function testRFCxxxSection3_1_availabilityprop_dtend_duration() + { + // Only DTEND. + $this->assertIsValid(Reader::read($this->template([ + 'DTEND:21111005T133225Z', + ]))); + + // Only DURATION. + $this->assertIsValid(Reader::read($this->template([ + 'DURATION:PT1H', + ]))); + + // Both (not allowed). + $this->assertIsNotValid(Reader::read($this->template([ + 'DTEND:21111005T133225Z', + 'DURATION:PT1H', + ]))); + } + + public function testAvailableSubComponent() + { + $vcal = <<<VCAL +BEGIN:VCALENDAR +BEGIN:VAVAILABILITY +BEGIN:AVAILABLE +END:AVAILABLE +END:VAVAILABILITY +END:VCALENDAR +VCAL; + $document = Reader::read($vcal); + + $this->assertInstanceOf(__NAMESPACE__, $document->VAVAILABILITY->AVAILABLE); + } + + public function testRFCxxxSection3_1_availableprop_required() + { + // UID, DTSTAMP and DTSTART are present. + $this->assertIsValid(Reader::read( +<<<VCAL +BEGIN:VCALENDAR +VERSION:2.0 +PRODID:-//id +BEGIN:VAVAILABILITY +UID:foo@test +DTSTAMP:20111005T133225Z +BEGIN:AVAILABLE +UID:foo@test +DTSTAMP:20111005T133225Z +DTSTART:20111005T133225Z +END:AVAILABLE +END:VAVAILABILITY +END:VCALENDAR +VCAL + )); + + // UID, DTSTAMP and DTSTART are missing. + $this->assertIsNotValid(Reader::read( +<<<VCAL +BEGIN:VCALENDAR +VERSION:2.0 +PRODID:-//id +BEGIN:VAVAILABILITY +UID:foo@test +DTSTAMP:20111005T133225Z +BEGIN:AVAILABLE +END:AVAILABLE +END:VAVAILABILITY +END:VCALENDAR +VCAL + )); + + // UID is missing. + $this->assertIsNotValid(Reader::read( +<<<VCAL +BEGIN:VCALENDAR +VERSION:2.0 +PRODID:-//id +BEGIN:VAVAILABILITY +UID:foo@test +DTSTAMP:20111005T133225Z +BEGIN:AVAILABLE +DTSTAMP:20111005T133225Z +DTSTART:20111005T133225Z +END:AVAILABLE +END:VAVAILABILITY +END:VCALENDAR +VCAL + )); + + // DTSTAMP is missing. + $this->assertIsNotValid(Reader::read( +<<<VCAL +BEGIN:VCALENDAR +VERSION:2.0 +PRODID:-//id +BEGIN:VAVAILABILITY +UID:foo@test +DTSTAMP:20111005T133225Z +BEGIN:AVAILABLE +UID:foo@test +DTSTART:20111005T133225Z +END:AVAILABLE +END:VAVAILABILITY +END:VCALENDAR +VCAL + )); + + // DTSTART is missing. + $this->assertIsNotValid(Reader::read( +<<<VCAL +BEGIN:VCALENDAR +VERSION:2.0 +PRODID:-//id +BEGIN:VAVAILABILITY +UID:foo@test +DTSTAMP:20111005T133225Z +BEGIN:AVAILABLE +UID:foo@test +DTSTAMP:20111005T133225Z +END:AVAILABLE +END:VAVAILABILITY +END:VCALENDAR +VCAL + )); + } + + public function testRFCxxxSection3_1_available_dtend_duration() + { + // Only DTEND. + $this->assertIsValid(Reader::read($this->templateAvailable([ + 'DTEND:21111005T133225Z', + ]))); + + // Only DURATION. + $this->assertIsValid(Reader::read($this->templateAvailable([ + 'DURATION:PT1H', + ]))); + + // Both (not allowed). + $this->assertIsNotValid(Reader::read($this->templateAvailable([ + 'DTEND:21111005T133225Z', + 'DURATION:PT1H', + ]))); + } + + public function testRFCxxxSection3_1_available_optional_once() + { + $properties = [ + 'CREATED:20111005T135125Z', + 'DESCRIPTION:Long bla bla', + 'LAST-MODIFIED:20111005T135325Z', + 'RECURRENCE-ID;RANGE=THISANDFUTURE:19980401T133000Z', + 'RRULE:FREQ=WEEKLY;BYDAY=MO,TU,WE,TH,FR', + 'SUMMARY:Bla bla', + ]; + + // They are all present, only once. + $this->assertIsValid(Reader::read($this->templateAvailable($properties))); + + // We duplicate each one to see if it fails. + foreach ($properties as $property) { + $this->assertIsNotValid(Reader::read($this->templateAvailable([ + $property, + $property, + ]))); + } + } + + public function testRFCxxxSection3_2() + { + $this->assertEquals( + 'BUSY', + Reader::read($this->templateAvailable([ + 'BUSYTYPE:BUSY', + ])) + ->VAVAILABILITY + ->AVAILABLE + ->BUSYTYPE + ->getValue() + ); + + $this->assertEquals( + 'BUSY-UNAVAILABLE', + Reader::read($this->templateAvailable([ + 'BUSYTYPE:BUSY-UNAVAILABLE', + ])) + ->VAVAILABILITY + ->AVAILABLE + ->BUSYTYPE + ->getValue() + ); + + $this->assertEquals( + 'BUSY-TENTATIVE', + Reader::read($this->templateAvailable([ + 'BUSYTYPE:BUSY-TENTATIVE', + ])) + ->VAVAILABILITY + ->AVAILABLE + ->BUSYTYPE + ->getValue() + ); + } + + protected function assertIsValid(VObject\Document $document) + { + $validationResult = $document->validate(); + if ($validationResult) { + $messages = array_map(function ($item) { return $item['message']; }, $validationResult); + $this->fail('Failed to assert that the supplied document is a valid document. Validation messages: '.implode(', ', $messages)); + } + $this->assertEmpty($document->validate()); + } + + protected function assertIsNotValid(VObject\Document $document) + { + $this->assertNotEmpty($document->validate()); + } + + protected function template(array $properties) + { + return $this->_template( + <<<VCAL +BEGIN:VCALENDAR +VERSION:2.0 +PRODID:-//id +BEGIN:VAVAILABILITY +UID:foo@test +DTSTAMP:20111005T133225Z +… +END:VAVAILABILITY +END:VCALENDAR +VCAL +, + $properties + ); + } + + protected function templateAvailable(array $properties) + { + return $this->_template( + <<<VCAL +BEGIN:VCALENDAR +VERSION:2.0 +PRODID:-//id +BEGIN:VAVAILABILITY +UID:foo@test +DTSTAMP:20111005T133225Z +BEGIN:AVAILABLE +UID:foo@test +DTSTAMP:20111005T133225Z +DTSTART:20111005T133225Z +… +END:AVAILABLE +END:VAVAILABILITY +END:VCALENDAR +VCAL +, + $properties + ); + } + + protected function _template($template, array $properties) + { + return str_replace('…', implode("\r\n", $properties), $template); + } +} diff --git a/vendor/sabre/vobject/tests/VObject/Component/VCalendarTest.php b/vendor/sabre/vobject/tests/VObject/Component/VCalendarTest.php new file mode 100644 index 000000000..dbf2fef0a --- /dev/null +++ b/vendor/sabre/vobject/tests/VObject/Component/VCalendarTest.php @@ -0,0 +1,758 @@ +<?php + +namespace Sabre\VObject\Component; + +use DateTimeZone; +use PHPUnit\Framework\TestCase; +use Sabre\VObject; + +class VCalendarTest extends TestCase +{ + use VObject\PHPUnitAssertions; + + /** + * @dataProvider expandData + */ + public function testExpand($input, $output, $timeZone = 'UTC', $start = '2011-12-01', $end = '2011-12-31') + { + $vcal = VObject\Reader::read($input); + + $timeZone = new DateTimeZone($timeZone); + + $vcal = $vcal->expand( + new \DateTime($start), + new \DateTime($end), + $timeZone + ); + + // This will normalize the output + $output = VObject\Reader::read($output)->serialize(); + + $this->assertVObjectEqualsVObject($output, $vcal->serialize()); + } + + public function expandData() + { + $tests = []; + + // No data + $input = 'BEGIN:VCALENDAR +CALSCALE:GREGORIAN +VERSION:2.0 +END:VCALENDAR +'; + + $output = $input; + $tests[] = [$input, $output]; + + // Simple events + $input = 'BEGIN:VCALENDAR +CALSCALE:GREGORIAN +VERSION:2.0 +BEGIN:VEVENT +UID:bla +SUMMARY:InExpand +DTSTART;VALUE=DATE:20111202 +END:VEVENT +BEGIN:VEVENT +UID:bla2 +SUMMARY:NotInExpand +DTSTART;VALUE=DATE:20120101 +END:VEVENT +END:VCALENDAR +'; + + $output = 'BEGIN:VCALENDAR +CALSCALE:GREGORIAN +VERSION:2.0 +BEGIN:VEVENT +UID:bla +SUMMARY:InExpand +DTSTART;VALUE=DATE:20111202 +END:VEVENT +END:VCALENDAR +'; + + $tests[] = [$input, $output]; + + // Removing timezone info + $input = 'BEGIN:VCALENDAR +CALSCALE:GREGORIAN +VERSION:2.0 +BEGIN:VTIMEZONE +TZID:Europe/Paris +END:VTIMEZONE +BEGIN:VEVENT +UID:bla4 +SUMMARY:RemoveTZ info +DTSTART;TZID=Europe/Paris:20111203T130102 +END:VEVENT +END:VCALENDAR +'; + + $output = 'BEGIN:VCALENDAR +CALSCALE:GREGORIAN +VERSION:2.0 +BEGIN:VEVENT +UID:bla4 +SUMMARY:RemoveTZ info +DTSTART:20111203T120102Z +END:VEVENT +END:VCALENDAR +'; + + $tests[] = [$input, $output]; + + // Removing timezone info from sub-components. See Issue #278 + $input = 'BEGIN:VCALENDAR +CALSCALE:GREGORIAN +VERSION:2.0 +BEGIN:VTIMEZONE +TZID:Europe/Paris +END:VTIMEZONE +BEGIN:VEVENT +UID:bla4 +SUMMARY:RemoveTZ info +DTSTART;TZID=Europe/Paris:20111203T130102 +BEGIN:VALARM +TRIGGER;VALUE=DATE-TIME;TZID=America/New_York:20151209T133200 +END:VALARM +END:VEVENT +END:VCALENDAR +'; + + $output = 'BEGIN:VCALENDAR +CALSCALE:GREGORIAN +VERSION:2.0 +BEGIN:VEVENT +UID:bla4 +SUMMARY:RemoveTZ info +DTSTART:20111203T120102Z +BEGIN:VALARM +TRIGGER;VALUE=DATE-TIME:20151209T183200Z +END:VALARM +END:VEVENT +END:VCALENDAR +'; + + $tests[] = [$input, $output]; + + // Recurrence rule + $input = 'BEGIN:VCALENDAR +CALSCALE:GREGORIAN +VERSION:2.0 +BEGIN:VEVENT +UID:bla6 +SUMMARY:Testing RRule +DTSTART:20111125T120000Z +DTEND:20111125T130000Z +RRULE:FREQ=WEEKLY +END:VEVENT +END:VCALENDAR +'; + + $output = 'BEGIN:VCALENDAR +CALSCALE:GREGORIAN +VERSION:2.0 +BEGIN:VEVENT +UID:bla6 +SUMMARY:Testing RRule +DTSTART:20111202T120000Z +DTEND:20111202T130000Z +RECURRENCE-ID:20111202T120000Z +END:VEVENT +BEGIN:VEVENT +UID:bla6 +SUMMARY:Testing RRule +DTSTART:20111209T120000Z +DTEND:20111209T130000Z +RECURRENCE-ID:20111209T120000Z +END:VEVENT +BEGIN:VEVENT +UID:bla6 +SUMMARY:Testing RRule +DTSTART:20111216T120000Z +DTEND:20111216T130000Z +RECURRENCE-ID:20111216T120000Z +END:VEVENT +BEGIN:VEVENT +UID:bla6 +SUMMARY:Testing RRule +DTSTART:20111223T120000Z +DTEND:20111223T130000Z +RECURRENCE-ID:20111223T120000Z +END:VEVENT +BEGIN:VEVENT +UID:bla6 +SUMMARY:Testing RRule +DTSTART:20111230T120000Z +DTEND:20111230T130000Z +RECURRENCE-ID:20111230T120000Z +END:VEVENT +END:VCALENDAR +'; + + $tests[] = [$input, $output]; + + // Recurrence rule + override + $input = 'BEGIN:VCALENDAR +CALSCALE:GREGORIAN +VERSION:2.0 +BEGIN:VEVENT +UID:bla6 +SUMMARY:Testing RRule2 +DTSTART:20111125T120000Z +DTEND:20111125T130000Z +RRULE:FREQ=WEEKLY +END:VEVENT +BEGIN:VEVENT +UID:bla6 +RECURRENCE-ID:20111209T120000Z +DTSTART:20111209T140000Z +DTEND:20111209T150000Z +SUMMARY:Override! +END:VEVENT +END:VCALENDAR +'; + + $output = 'BEGIN:VCALENDAR +CALSCALE:GREGORIAN +VERSION:2.0 +BEGIN:VEVENT +UID:bla6 +SUMMARY:Testing RRule2 +DTSTART:20111202T120000Z +DTEND:20111202T130000Z +RECURRENCE-ID:20111202T120000Z +END:VEVENT +BEGIN:VEVENT +UID:bla6 +RECURRENCE-ID:20111209T120000Z +DTSTART:20111209T140000Z +DTEND:20111209T150000Z +SUMMARY:Override! +END:VEVENT +BEGIN:VEVENT +UID:bla6 +SUMMARY:Testing RRule2 +DTSTART:20111216T120000Z +DTEND:20111216T130000Z +RECURRENCE-ID:20111216T120000Z +END:VEVENT +BEGIN:VEVENT +UID:bla6 +SUMMARY:Testing RRule2 +DTSTART:20111223T120000Z +DTEND:20111223T130000Z +RECURRENCE-ID:20111223T120000Z +END:VEVENT +BEGIN:VEVENT +UID:bla6 +SUMMARY:Testing RRule2 +DTSTART:20111230T120000Z +DTEND:20111230T130000Z +RECURRENCE-ID:20111230T120000Z +END:VEVENT +END:VCALENDAR +'; + + $tests[] = [$input, $output]; + + // Floating dates and times. + $input = <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +BEGIN:VEVENT +UID:bla1 +DTSTART:20141112T195000 +END:VEVENT +BEGIN:VEVENT +UID:bla2 +DTSTART;VALUE=DATE:20141112 +END:VEVENT +BEGIN:VEVENT +UID:bla3 +DTSTART;VALUE=DATE:20141112 +RRULE:FREQ=DAILY;COUNT=2 +END:VEVENT +END:VCALENDAR +ICS; + + $output = <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +BEGIN:VEVENT +UID:bla1 +DTSTART:20141112T225000Z +END:VEVENT +BEGIN:VEVENT +UID:bla2 +DTSTART;VALUE=DATE:20141112 +END:VEVENT +BEGIN:VEVENT +UID:bla3 +DTSTART;VALUE=DATE:20141112 +RECURRENCE-ID;VALUE=DATE:20141112 +END:VEVENT +BEGIN:VEVENT +UID:bla3 +DTSTART;VALUE=DATE:20141113 +RECURRENCE-ID;VALUE=DATE:20141113 +END:VEVENT +END:VCALENDAR +ICS; + + $tests[] = [$input, $output, 'America/Argentina/Buenos_Aires', '2014-01-01', '2015-01-01']; + + // Recurrence rule with no valid instances + $input = 'BEGIN:VCALENDAR +CALSCALE:GREGORIAN +VERSION:2.0 +BEGIN:VEVENT +UID:bla6 +SUMMARY:Testing RRule3 +DTSTART:20111125T120000Z +DTEND:20111125T130000Z +RRULE:FREQ=WEEKLY;COUNT=1 +EXDATE:20111125T120000Z +END:VEVENT +END:VCALENDAR +'; + + $output = 'BEGIN:VCALENDAR +CALSCALE:GREGORIAN +VERSION:2.0 +END:VCALENDAR +'; + + $tests[] = [$input, $output]; + + return $tests; + } + + /** + * @expectedException \Sabre\VObject\InvalidDataException + */ + public function testBrokenEventExpand() + { + $input = 'BEGIN:VCALENDAR +CALSCALE:GREGORIAN +VERSION:2.0 +BEGIN:VEVENT +RRULE:FREQ=WEEKLY +DTSTART;VALUE=DATE:20111202 +END:VEVENT +END:VCALENDAR +'; + $vcal = VObject\Reader::read($input); + $vcal->expand( + new \DateTime('2011-12-01'), + new \DateTime('2011-12-31') + ); + } + + public function testGetDocumentType() + { + $vcard = new VCalendar(); + $vcard->VERSION = '2.0'; + $this->assertEquals(VCalendar::ICALENDAR20, $vcard->getDocumentType()); + } + + public function testValidateCorrect() + { + $input = 'BEGIN:VCALENDAR +CALSCALE:GREGORIAN +VERSION:2.0 +PRODID:foo +BEGIN:VEVENT +DTSTART;VALUE=DATE:20111202 +DTSTAMP:20140122T233226Z +UID:foo +END:VEVENT +END:VCALENDAR +'; + + $vcal = VObject\Reader::read($input); + $this->assertEquals([], $vcal->validate(), 'Got an error'); + } + + public function testValidateNoVersion() + { + $input = 'BEGIN:VCALENDAR +CALSCALE:GREGORIAN +PRODID:foo +BEGIN:VEVENT +DTSTART;VALUE=DATE:20111202 +UID:foo +DTSTAMP:20140122T234434Z +END:VEVENT +END:VCALENDAR +'; + + $vcal = VObject\Reader::read($input); + $this->assertEquals(1, count($vcal->validate())); + } + + public function testValidateWrongVersion() + { + $input = 'BEGIN:VCALENDAR +CALSCALE:GREGORIAN +VERSION:3.0 +PRODID:foo +BEGIN:VEVENT +DTSTART;VALUE=DATE:20111202 +UID:foo +DTSTAMP:20140122T234434Z +END:VEVENT +END:VCALENDAR +'; + + $vcal = VObject\Reader::read($input); + $this->assertEquals(1, count($vcal->validate())); + } + + public function testValidateNoProdId() + { + $input = 'BEGIN:VCALENDAR +CALSCALE:GREGORIAN +VERSION:2.0 +BEGIN:VEVENT +DTSTART;VALUE=DATE:20111202 +UID:foo +DTSTAMP:20140122T234434Z +END:VEVENT +END:VCALENDAR +'; + + $vcal = VObject\Reader::read($input); + $this->assertEquals(1, count($vcal->validate())); + } + + public function testValidateDoubleCalScale() + { + $input = 'BEGIN:VCALENDAR +VERSION:2.0 +PRODID:foo +CALSCALE:GREGORIAN +CALSCALE:GREGORIAN +BEGIN:VEVENT +DTSTART;VALUE=DATE:20111202 +UID:foo +DTSTAMP:20140122T234434Z +END:VEVENT +END:VCALENDAR +'; + + $vcal = VObject\Reader::read($input); + $this->assertEquals(1, count($vcal->validate())); + } + + public function testValidateDoubleMethod() + { + $input = 'BEGIN:VCALENDAR +VERSION:2.0 +PRODID:foo +METHOD:REQUEST +METHOD:REQUEST +BEGIN:VEVENT +DTSTART;VALUE=DATE:20111202 +UID:foo +DTSTAMP:20140122T234434Z +END:VEVENT +END:VCALENDAR +'; + + $vcal = VObject\Reader::read($input); + $this->assertEquals(1, count($vcal->validate())); + } + + public function testValidateTwoMasterEvents() + { + $input = 'BEGIN:VCALENDAR +VERSION:2.0 +PRODID:foo +METHOD:REQUEST +BEGIN:VEVENT +DTSTART;VALUE=DATE:20111202 +UID:foo +DTSTAMP:20140122T234434Z +END:VEVENT +BEGIN:VEVENT +DTSTART;VALUE=DATE:20111202 +UID:foo +DTSTAMP:20140122T234434Z +END:VEVENT +END:VCALENDAR +'; + + $vcal = VObject\Reader::read($input); + $this->assertEquals(1, count($vcal->validate())); + } + + public function testValidateOneMasterEvent() + { + $input = 'BEGIN:VCALENDAR +VERSION:2.0 +PRODID:foo +METHOD:REQUEST +BEGIN:VEVENT +DTSTART;VALUE=DATE:20111202 +UID:foo +DTSTAMP:20140122T234434Z +END:VEVENT +BEGIN:VEVENT +DTSTART;VALUE=DATE:20111202 +UID:foo +DTSTAMP:20140122T234434Z +RECURRENCE-ID;VALUE=DATE:20111202 +END:VEVENT +END:VCALENDAR +'; + + $vcal = VObject\Reader::read($input); + $this->assertEquals(0, count($vcal->validate())); + } + + public function testGetBaseComponent() + { + $input = 'BEGIN:VCALENDAR +VERSION:2.0 +PRODID:foo +METHOD:REQUEST +BEGIN:VEVENT +SUMMARY:test +DTSTART;VALUE=DATE:20111202 +UID:foo +DTSTAMP:20140122T234434Z +END:VEVENT +BEGIN:VEVENT +DTSTART;VALUE=DATE:20111202 +UID:foo +DTSTAMP:20140122T234434Z +RECURRENCE-ID;VALUE=DATE:20111202 +END:VEVENT +END:VCALENDAR +'; + + $vcal = VObject\Reader::read($input); + + $result = $vcal->getBaseComponent(); + $this->assertEquals('test', $result->SUMMARY->getValue()); + } + + public function testGetBaseComponentNoResult() + { + $input = 'BEGIN:VCALENDAR +VERSION:2.0 +PRODID:foo +METHOD:REQUEST +BEGIN:VEVENT +SUMMARY:test +RECURRENCE-ID;VALUE=DATE:20111202 +DTSTART;VALUE=DATE:20111202 +UID:foo +DTSTAMP:20140122T234434Z +END:VEVENT +BEGIN:VEVENT +DTSTART;VALUE=DATE:20111202 +UID:foo +DTSTAMP:20140122T234434Z +RECURRENCE-ID;VALUE=DATE:20111202 +END:VEVENT +END:VCALENDAR +'; + + $vcal = VObject\Reader::read($input); + + $result = $vcal->getBaseComponent(); + $this->assertNull($result); + } + + public function testGetBaseComponentWithFilter() + { + $input = 'BEGIN:VCALENDAR +VERSION:2.0 +PRODID:foo +METHOD:REQUEST +BEGIN:VEVENT +SUMMARY:test +DTSTART;VALUE=DATE:20111202 +UID:foo +DTSTAMP:20140122T234434Z +END:VEVENT +BEGIN:VEVENT +DTSTART;VALUE=DATE:20111202 +UID:foo +DTSTAMP:20140122T234434Z +RECURRENCE-ID;VALUE=DATE:20111202 +END:VEVENT +END:VCALENDAR +'; + + $vcal = VObject\Reader::read($input); + + $result = $vcal->getBaseComponent('VEVENT'); + $this->assertEquals('test', $result->SUMMARY->getValue()); + } + + public function testGetBaseComponentWithFilterNoResult() + { + $input = 'BEGIN:VCALENDAR +VERSION:2.0 +PRODID:foo +METHOD:REQUEST +BEGIN:VTODO +SUMMARY:test +UID:foo +DTSTAMP:20140122T234434Z +END:VTODO +END:VCALENDAR +'; + + $vcal = VObject\Reader::read($input); + + $result = $vcal->getBaseComponent('VEVENT'); + $this->assertNull($result); + } + + public function testNoComponents() + { + $input = <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +PRODID:vobject +END:VCALENDAR +ICS; + + $this->assertValidate( + $input, + 0, + 3, + 'An iCalendar object must have at least 1 component.' + ); + } + + public function testCalDAVNoComponents() + { + $input = <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +PRODID:vobject +BEGIN:VTIMEZONE +TZID:America/Toronto +END:VTIMEZONE +END:VCALENDAR +ICS; + + $this->assertValidate( + $input, + VCalendar::PROFILE_CALDAV, + 3, + 'A calendar object on a CalDAV server must have at least 1 component (VTODO, VEVENT, VJOURNAL).' + ); + } + + public function testCalDAVMultiUID() + { + $input = <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +PRODID:vobject +BEGIN:VEVENT +UID:foo +DTSTAMP:20150109T184500Z +DTSTART:20150109T184500Z +END:VEVENT +BEGIN:VEVENT +UID:bar +DTSTAMP:20150109T184500Z +DTSTART:20150109T184500Z +END:VEVENT +END:VCALENDAR +ICS; + + $this->assertValidate( + $input, + VCalendar::PROFILE_CALDAV, + 3, + 'A calendar object on a CalDAV server may only have components with the same UID.' + ); + } + + public function testCalDAVMultiComponent() + { + $input = <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +PRODID:vobject +BEGIN:VEVENT +UID:foo +RECURRENCE-ID:20150109T185200Z +DTSTAMP:20150109T184500Z +DTSTART:20150109T184500Z +END:VEVENT +BEGIN:VTODO +UID:foo +DTSTAMP:20150109T184500Z +DTSTART:20150109T184500Z +END:VTODO +END:VCALENDAR +ICS; + + $this->assertValidate( + $input, + VCalendar::PROFILE_CALDAV, + 3, + 'A calendar object on a CalDAV server may only have 1 type of component (VEVENT, VTODO or VJOURNAL).' + ); + } + + public function testCalDAVMETHOD() + { + $input = <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +METHOD:PUBLISH +PRODID:vobject +BEGIN:VEVENT +UID:foo +RECURRENCE-ID:20150109T185200Z +DTSTAMP:20150109T184500Z +DTSTART:20150109T184500Z +END:VEVENT +END:VCALENDAR +ICS; + + $this->assertValidate( + $input, + VCalendar::PROFILE_CALDAV, + 3, + 'A calendar object on a CalDAV server MUST NOT have a METHOD property.' + ); + } + + public function assertValidate($ics, $options, $expectedLevel, $expectedMessage = null) + { + $vcal = VObject\Reader::read($ics); + $result = $vcal->validate($options); + + $this->assertValidateResult($result, $expectedLevel, $expectedMessage); + } + + public function assertValidateResult($input, $expectedLevel, $expectedMessage = null) + { + $messages = []; + foreach ($input as $warning) { + $messages[] = $warning['message']; + } + + if (0 === $expectedLevel) { + $this->assertEquals(0, count($input), 'No validation messages were expected. We got: '.implode(', ', $messages)); + } else { + $this->assertEquals(1, count($input), 'We expected exactly 1 validation message, We got: '.implode(', ', $messages)); + + $this->assertEquals($expectedMessage, $input[0]['message']); + $this->assertEquals($expectedLevel, $input[0]['level']); + } + } +} diff --git a/vendor/sabre/vobject/tests/VObject/Component/VCardTest.php b/vendor/sabre/vobject/tests/VObject/Component/VCardTest.php new file mode 100644 index 000000000..3124fec84 --- /dev/null +++ b/vendor/sabre/vobject/tests/VObject/Component/VCardTest.php @@ -0,0 +1,302 @@ +<?php + +namespace Sabre\VObject\Component; + +use PHPUnit\Framework\TestCase; +use Sabre\VObject; + +class VCardTest extends TestCase +{ + /** + * @dataProvider validateData + */ + public function testValidate($input, $expectedWarnings, $expectedRepairedOutput) + { + $vcard = VObject\Reader::read($input); + + $warnings = $vcard->validate(); + + $warnMsg = []; + foreach ($warnings as $warning) { + $warnMsg[] = $warning['message']; + } + + $this->assertEquals($expectedWarnings, $warnMsg); + + $vcard->validate(VObject\Component::REPAIR); + + $this->assertEquals( + $expectedRepairedOutput, + $vcard->serialize() + ); + } + + public function validateData() + { + $tests = []; + + // Correct + $tests[] = [ + "BEGIN:VCARD\r\nVERSION:4.0\r\nFN:John Doe\r\nUID:foo\r\nEND:VCARD\r\n", + [], + "BEGIN:VCARD\r\nVERSION:4.0\r\nFN:John Doe\r\nUID:foo\r\nEND:VCARD\r\n", + ]; + + // No VERSION + $tests[] = [ + "BEGIN:VCARD\r\nFN:John Doe\r\nUID:foo\r\nEND:VCARD\r\n", + [ + 'VERSION MUST appear exactly once in a VCARD component', + ], + "BEGIN:VCARD\r\nVERSION:4.0\r\nFN:John Doe\r\nUID:foo\r\nEND:VCARD\r\n", + ]; + + // Unknown version + $tests[] = [ + "BEGIN:VCARD\r\nVERSION:2.2\r\nFN:John Doe\r\nUID:foo\r\nEND:VCARD\r\n", + [ + 'Only vcard version 4.0 (RFC6350), version 3.0 (RFC2426) or version 2.1 (icm-vcard-2.1) are supported.', + ], + "BEGIN:VCARD\r\nVERSION:2.1\r\nFN:John Doe\r\nUID:foo\r\nEND:VCARD\r\n", + ]; + + // No FN + $tests[] = [ + "BEGIN:VCARD\r\nVERSION:4.0\r\nUID:foo\r\nEND:VCARD\r\n", + [ + 'The FN property must appear in the VCARD component exactly 1 time', + ], + "BEGIN:VCARD\r\nVERSION:4.0\r\nUID:foo\r\nEND:VCARD\r\n", + ]; + // No FN, N fallback + $tests[] = [ + "BEGIN:VCARD\r\nVERSION:4.0\r\nUID:foo\r\nN:Doe;John;;;;;\r\nEND:VCARD\r\n", + [ + 'The FN property must appear in the VCARD component exactly 1 time', + ], + "BEGIN:VCARD\r\nVERSION:4.0\r\nUID:foo\r\nN:Doe;John;;;;;\r\nFN:John Doe\r\nEND:VCARD\r\n", + ]; + // No FN, N fallback, no first name + $tests[] = [ + "BEGIN:VCARD\r\nVERSION:4.0\r\nUID:foo\r\nN:Doe;;;;;;\r\nEND:VCARD\r\n", + [ + 'The FN property must appear in the VCARD component exactly 1 time', + ], + "BEGIN:VCARD\r\nVERSION:4.0\r\nUID:foo\r\nN:Doe;;;;;;\r\nFN:Doe\r\nEND:VCARD\r\n", + ]; + // No FN, ORG fallback + $tests[] = [ + "BEGIN:VCARD\r\nVERSION:4.0\r\nUID:foo\r\nORG:Acme Co.\r\nEND:VCARD\r\n", + [ + 'The FN property must appear in the VCARD component exactly 1 time', + ], + "BEGIN:VCARD\r\nVERSION:4.0\r\nUID:foo\r\nORG:Acme Co.\r\nFN:Acme Co.\r\nEND:VCARD\r\n", + ]; + // No FN, EMAIL fallback + $tests[] = [ + "BEGIN:VCARD\r\nVERSION:4.0\r\nUID:foo\r\nEMAIL:1@example.org\r\nEND:VCARD\r\n", + [ + 'The FN property must appear in the VCARD component exactly 1 time', + ], + "BEGIN:VCARD\r\nVERSION:4.0\r\nUID:foo\r\nEMAIL:1@example.org\r\nFN:1@example.org\r\nEND:VCARD\r\n", + ]; + + return $tests; + } + + public function testGetDocumentType() + { + $vcard = new VCard([], false); + $vcard->VERSION = '2.1'; + $this->assertEquals(VCard::VCARD21, $vcard->getDocumentType()); + + $vcard = new VCard([], false); + $vcard->VERSION = '3.0'; + $this->assertEquals(VCard::VCARD30, $vcard->getDocumentType()); + + $vcard = new VCard([], false); + $vcard->VERSION = '4.0'; + $this->assertEquals(VCard::VCARD40, $vcard->getDocumentType()); + + $vcard = new VCard([], false); + $this->assertEquals(VCard::UNKNOWN, $vcard->getDocumentType()); + } + + public function testGetByType() + { + $vcard = <<<VCF +BEGIN:VCARD +VERSION:3.0 +EMAIL;TYPE=home:1@example.org +EMAIL;TYPE=work:2@example.org +END:VCARD +VCF; + + $vcard = VObject\Reader::read($vcard); + $this->assertEquals('1@example.org', $vcard->getByType('EMAIL', 'home')->getValue()); + $this->assertEquals('2@example.org', $vcard->getByType('EMAIL', 'work')->getValue()); + $this->assertNull($vcard->getByType('EMAIL', 'non-existant')); + $this->assertNull($vcard->getByType('ADR', 'non-existant')); + } + + public function testPreferredNoPref() + { + $vcard = <<<VCF +BEGIN:VCARD +VERSION:3.0 +EMAIL:1@example.org +EMAIL:2@example.org +END:VCARD +VCF; + + $vcard = VObject\Reader::read($vcard); + $this->assertEquals('1@example.org', $vcard->preferred('EMAIL')->getValue()); + } + + public function testPreferredWithPref() + { + $vcard = <<<VCF +BEGIN:VCARD +VERSION:3.0 +EMAIL:1@example.org +EMAIL;TYPE=PREF:2@example.org +END:VCARD +VCF; + + $vcard = VObject\Reader::read($vcard); + $this->assertEquals('2@example.org', $vcard->preferred('EMAIL')->getValue()); + } + + public function testPreferredWith40Pref() + { + $vcard = <<<VCF +BEGIN:VCARD +VERSION:4.0 +EMAIL:1@example.org +EMAIL;PREF=3:2@example.org +EMAIL;PREF=2:3@example.org +END:VCARD +VCF; + + $vcard = VObject\Reader::read($vcard); + $this->assertEquals('3@example.org', $vcard->preferred('EMAIL')->getValue()); + } + + public function testPreferredNotFound() + { + $vcard = <<<VCF +BEGIN:VCARD +VERSION:4.0 +END:VCARD +VCF; + + $vcard = VObject\Reader::read($vcard); + $this->assertNull($vcard->preferred('EMAIL')); + } + + public function testNoUIDCardDAV() + { + $vcard = <<<VCF +BEGIN:VCARD +VERSION:4.0 +FN:John Doe +END:VCARD +VCF; + $this->assertValidate( + $vcard, + VCard::PROFILE_CARDDAV, + 3, + 'vCards on CardDAV servers MUST have a UID property.' + ); + } + + public function testNoUIDNoCardDAV() + { + $vcard = <<<VCF +BEGIN:VCARD +VERSION:4.0 +FN:John Doe +END:VCARD +VCF; + $this->assertValidate( + $vcard, + 0, + 2, + 'Adding a UID to a vCard property is recommended.' + ); + } + + public function testNoUIDNoCardDAVRepair() + { + $vcard = <<<VCF +BEGIN:VCARD +VERSION:4.0 +FN:John Doe +END:VCARD +VCF; + $this->assertValidate( + $vcard, + VCard::REPAIR, + 1, + 'Adding a UID to a vCard property is recommended.' + ); + } + + public function testVCard21CardDAV() + { + $vcard = <<<VCF +BEGIN:VCARD +VERSION:2.1 +FN:John Doe +UID:foo +END:VCARD +VCF; + $this->assertValidate( + $vcard, + VCard::PROFILE_CARDDAV, + 3, + 'CardDAV servers are not allowed to accept vCard 2.1.' + ); + } + + public function testVCard21NoCardDAV() + { + $vcard = <<<VCF +BEGIN:VCARD +VERSION:2.1 +FN:John Doe +UID:foo +END:VCARD +VCF; + $this->assertValidate( + $vcard, + 0, + 0 + ); + } + + public function assertValidate($vcf, $options, $expectedLevel, $expectedMessage = null) + { + $vcal = VObject\Reader::read($vcf); + $result = $vcal->validate($options); + + $this->assertValidateResult($result, $expectedLevel, $expectedMessage); + } + + public function assertValidateResult($input, $expectedLevel, $expectedMessage = null) + { + $messages = []; + foreach ($input as $warning) { + $messages[] = $warning['message']; + } + + if (0 === $expectedLevel) { + $this->assertEquals(0, count($input), 'No validation messages were expected. We got: '.implode(', ', $messages)); + } else { + $this->assertEquals(1, count($input), 'We expected exactly 1 validation message, We got: '.implode(', ', $messages)); + + $this->assertEquals($expectedMessage, $input[0]['message']); + $this->assertEquals($expectedLevel, $input[0]['level']); + } + } +} diff --git a/vendor/sabre/vobject/tests/VObject/Component/VEventTest.php b/vendor/sabre/vobject/tests/VObject/Component/VEventTest.php new file mode 100644 index 000000000..635ae5acd --- /dev/null +++ b/vendor/sabre/vobject/tests/VObject/Component/VEventTest.php @@ -0,0 +1,94 @@ +<?php + +namespace Sabre\VObject\Component; + +use PHPUnit\Framework\TestCase; + +class VEventTest extends TestCase +{ + /** + * @dataProvider timeRangeTestData + */ + public function testInTimeRange(VEvent $vevent, $start, $end, $outcome) + { + $this->assertEquals($outcome, $vevent->isInTimeRange($start, $end)); + } + + public function timeRangeTestData() + { + $tests = []; + + $calendar = new VCalendar(); + + $vevent = $calendar->createComponent('VEVENT'); + $vevent->DTSTART = '20111223T120000Z'; + $tests[] = [$vevent, new \DateTime('2011-01-01'), new \DateTime('2012-01-01'), true]; + $tests[] = [$vevent, new \DateTime('2011-01-01'), new \DateTime('2011-11-01'), false]; + + $vevent2 = clone $vevent; + $vevent2->DTEND = '20111225T120000Z'; + $tests[] = [$vevent2, new \DateTime('2011-01-01'), new \DateTime('2012-01-01'), true]; + $tests[] = [$vevent2, new \DateTime('2011-01-01'), new \DateTime('2011-11-01'), false]; + + $vevent3 = clone $vevent; + $vevent3->DURATION = 'P1D'; + $tests[] = [$vevent3, new \DateTime('2011-01-01'), new \DateTime('2012-01-01'), true]; + $tests[] = [$vevent3, new \DateTime('2011-01-01'), new \DateTime('2011-11-01'), false]; + + $vevent4 = clone $vevent; + $vevent4->DTSTART = '20111225'; + $vevent4->DTSTART['VALUE'] = 'DATE'; + $tests[] = [$vevent4, new \DateTime('2011-01-01'), new \DateTime('2012-01-01'), true]; + $tests[] = [$vevent4, new \DateTime('2011-01-01'), new \DateTime('2011-11-01'), false]; + // Event with no end date should be treated as lasting the entire day. + $tests[] = [$vevent4, new \DateTime('2011-12-25 16:00:00'), new \DateTime('2011-12-25 17:00:00'), true]; + // DTEND is non inclusive so all day events should not be returned on the next day. + $tests[] = [$vevent4, new \DateTime('2011-12-26 00:00:00'), new \DateTime('2011-12-26 17:00:00'), false]; + // The timezone of timerange in question also needs to be considered. + $tests[] = [$vevent4, new \DateTime('2011-12-26 00:00:00', new \DateTimeZone('Europe/Berlin')), new \DateTime('2011-12-26 17:00:00', new \DateTimeZone('Europe/Berlin')), false]; + + $vevent5 = clone $vevent; + $vevent5->DURATION = 'P1D'; + $vevent5->RRULE = 'FREQ=YEARLY'; + $tests[] = [$vevent5, new \DateTime('2011-01-01'), new \DateTime('2012-01-01'), true]; + $tests[] = [$vevent5, new \DateTime('2011-01-01'), new \DateTime('2011-11-01'), false]; + $tests[] = [$vevent5, new \DateTime('2013-12-01'), new \DateTime('2013-12-31'), true]; + + $vevent6 = clone $vevent; + $vevent6->DTSTART = '20111225'; + $vevent6->DTSTART['VALUE'] = 'DATE'; + $vevent6->DTEND = '20111225'; + $vevent6->DTEND['VALUE'] = 'DATE'; + + $tests[] = [$vevent6, new \DateTime('2011-01-01'), new \DateTime('2012-01-01'), true]; + $tests[] = [$vevent6, new \DateTime('2011-01-01'), new \DateTime('2011-11-01'), false]; + + // Added this test to ensure that recurrence rules with no DTEND also + // get checked for the entire day. + $vevent7 = clone $vevent; + $vevent7->DTSTART = '20120101'; + $vevent7->DTSTART['VALUE'] = 'DATE'; + $vevent7->RRULE = 'FREQ=MONTHLY'; + $tests[] = [$vevent7, new \DateTime('2012-02-01 15:00:00'), new \DateTime('2012-02-02'), true]; + // The timezone of timerange in question should also be considered. + $tests[] = [$vevent7, new \DateTime('2012-02-02 00:00:00', new \DateTimeZone('Europe/Berlin')), new \DateTime('2012-02-03 00:00:00', new \DateTimeZone('Europe/Berlin')), false]; + + // Added this test to check recurring events that have no instances. + $vevent8 = clone $vevent; + $vevent8->DTSTART = '20130329T140000'; + $vevent8->DTEND = '20130329T153000'; + $vevent8->RRULE = ['FREQ' => 'WEEKLY', 'BYDAY' => ['FR'], 'UNTIL' => '20130412T115959Z']; + $vevent8->add('EXDATE', '20130405T140000'); + $vevent8->add('EXDATE', '20130329T140000'); + $tests[] = [$vevent8, new \DateTime('2013-03-01'), new \DateTime('2013-04-01'), false]; + + // Added this test to check recurring all day event that repeat every day + $vevent9 = clone $vevent; + $vevent9->DTSTART = '20161027'; + $vevent9->DTEND = '20161028'; + $vevent9->RRULE = 'FREQ=DAILY'; + $tests[] = [$vevent9, new \DateTime('2016-10-31'), new \DateTime('2016-12-12'), true]; + + return $tests; + } +} diff --git a/vendor/sabre/vobject/tests/VObject/Component/VFreeBusyTest.php b/vendor/sabre/vobject/tests/VObject/Component/VFreeBusyTest.php new file mode 100644 index 000000000..2aa4351ca --- /dev/null +++ b/vendor/sabre/vobject/tests/VObject/Component/VFreeBusyTest.php @@ -0,0 +1,64 @@ +<?php + +namespace Sabre\VObject\Component; + +use PHPUnit\Framework\TestCase; +use Sabre\VObject; +use Sabre\VObject\Reader; + +class VFreeBusyTest extends TestCase +{ + public function testIsFree() + { + $input = <<<BLA +BEGIN:VCALENDAR +BEGIN:VFREEBUSY +FREEBUSY;FBTYPE=FREE:20120912T000500Z/PT1H +FREEBUSY;FBTYPE=BUSY:20120912T010000Z/20120912T020000Z +FREEBUSY;FBTYPE=BUSY-TENTATIVE:20120912T020000Z/20120912T030000Z +FREEBUSY;FBTYPE=BUSY-UNAVAILABLE:20120912T030000Z/20120912T040000Z +FREEBUSY;FBTYPE=BUSY:20120912T050000Z/20120912T060000Z,20120912T080000Z/20120912T090000Z +FREEBUSY;FBTYPE=BUSY:20120912T100000Z/PT1H +END:VFREEBUSY +END:VCALENDAR +BLA; + + $obj = VObject\Reader::read($input); + $vfb = $obj->VFREEBUSY; + + $tz = new \DateTimeZone('UTC'); + + $this->assertFalse($vfb->isFree(new \DateTime('2012-09-12 01:15:00', $tz), new \DateTime('2012-09-12 01:45:00', $tz))); + $this->assertFalse($vfb->isFree(new \DateTime('2012-09-12 08:05:00', $tz), new \DateTime('2012-09-12 08:10:00', $tz))); + $this->assertFalse($vfb->isFree(new \DateTime('2012-09-12 10:15:00', $tz), new \DateTime('2012-09-12 10:45:00', $tz))); + + // Checking whether the end time is treated as non-inclusive + $this->assertTrue($vfb->isFree(new \DateTime('2012-09-12 09:00:00', $tz), new \DateTime('2012-09-12 09:15:00', $tz))); + $this->assertTrue($vfb->isFree(new \DateTime('2012-09-12 09:45:00', $tz), new \DateTime('2012-09-12 10:00:00', $tz))); + $this->assertTrue($vfb->isFree(new \DateTime('2012-09-12 11:00:00', $tz), new \DateTime('2012-09-12 12:00:00', $tz))); + } + + public function testValidate() + { + $input = <<<HI +BEGIN:VCALENDAR +VERSION:2.0 +PRODID:YoYo +BEGIN:VFREEBUSY +UID:some-random-id +DTSTAMP:20140402T180200Z +END:VFREEBUSY +END:VCALENDAR +HI; + + $obj = Reader::read($input); + + $warnings = $obj->validate(); + $messages = []; + foreach ($warnings as $warning) { + $messages[] = $warning['message']; + } + + $this->assertEquals([], $messages); + } +} diff --git a/vendor/sabre/vobject/tests/VObject/Component/VJournalTest.php b/vendor/sabre/vobject/tests/VObject/Component/VJournalTest.php new file mode 100644 index 000000000..67901b71b --- /dev/null +++ b/vendor/sabre/vobject/tests/VObject/Component/VJournalTest.php @@ -0,0 +1,94 @@ +<?php + +namespace Sabre\VObject\Component; + +use PHPUnit\Framework\TestCase; +use Sabre\VObject\Reader; + +class VJournalTest extends TestCase +{ + /** + * @dataProvider timeRangeTestData + */ + public function testInTimeRange(VJournal $vtodo, $start, $end, $outcome) + { + $this->assertEquals($outcome, $vtodo->isInTimeRange($start, $end)); + } + + public function testValidate() + { + $input = <<<HI +BEGIN:VCALENDAR +VERSION:2.0 +PRODID:YoYo +BEGIN:VJOURNAL +UID:12345678 +DTSTAMP:20140402T174100Z +END:VJOURNAL +END:VCALENDAR +HI; + + $obj = Reader::read($input); + + $warnings = $obj->validate(); + $messages = []; + foreach ($warnings as $warning) { + $messages[] = $warning['message']; + } + + $this->assertEquals([], $messages); + } + + public function testValidateBroken() + { + $input = <<<HI +BEGIN:VCALENDAR +VERSION:2.0 +PRODID:YoYo +BEGIN:VJOURNAL +UID:12345678 +DTSTAMP:20140402T174100Z +URL:http://example.org/ +URL:http://example.com/ +END:VJOURNAL +END:VCALENDAR +HI; + + $obj = Reader::read($input); + + $warnings = $obj->validate(); + $messages = []; + foreach ($warnings as $warning) { + $messages[] = $warning['message']; + } + + $this->assertEquals( + ['URL MUST NOT appear more than once in a VJOURNAL component'], + $messages + ); + } + + public function timeRangeTestData() + { + $calendar = new VCalendar(); + + $tests = []; + + $vjournal = $calendar->createComponent('VJOURNAL'); + $vjournal->DTSTART = '20111223T120000Z'; + $tests[] = [$vjournal, new \DateTime('2011-01-01'), new \DateTime('2012-01-01'), true]; + $tests[] = [$vjournal, new \DateTime('2011-01-01'), new \DateTime('2011-11-01'), false]; + + $vjournal2 = $calendar->createComponent('VJOURNAL'); + $vjournal2->DTSTART = '20111223'; + $vjournal2->DTSTART['VALUE'] = 'DATE'; + $tests[] = [$vjournal2, new \DateTime('2011-01-01'), new \DateTime('2012-01-01'), true]; + $tests[] = [$vjournal2, new \DateTime('2011-01-01'), new \DateTime('2011-11-01'), false]; + + $vjournal3 = $calendar->createComponent('VJOURNAL'); + $tests[] = [$vjournal3, new \DateTime('2011-01-01'), new \DateTime('2012-01-01'), false]; + $tests[] = [$vjournal3, new \DateTime('2011-01-01'), new \DateTime('2011-11-01'), false]; + + return $tests; + } +} diff --git a/vendor/sabre/vobject/tests/VObject/Component/VTimeZoneTest.php b/vendor/sabre/vobject/tests/VObject/Component/VTimeZoneTest.php new file mode 100644 index 000000000..ead22b81e --- /dev/null +++ b/vendor/sabre/vobject/tests/VObject/Component/VTimeZoneTest.php @@ -0,0 +1,54 @@ +<?php + +namespace Sabre\VObject\Component; + +use PHPUnit\Framework\TestCase; +use Sabre\VObject\Reader; + +class VTimeZoneTest extends TestCase +{ + public function testValidate() + { + $input = <<<HI +BEGIN:VCALENDAR +VERSION:2.0 +PRODID:YoYo +BEGIN:VTIMEZONE +TZID:America/Toronto +END:VTIMEZONE +END:VCALENDAR +HI; + + $obj = Reader::read($input); + + $warnings = $obj->validate(); + $messages = []; + foreach ($warnings as $warning) { + $messages[] = $warning['message']; + } + + $this->assertEquals([], $messages); + } + + public function testGetTimeZone() + { + $input = <<<HI +BEGIN:VCALENDAR +VERSION:2.0 +PRODID:YoYo +BEGIN:VTIMEZONE +TZID:America/Toronto +END:VTIMEZONE +END:VCALENDAR +HI; + + $obj = Reader::read($input); + + $tz = new \DateTimeZone('America/Toronto'); + + $this->assertEquals( + $tz, + $obj->VTIMEZONE->getTimeZone() + ); + } +} diff --git a/vendor/sabre/vobject/tests/VObject/Component/VTodoTest.php b/vendor/sabre/vobject/tests/VObject/Component/VTodoTest.php new file mode 100644 index 000000000..d5434458a --- /dev/null +++ b/vendor/sabre/vobject/tests/VObject/Component/VTodoTest.php @@ -0,0 +1,171 @@ +<?php + +namespace Sabre\VObject\Component; + +use PHPUnit\Framework\TestCase; +use Sabre\VObject\Reader; + +class VTodoTest extends TestCase +{ + /** + * @dataProvider timeRangeTestData + */ + public function testInTimeRange(VTodo $vtodo, $start, $end, $outcome) + { + $this->assertEquals($outcome, $vtodo->isInTimeRange($start, $end)); + } + + public function timeRangeTestData() + { + $tests = []; + + $calendar = new VCalendar(); + + $vtodo = $calendar->createComponent('VTODO'); + $vtodo->DTSTART = '20111223T120000Z'; + $tests[] = [$vtodo, new \DateTime('2011-01-01'), new \DateTime('2012-01-01'), true]; + $tests[] = [$vtodo, new \DateTime('2011-01-01'), new \DateTime('2011-11-01'), false]; + + $vtodo2 = clone $vtodo; + $vtodo2->DURATION = 'P1D'; + $tests[] = [$vtodo2, new \DateTime('2011-01-01'), new \DateTime('2012-01-01'), true]; + $tests[] = [$vtodo2, new \DateTime('2011-01-01'), new \DateTime('2011-11-01'), false]; + + $vtodo3 = clone $vtodo; + $vtodo3->DUE = '20111225'; + $tests[] = [$vtodo3, new \DateTime('2011-01-01'), new \DateTime('2012-01-01'), true]; + $tests[] = [$vtodo3, new \DateTime('2011-01-01'), new \DateTime('2011-11-01'), false]; + + $vtodo4 = $calendar->createComponent('VTODO'); + $vtodo4->DUE = '20111225'; + $tests[] = [$vtodo4, new \DateTime('2011-01-01'), new \DateTime('2012-01-01'), true]; + $tests[] = [$vtodo4, new \DateTime('2011-01-01'), new \DateTime('2011-11-01'), false]; + + $vtodo5 = $calendar->createComponent('VTODO'); + $vtodo5->COMPLETED = '20111225'; + $tests[] = [$vtodo5, new \DateTime('2011-01-01'), new \DateTime('2012-01-01'), true]; + $tests[] = [$vtodo5, new \DateTime('2011-01-01'), new \DateTime('2011-11-01'), false]; + + $vtodo6 = $calendar->createComponent('VTODO'); + $vtodo6->CREATED = '20111225'; + $tests[] = [$vtodo6, new \DateTime('2011-01-01'), new \DateTime('2012-01-01'), true]; + $tests[] = [$vtodo6, new \DateTime('2011-01-01'), new \DateTime('2011-11-01'), false]; + + $vtodo7 = $calendar->createComponent('VTODO'); + $vtodo7->CREATED = '20111225'; + $vtodo7->COMPLETED = '20111226'; + $tests[] = [$vtodo7, new \DateTime('2011-01-01'), new \DateTime('2012-01-01'), true]; + $tests[] = [$vtodo7, new \DateTime('2011-01-01'), new \DateTime('2011-11-01'), false]; + + $vtodo7 = $calendar->createComponent('VTODO'); + $tests[] = [$vtodo7, new \DateTime('2011-01-01'), new \DateTime('2012-01-01'), true]; + $tests[] = [$vtodo7, new \DateTime('2011-01-01'), new \DateTime('2011-11-01'), true]; + + return $tests; + } + + public function testValidate() + { + $input = <<<HI +BEGIN:VCALENDAR +VERSION:2.0 +PRODID:YoYo +BEGIN:VTODO +UID:1234-21355-123156 +DTSTAMP:20140402T183400Z +END:VTODO +END:VCALENDAR +HI; + + $obj = Reader::read($input); + + $warnings = $obj->validate(); + $messages = []; + foreach ($warnings as $warning) { + $messages[] = $warning['message']; + } + + $this->assertEquals([], $messages); + } + + public function testValidateInvalid() + { + $input = <<<HI +BEGIN:VCALENDAR +VERSION:2.0 +PRODID:YoYo +BEGIN:VTODO +END:VTODO +END:VCALENDAR +HI; + + $obj = Reader::read($input); + + $warnings = $obj->validate(); + $messages = []; + foreach ($warnings as $warning) { + $messages[] = $warning['message']; + } + + $this->assertEquals([ + 'UID MUST appear exactly once in a VTODO component', + 'DTSTAMP MUST appear exactly once in a VTODO component', + ], $messages); + } + + public function testValidateDUEDTSTARTMisMatch() + { + $input = <<<HI +BEGIN:VCALENDAR +VERSION:2.0 +PRODID:YoYo +BEGIN:VTODO +UID:FOO +DTSTART;VALUE=DATE-TIME:20140520T131600Z +DUE;VALUE=DATE:20140520 +DTSTAMP;VALUE=DATE-TIME:20140520T131600Z +END:VTODO +END:VCALENDAR +HI; + + $obj = Reader::read($input); + + $warnings = $obj->validate(); + $messages = []; + foreach ($warnings as $warning) { + $messages[] = $warning['message']; + } + + $this->assertEquals([ + 'The value type (DATE or DATE-TIME) must be identical for DUE and DTSTART', + ], $messages); + } + + public function testValidateDUEbeforeDTSTART() + { + $input = <<<HI +BEGIN:VCALENDAR +VERSION:2.0 +PRODID:YoYo +BEGIN:VTODO +UID:FOO +DTSTART;VALUE=DATE:20140520 +DUE;VALUE=DATE:20140518 +DTSTAMP;VALUE=DATE-TIME:20140520T131600Z +END:VTODO +END:VCALENDAR +HI; + + $obj = Reader::read($input); + + $warnings = $obj->validate(); + $messages = []; + foreach ($warnings as $warning) { + $messages[] = $warning['message']; + } + + $this->assertEquals([ + 'DUE must occur after DTSTART', + ], $messages); + } +} diff --git a/vendor/sabre/vobject/tests/VObject/ComponentTest.php b/vendor/sabre/vobject/tests/VObject/ComponentTest.php new file mode 100644 index 000000000..8c0a0d7c6 --- /dev/null +++ b/vendor/sabre/vobject/tests/VObject/ComponentTest.php @@ -0,0 +1,549 @@ +<?php + +namespace Sabre\VObject; + +use PHPUnit\Framework\TestCase; +use Sabre\VObject\Component\VCalendar; +use Sabre\VObject\Component\VCard; + +class ComponentTest extends TestCase +{ + public function testIterate() + { + $comp = new VCalendar([], false); + + $sub = $comp->createComponent('VEVENT'); + $comp->add($sub); + + $sub = $comp->createComponent('VTODO'); + $comp->add($sub); + + $count = 0; + foreach ($comp->children() as $key => $subcomponent) { + ++$count; + $this->assertInstanceOf('Sabre\\VObject\\Component', $subcomponent); + } + $this->assertEquals(2, $count); + $this->assertEquals(1, $key); + } + + public function testMagicGet() + { + $comp = new VCalendar([], false); + + $sub = $comp->createComponent('VEVENT'); + $comp->add($sub); + + $sub = $comp->createComponent('VTODO'); + $comp->add($sub); + + $event = $comp->vevent; + $this->assertInstanceOf('Sabre\\VObject\\Component', $event); + $this->assertEquals('VEVENT', $event->name); + + $this->assertInternalType('null', $comp->vjournal); + } + + public function testMagicGetGroups() + { + $comp = new VCard(); + + $sub = $comp->createProperty('GROUP1.EMAIL', '1@1.com'); + $comp->add($sub); + + $sub = $comp->createProperty('GROUP2.EMAIL', '2@2.com'); + $comp->add($sub); + + $sub = $comp->createProperty('EMAIL', '3@3.com'); + $comp->add($sub); + + $emails = $comp->email; + $this->assertEquals(3, count($emails)); + + $email1 = $comp->{'group1.email'}; + $this->assertEquals('EMAIL', $email1[0]->name); + $this->assertEquals('GROUP1', $email1[0]->group); + + $email3 = $comp->{'.email'}; + $this->assertEquals('EMAIL', $email3[0]->name); + $this->assertEquals(null, $email3[0]->group); + } + + public function testMagicIsset() + { + $comp = new VCalendar(); + + $sub = $comp->createComponent('VEVENT'); + $comp->add($sub); + + $sub = $comp->createComponent('VTODO'); + $comp->add($sub); + + $this->assertTrue(isset($comp->vevent)); + $this->assertTrue(isset($comp->vtodo)); + $this->assertFalse(isset($comp->vjournal)); + } + + public function testMagicSetScalar() + { + $comp = new VCalendar(); + $comp->myProp = 'myValue'; + + $this->assertInstanceOf('Sabre\\VObject\\Property', $comp->MYPROP); + $this->assertEquals('myValue', (string) $comp->MYPROP); + } + + public function testMagicSetScalarTwice() + { + $comp = new VCalendar([], false); + $comp->myProp = 'myValue'; + $comp->myProp = 'myValue'; + + $this->assertEquals(1, count($comp->children())); + $this->assertInstanceOf('Sabre\\VObject\\Property', $comp->MYPROP); + $this->assertEquals('myValue', (string) $comp->MYPROP); + } + + public function testMagicSetArray() + { + $comp = new VCalendar(); + $comp->ORG = ['Acme Inc', 'Section 9']; + + $this->assertInstanceOf('Sabre\\VObject\\Property', $comp->ORG); + $this->assertEquals(['Acme Inc', 'Section 9'], $comp->ORG->getParts()); + } + + public function testMagicSetComponent() + { + $comp = new VCalendar(); + + // Note that 'myProp' is ignored here. + $comp->myProp = $comp->createComponent('VEVENT'); + + $this->assertEquals(1, count($comp)); + + $this->assertEquals('VEVENT', $comp->VEVENT->name); + } + + public function testMagicSetTwice() + { + $comp = new VCalendar([], false); + + $comp->VEVENT = $comp->createComponent('VEVENT'); + $comp->VEVENT = $comp->createComponent('VEVENT'); + + $this->assertEquals(1, count($comp->children())); + + $this->assertEquals('VEVENT', $comp->VEVENT->name); + } + + public function testArrayAccessGet() + { + $comp = new VCalendar([], false); + + $event = $comp->createComponent('VEVENT'); + $event->summary = 'Event 1'; + + $comp->add($event); + + $event2 = clone $event; + $event2->summary = 'Event 2'; + + $comp->add($event2); + + $this->assertEquals(2, count($comp->children())); + $this->assertTrue($comp->vevent[1] instanceof Component); + $this->assertEquals('Event 2', (string) $comp->vevent[1]->summary); + } + + public function testArrayAccessExists() + { + $comp = new VCalendar(); + + $event = $comp->createComponent('VEVENT'); + $event->summary = 'Event 1'; + + $comp->add($event); + + $event2 = clone $event; + $event2->summary = 'Event 2'; + + $comp->add($event2); + + $this->assertTrue(isset($comp->vevent[0])); + $this->assertTrue(isset($comp->vevent[1])); + } + + /** + * @expectedException \LogicException + */ + public function testArrayAccessSet() + { + $comp = new VCalendar(); + $comp['hey'] = 'hi there'; + } + + /** + * @expectedException \LogicException + */ + public function testArrayAccessUnset() + { + $comp = new VCalendar(); + unset($comp[0]); + } + + public function testAddScalar() + { + $comp = new VCalendar([], false); + + $comp->add('myprop', 'value'); + + $this->assertEquals(1, count($comp->children())); + + $bla = $comp->children()[0]; + + $this->assertTrue($bla instanceof Property); + $this->assertEquals('MYPROP', $bla->name); + $this->assertEquals('value', (string) $bla); + } + + public function testAddScalarParams() + { + $comp = new VCalendar([], false); + + $comp->add('myprop', 'value', ['param1' => 'value1']); + + $this->assertEquals(1, count($comp->children())); + + $bla = $comp->children()[0]; + + $this->assertInstanceOf('Sabre\\VObject\\Property', $bla); + $this->assertEquals('MYPROP', $bla->name); + $this->assertEquals('value', (string) $bla); + + $this->assertEquals(1, count($bla->parameters())); + + $this->assertEquals('PARAM1', $bla->parameters['PARAM1']->name); + $this->assertEquals('value1', $bla->parameters['PARAM1']->getValue()); + } + + public function testAddComponent() + { + $comp = new VCalendar([], false); + + $comp->add($comp->createComponent('VEVENT')); + + $this->assertEquals(1, count($comp->children())); + + $this->assertEquals('VEVENT', $comp->VEVENT->name); + } + + public function testAddComponentTwice() + { + $comp = new VCalendar([], false); + + $comp->add($comp->createComponent('VEVENT')); + $comp->add($comp->createComponent('VEVENT')); + + $this->assertEquals(2, count($comp->children())); + + $this->assertEquals('VEVENT', $comp->VEVENT->name); + } + + /** + * @expectedException \InvalidArgumentException + */ + public function testAddArgFail() + { + $comp = new VCalendar(); + $comp->add($comp->createComponent('VEVENT'), 'hello'); + } + + /** + * @expectedException \InvalidArgumentException + */ + public function testAddArgFail2() + { + $comp = new VCalendar(); + $comp->add([]); + } + + public function testMagicUnset() + { + $comp = new VCalendar([], false); + $comp->add($comp->createComponent('VEVENT')); + + unset($comp->vevent); + + $this->assertEquals(0, count($comp->children())); + } + + public function testCount() + { + $comp = new VCalendar(); + $this->assertEquals(1, $comp->count()); + } + + public function testChildren() + { + $comp = new VCalendar([], false); + + // Note that 'myProp' is ignored here. + $comp->add($comp->createComponent('VEVENT')); + $comp->add($comp->createComponent('VTODO')); + + $r = $comp->children(); + $this->assertInternalType('array', $r); + $this->assertEquals(2, count($r)); + } + + public function testGetComponents() + { + $comp = new VCalendar(); + + $comp->add($comp->createProperty('FOO', 'BAR')); + $comp->add($comp->createComponent('VTODO')); + + $r = $comp->getComponents(); + $this->assertInternalType('array', $r); + $this->assertEquals(1, count($r)); + $this->assertEquals('VTODO', $r[0]->name); + } + + public function testSerialize() + { + $comp = new VCalendar([], false); + $this->assertEquals("BEGIN:VCALENDAR\r\nEND:VCALENDAR\r\n", $comp->serialize()); + } + + public function testSerializeChildren() + { + $comp = new VCalendar([], false); + $event = $comp->add($comp->createComponent('VEVENT')); + unset($event->DTSTAMP, $event->UID); + $todo = $comp->add($comp->createComponent('VTODO')); + unset($todo->DTSTAMP, $todo->UID); + + $str = $comp->serialize(); + + $this->assertEquals("BEGIN:VCALENDAR\r\nBEGIN:VEVENT\r\nEND:VEVENT\r\nBEGIN:VTODO\r\nEND:VTODO\r\nEND:VCALENDAR\r\n", $str); + } + + public function testSerializeOrderCompAndProp() + { + $comp = new VCalendar([], false); + $comp->add($event = $comp->createComponent('VEVENT')); + $comp->add('PROP1', 'BLABLA'); + $comp->add('VERSION', '2.0'); + $comp->add($comp->createComponent('VTIMEZONE')); + + unset($event->DTSTAMP, $event->UID); + $str = $comp->serialize(); + + $this->assertEquals("BEGIN:VCALENDAR\r\nVERSION:2.0\r\nPROP1:BLABLA\r\nBEGIN:VTIMEZONE\r\nEND:VTIMEZONE\r\nBEGIN:VEVENT\r\nEND:VEVENT\r\nEND:VCALENDAR\r\n", $str); + } + + public function testAnotherSerializeOrderProp() + { + $prop4s = ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10']; + + $comp = new VCard([], false); + + $comp->__set('SOMEPROP', 'FOO'); + $comp->__set('ANOTHERPROP', 'FOO'); + $comp->__set('THIRDPROP', 'FOO'); + foreach ($prop4s as $prop4) { + $comp->add('PROP4', 'FOO '.$prop4); + } + $comp->__set('PROPNUMBERFIVE', 'FOO'); + $comp->__set('PROPNUMBERSIX', 'FOO'); + $comp->__set('PROPNUMBERSEVEN', 'FOO'); + $comp->__set('PROPNUMBEREIGHT', 'FOO'); + $comp->__set('PROPNUMBERNINE', 'FOO'); + $comp->__set('PROPNUMBERTEN', 'FOO'); + $comp->__set('VERSION', '2.0'); + $comp->__set('UID', 'FOO'); + + $str = $comp->serialize(); + + $this->assertEquals("BEGIN:VCARD\r\nVERSION:2.0\r\nSOMEPROP:FOO\r\nANOTHERPROP:FOO\r\nTHIRDPROP:FOO\r\nPROP4:FOO 1\r\nPROP4:FOO 2\r\nPROP4:FOO 3\r\nPROP4:FOO 4\r\nPROP4:FOO 5\r\nPROP4:FOO 6\r\nPROP4:FOO 7\r\nPROP4:FOO 8\r\nPROP4:FOO 9\r\nPROP4:FOO 10\r\nPROPNUMBERFIVE:FOO\r\nPROPNUMBERSIX:FOO\r\nPROPNUMBERSEVEN:FOO\r\nPROPNUMBEREIGHT:FOO\r\nPROPNUMBERNINE:FOO\r\nPROPNUMBERTEN:FOO\r\nUID:FOO\r\nEND:VCARD\r\n", $str); + } + + public function testInstantiateWithChildren() + { + $comp = new VCard([ + 'ORG' => ['Acme Inc.', 'Section 9'], + 'FN' => 'Finn The Human', + ]); + + $this->assertEquals(['Acme Inc.', 'Section 9'], $comp->ORG->getParts()); + $this->assertEquals('Finn The Human', $comp->FN->getValue()); + } + + public function testInstantiateSubComponent() + { + $comp = new VCalendar(); + $event = $comp->createComponent('VEVENT', [ + $comp->createProperty('UID', '12345'), + ]); + $comp->add($event); + + $this->assertEquals('12345', $comp->VEVENT->UID->getValue()); + } + + public function testRemoveByName() + { + $comp = new VCalendar([], false); + $comp->add('prop1', 'val1'); + $comp->add('prop2', 'val2'); + $comp->add('prop2', 'val2'); + + $comp->remove('prop2'); + $this->assertFalse(isset($comp->prop2)); + $this->assertTrue(isset($comp->prop1)); + } + + public function testRemoveByObj() + { + $comp = new VCalendar([], false); + $comp->add('prop1', 'val1'); + $prop = $comp->add('prop2', 'val2'); + + $comp->remove($prop); + $this->assertFalse(isset($comp->prop2)); + $this->assertTrue(isset($comp->prop1)); + } + + /** + * @expectedException \InvalidArgumentException + */ + public function testRemoveNotFound() + { + $comp = new VCalendar([], false); + $prop = $comp->createProperty('A', 'B'); + $comp->remove($prop); + } + + /** + * @dataProvider ruleData + */ + public function testValidateRules($componentList, $errorCount) + { + $vcard = new Component\VCard(); + + $component = new FakeComponent($vcard, 'Hi', [], $defaults = false); + foreach ($componentList as $v) { + $component->add($v, 'Hello.'); + } + + $this->assertEquals($errorCount, count($component->validate())); + } + + public function testValidateRepair() + { + $vcard = new Component\VCard(); + + $component = new FakeComponent($vcard, 'Hi', [], $defaults = false); + $component->validate(Component::REPAIR); + $this->assertEquals('yow', $component->BAR->getValue()); + } + + public function testValidateRepairShouldNotDeduplicatePropertiesWhenValuesDiffer() + { + $vcard = new Component\VCard(); + + $component = new FakeComponent($vcard, 'WithDuplicateGIR', []); + $component->add('BAZ', 'BAZ'); + $component->add('GIR', 'VALUE1'); + $component->add('GIR', 'VALUE2'); // Different values + + $messages = $component->validate(Component::REPAIR); + + $this->assertEquals(1, count($messages)); + $this->assertEquals(3, $messages[0]['level']); + $this->assertEquals(2, count($component->GIR)); + } + + public function testValidateRepairShouldNotDeduplicatePropertiesWhenParametersDiffer() + { + $vcard = new Component\VCard(); + + $component = new FakeComponent($vcard, 'WithDuplicateGIR', []); + $component->add('BAZ', 'BAZ'); + $component->add('GIR', 'VALUE')->add('PARAM', '1'); + $component->add('GIR', 'VALUE')->add('PARAM', '2'); // Same value but different parameters + + $messages = $component->validate(Component::REPAIR); + + $this->assertEquals(1, count($messages)); + $this->assertEquals(3, $messages[0]['level']); + $this->assertEquals(2, count($component->GIR)); + } + + public function testValidateRepairShouldDeduplicatePropertiesWhenValuesAndParametersAreEqual() + { + $vcard = new Component\VCard(); + + $component = new FakeComponent($vcard, 'WithDuplicateGIR', []); + $component->add('BAZ', 'BAZ'); + $component->add('GIR', 'VALUE')->add('PARAM', 'P'); + $component->add('GIR', 'VALUE')->add('PARAM', 'P'); + + $messages = $component->validate(Component::REPAIR); + + $this->assertEquals(1, count($messages)); + $this->assertEquals(1, $messages[0]['level']); + $this->assertEquals(1, count($component->GIR)); + } + + public function testValidateRepairShouldDeduplicatePropertiesWhenValuesAreEqual() + { + $vcard = new Component\VCard(); + + $component = new FakeComponent($vcard, 'WithDuplicateGIR', []); + $component->add('BAZ', 'BAZ'); + $component->add('GIR', 'VALUE'); + $component->add('GIR', 'VALUE'); + + $messages = $component->validate(Component::REPAIR); + + $this->assertEquals(1, count($messages)); + $this->assertEquals(1, $messages[0]['level']); + $this->assertEquals(1, count($component->GIR)); + } + + public function ruleData() + { + return [ + [[], 2], + [['FOO'], 3], + [['BAR'], 1], + [['BAZ'], 1], + [['BAR', 'BAZ'], 0], + [['BAR', 'BAZ', 'ZIM'], 0], + [['BAR', 'BAZ', 'ZIM', 'GIR'], 0], + [['BAR', 'BAZ', 'ZIM', 'GIR', 'GIR'], 1], + ]; + } +} + +class FakeComponent extends Component +{ + public function getValidationRules() + { + return [ + 'FOO' => '0', + 'BAR' => '1', + 'BAZ' => '+', + 'ZIM' => '*', + 'GIR' => '?', + ]; + } + + public function getDefaults() + { + return [ + 'BAR' => 'yow', + ]; + } +} diff --git a/vendor/sabre/vobject/tests/VObject/DateTimeParserTest.php b/vendor/sabre/vobject/tests/VObject/DateTimeParserTest.php new file mode 100644 index 000000000..44fba80c5 --- /dev/null +++ b/vendor/sabre/vobject/tests/VObject/DateTimeParserTest.php @@ -0,0 +1,660 @@ +<?php + +namespace Sabre\VObject; + +use DateInterval; +use DateTimeImmutable; +use DateTimeZone; +use PHPUnit\Framework\TestCase; + +class DateTimeParserTest extends TestCase +{ + public function testParseICalendarDuration() + { + $this->assertEquals('+1 weeks', DateTimeParser::parseDuration('P1W', true)); + $this->assertEquals('+5 days', DateTimeParser::parseDuration('P5D', true)); + $this->assertEquals('+5 days 3 hours 50 minutes 12 seconds', DateTimeParser::parseDuration('P5DT3H50M12S', true)); + $this->assertEquals('-1 weeks 50 minutes', DateTimeParser::parseDuration('-P1WT50M', true)); + $this->assertEquals('+50 days 3 hours 2 seconds', DateTimeParser::parseDuration('+P50DT3H2S', true)); + $this->assertEquals('+0 seconds', DateTimeParser::parseDuration('+PT0S', true)); + $this->assertEquals(new DateInterval('PT0S'), DateTimeParser::parseDuration('PT0S')); + } + + public function testParseICalendarDurationDateInterval() + { + $expected = new DateInterval('P7D'); + $this->assertEquals($expected, DateTimeParser::parseDuration('P1W')); + $this->assertEquals($expected, DateTimeParser::parse('P1W')); + + $expected = new DateInterval('PT3M'); + $expected->invert = true; + $this->assertEquals($expected, DateTimeParser::parseDuration('-PT3M')); + } + + /** + * @expectedException \Sabre\VObject\InvalidDataException + */ + public function testParseICalendarDurationFail() + { + DateTimeParser::parseDuration('P1X', true); + } + + public function testParseICalendarDateTime() + { + $dateTime = DateTimeParser::parseDateTime('20100316T141405'); + + $compare = new DateTimeImmutable('2010-03-16 14:14:05', new DateTimeZone('UTC')); + + $this->assertEquals($compare, $dateTime); + } + + /** + * @depends testParseICalendarDateTime + * @expectedException \Sabre\VObject\InvalidDataException + */ + public function testParseICalendarDateTimeBadFormat() + { + $dateTime = DateTimeParser::parseDateTime('20100316T141405 '); + } + + /** + * @depends testParseICalendarDateTime + * @expectedException \Sabre\VObject\InvalidDataException + */ + public function testParseICalendarDateTimeInvalidTime() + { + $dateTime = DateTimeParser::parseDateTime('20100316T251405'); + } + + /** + * @depends testParseICalendarDateTime + */ + public function testParseICalendarDateTimeUTC() + { + $dateTime = DateTimeParser::parseDateTime('20100316T141405Z'); + + $compare = new DateTimeImmutable('2010-03-16 14:14:05', new DateTimeZone('UTC')); + $this->assertEquals($compare, $dateTime); + } + + /** + * @depends testParseICalendarDateTime + */ + public function testParseICalendarDateTimeUTC2() + { + $dateTime = DateTimeParser::parseDateTime('20101211T160000Z'); + + $compare = new DateTimeImmutable('2010-12-11 16:00:00', new DateTimeZone('UTC')); + $this->assertEquals($compare, $dateTime); + } + + /** + * @depends testParseICalendarDateTime + */ + public function testParseICalendarDateTimeCustomTimeZone() + { + $dateTime = DateTimeParser::parseDateTime('20100316T141405', new DateTimeZone('Europe/Amsterdam')); + + $compare = new DateTimeImmutable('2010-03-16 14:14:05', new DateTimeZone('Europe/Amsterdam')); + $this->assertEquals($compare, $dateTime); + } + + public function testParseICalendarDate() + { + $dateTime = DateTimeParser::parseDate('20100316'); + + $expected = new DateTimeImmutable('2010-03-16 00:00:00', new DateTimeZone('UTC')); + + $this->assertEquals($expected, $dateTime); + + $dateTime = DateTimeParser::parse('20100316'); + $this->assertEquals($expected, $dateTime); + } + + /** + * TCheck if a date with year > 4000 will not throw an exception. iOS seems to use 45001231 in yearly recurring events. + */ + public function testParseICalendarDateGreaterThan4000() + { + $dateTime = DateTimeParser::parseDate('45001231'); + + $expected = new DateTimeImmutable('4500-12-31 00:00:00', new DateTimeZone('UTC')); + + $this->assertEquals($expected, $dateTime); + + $dateTime = DateTimeParser::parse('45001231'); + $this->assertEquals($expected, $dateTime); + } + + /** + * Check if a datetime with year > 4000 will not throw an exception. iOS seems to use 45001231T235959 in yearly recurring events. + */ + public function testParseICalendarDateTimeGreaterThan4000() + { + $dateTime = DateTimeParser::parseDateTime('45001231T235959'); + + $expected = new DateTimeImmutable('4500-12-31 23:59:59', new DateTimeZone('UTC')); + + $this->assertEquals($expected, $dateTime); + + $dateTime = DateTimeParser::parse('45001231T235959'); + $this->assertEquals($expected, $dateTime); + } + + /** + * @depends testParseICalendarDate + * @expectedException \Sabre\VObject\InvalidDataException + */ + public function testParseICalendarDateBadFormat() + { + $dateTime = DateTimeParser::parseDate('20100316T141405'); + } + + /** + * @depends testParseICalendarDate + * @expectedException \Sabre\VObject\InvalidDataException + */ + public function testParseICalendarDateInvalidDate() + { + $dateTime = DateTimeParser::parseDate('20101331'); + } + + /** + * @dataProvider vcardDates + */ + public function testVCardDate($input, $output) + { + $this->assertEquals( + $output, + DateTimeParser::parseVCardDateTime($input) + ); + } + + /** + * @expectedException \Sabre\VObject\InvalidDataException + */ + public function testBadVCardDate() + { + DateTimeParser::parseVCardDateTime('1985---01'); + } + + /** + * @expectedException \Sabre\VObject\InvalidDataException + */ + public function testBadVCardTime() + { + DateTimeParser::parseVCardTime('23:12:166'); + } + + public function vcardDates() + { + return [ + [ + '19961022T140000', + [ + 'year' => 1996, + 'month' => 10, + 'date' => 22, + 'hour' => 14, + 'minute' => 00, + 'second' => 00, + 'timezone' => null, + ], + ], + [ + '--1022T1400', + [ + 'year' => null, + 'month' => 10, + 'date' => 22, + 'hour' => 14, + 'minute' => 00, + 'second' => null, + 'timezone' => null, + ], + ], + [ + '---22T14', + [ + 'year' => null, + 'month' => null, + 'date' => 22, + 'hour' => 14, + 'minute' => null, + 'second' => null, + 'timezone' => null, + ], + ], + [ + '19850412', + [ + 'year' => 1985, + 'month' => 4, + 'date' => 12, + 'hour' => null, + 'minute' => null, + 'second' => null, + 'timezone' => null, + ], + ], + [ + '1985-04', + [ + 'year' => 1985, + 'month' => 04, + 'date' => null, + 'hour' => null, + 'minute' => null, + 'second' => null, + 'timezone' => null, + ], + ], + [ + '1985', + [ + 'year' => 1985, + 'month' => null, + 'date' => null, + 'hour' => null, + 'minute' => null, + 'second' => null, + 'timezone' => null, + ], + ], + [ + '--0412', + [ + 'year' => null, + 'month' => 4, + 'date' => 12, + 'hour' => null, + 'minute' => null, + 'second' => null, + 'timezone' => null, + ], + ], + [ + '---12', + [ + 'year' => null, + 'month' => null, + 'date' => 12, + 'hour' => null, + 'minute' => null, + 'second' => null, + 'timezone' => null, + ], + ], + [ + 'T102200', + [ + 'year' => null, + 'month' => null, + 'date' => null, + 'hour' => 10, + 'minute' => 22, + 'second' => 0, + 'timezone' => null, + ], + ], + [ + 'T1022', + [ + 'year' => null, + 'month' => null, + 'date' => null, + 'hour' => 10, + 'minute' => 22, + 'second' => null, + 'timezone' => null, + ], + ], + [ + 'T10', + [ + 'year' => null, + 'month' => null, + 'date' => null, + 'hour' => 10, + 'minute' => null, + 'second' => null, + 'timezone' => null, + ], + ], + [ + 'T-2200', + [ + 'year' => null, + 'month' => null, + 'date' => null, + 'hour' => null, + 'minute' => 22, + 'second' => 00, + 'timezone' => null, + ], + ], + [ + 'T--00', + [ + 'year' => null, + 'month' => null, + 'date' => null, + 'hour' => null, + 'minute' => null, + 'second' => 00, + 'timezone' => null, + ], + ], + [ + 'T102200Z', + [ + 'year' => null, + 'month' => null, + 'date' => null, + 'hour' => 10, + 'minute' => 22, + 'second' => 00, + 'timezone' => 'Z', + ], + ], + [ + 'T102200-0800', + [ + 'year' => null, + 'month' => null, + 'date' => null, + 'hour' => 10, + 'minute' => 22, + 'second' => 00, + 'timezone' => '-0800', + ], + ], + + // extended format + [ + '2012-11-29T15:10:53Z', + [ + 'year' => 2012, + 'month' => 11, + 'date' => 29, + 'hour' => 15, + 'minute' => 10, + 'second' => 53, + 'timezone' => 'Z', + ], + ], + + // with milliseconds + [ + '20121129T151053.123Z', + [ + 'year' => 2012, + 'month' => 11, + 'date' => 29, + 'hour' => 15, + 'minute' => 10, + 'second' => 53, + 'timezone' => 'Z', + ], + ], + + // extended format with milliseconds + [ + '2012-11-29T15:10:53.123Z', + [ + 'year' => 2012, + 'month' => 11, + 'date' => 29, + 'hour' => 15, + 'minute' => 10, + 'second' => 53, + 'timezone' => 'Z', + ], + ], + ]; + } + + public function testDateAndOrTime_DateWithYearMonthDay() + { + $this->assertDateAndOrTimeEqualsTo( + '20150128', + [ + 'year' => '2015', + 'month' => '01', + 'date' => '28', + ] + ); + } + + public function testDateAndOrTime_DateWithYearMonth() + { + $this->assertDateAndOrTimeEqualsTo( + '2015-01', + [ + 'year' => '2015', + 'month' => '01', + ] + ); + } + + public function testDateAndOrTime_DateWithMonth() + { + $this->assertDateAndOrTimeEqualsTo( + '--01', + [ + 'month' => '01', + ] + ); + } + + public function testDateAndOrTime_DateWithMonthDay() + { + $this->assertDateAndOrTimeEqualsTo( + '--0128', + [ + 'month' => '01', + 'date' => '28', + ] + ); + } + + public function testDateAndOrTime_DateWithDay() + { + $this->assertDateAndOrTimeEqualsTo( + '---28', + [ + 'date' => '28', + ] + ); + } + + public function testDateAndOrTime_TimeWithHour() + { + $this->assertDateAndOrTimeEqualsTo( + '13', + [ + 'hour' => '13', + ] + ); + } + + public function testDateAndOrTime_TimeWithHourMinute() + { + $this->assertDateAndOrTimeEqualsTo( + '1353', + [ + 'hour' => '13', + 'minute' => '53', + ] + ); + } + + public function testDateAndOrTime_TimeWithHourSecond() + { + $this->assertDateAndOrTimeEqualsTo( + '135301', + [ + 'hour' => '13', + 'minute' => '53', + 'second' => '01', + ] + ); + } + + public function testDateAndOrTime_TimeWithMinute() + { + $this->assertDateAndOrTimeEqualsTo( + '-53', + [ + 'minute' => '53', + ] + ); + } + + public function testDateAndOrTime_TimeWithMinuteSecond() + { + $this->assertDateAndOrTimeEqualsTo( + '-5301', + [ + 'minute' => '53', + 'second' => '01', + ] + ); + } + + public function testDateAndOrTime_TimeWithSecond() + { + $this->assertTrue(true); + + /* + * This is unreachable due to a conflict between date and time pattern. + * This is an error in the specification, not in our implementation. + */ + } + + public function testDateAndOrTime_TimeWithSecondZ() + { + $this->assertDateAndOrTimeEqualsTo( + '--01Z', + [ + 'second' => '01', + 'timezone' => 'Z', + ] + ); + } + + public function testDateAndOrTime_TimeWithSecondTZ() + { + $this->assertDateAndOrTimeEqualsTo( + '--01+1234', + [ + 'second' => '01', + 'timezone' => '+1234', + ] + ); + } + + public function testDateAndOrTime_DateTimeWithYearMonthDayHour() + { + $this->assertDateAndOrTimeEqualsTo( + '20150128T13', + [ + 'year' => '2015', + 'month' => '01', + 'date' => '28', + 'hour' => '13', + ] + ); + } + + public function testDateAndOrTime_DateTimeWithMonthDayHour() + { + $this->assertDateAndOrTimeEqualsTo( + '--0128T13', + [ + 'month' => '01', + 'date' => '28', + 'hour' => '13', + ] + ); + } + + public function testDateAndOrTime_DateTimeWithDayHour() + { + $this->assertDateAndOrTimeEqualsTo( + '---28T13', + [ + 'date' => '28', + 'hour' => '13', + ] + ); + } + + public function testDateAndOrTime_DateTimeWithDayHourMinute() + { + $this->assertDateAndOrTimeEqualsTo( + '---28T1353', + [ + 'date' => '28', + 'hour' => '13', + 'minute' => '53', + ] + ); + } + + public function testDateAndOrTime_DateTimeWithDayHourMinuteSecond() + { + $this->assertDateAndOrTimeEqualsTo( + '---28T135301', + [ + 'date' => '28', + 'hour' => '13', + 'minute' => '53', + 'second' => '01', + ] + ); + } + + public function testDateAndOrTime_DateTimeWithDayHourZ() + { + $this->assertDateAndOrTimeEqualsTo( + '---28T13Z', + [ + 'date' => '28', + 'hour' => '13', + 'timezone' => 'Z', + ] + ); + } + + public function testDateAndOrTime_DateTimeWithDayHourTZ() + { + $this->assertDateAndOrTimeEqualsTo( + '---28T13+1234', + [ + 'date' => '28', + 'hour' => '13', + 'timezone' => '+1234', + ] + ); + } + + protected function assertDateAndOrTimeEqualsTo($date, $parts) + { + $this->assertSame( + DateTimeParser::parseVCardDateAndOrTime($date), + array_merge( + [ + 'year' => null, + 'month' => null, + 'date' => null, + 'hour' => null, + 'minute' => null, + 'second' => null, + 'timezone' => null, + ], + $parts + ) + ); + } +} diff --git a/vendor/sabre/vobject/tests/VObject/DocumentTest.php b/vendor/sabre/vobject/tests/VObject/DocumentTest.php new file mode 100644 index 000000000..2665406f6 --- /dev/null +++ b/vendor/sabre/vobject/tests/VObject/DocumentTest.php @@ -0,0 +1,84 @@ +<?php + +namespace Sabre\VObject; + +use PHPUnit\Framework\TestCase; + +class DocumentTest extends TestCase +{ + public function testGetDocumentType() + { + $doc = new MockDocument(); + $this->assertEquals(Document::UNKNOWN, $doc->getDocumentType()); + } + + public function testConstruct() + { + $doc = new MockDocument('VLIST'); + $this->assertEquals('VLIST', $doc->name); + } + + public function testCreateComponent() + { + $vcal = new Component\VCalendar([], false); + + $event = $vcal->createComponent('VEVENT'); + + $this->assertInstanceOf('Sabre\VObject\Component\VEvent', $event); + $vcal->add($event); + + $prop = $vcal->createProperty('X-PROP', '1234256', ['X-PARAM' => '3']); + $this->assertInstanceOf('Sabre\VObject\Property', $prop); + + $event->add($prop); + + unset( + $event->DTSTAMP, + $event->UID + ); + + $out = $vcal->serialize(); + $this->assertEquals("BEGIN:VCALENDAR\r\nBEGIN:VEVENT\r\nX-PROP;X-PARAM=3:1234256\r\nEND:VEVENT\r\nEND:VCALENDAR\r\n", $out); + } + + public function testCreate() + { + $vcal = new Component\VCalendar([], false); + + $event = $vcal->create('VEVENT'); + $this->assertInstanceOf('Sabre\VObject\Component\VEvent', $event); + + $prop = $vcal->create('CALSCALE'); + $this->assertInstanceOf('Sabre\VObject\Property\Text', $prop); + } + + public function testGetClassNameForPropertyValue() + { + $vcal = new Component\VCalendar([], false); + $this->assertEquals('Sabre\\VObject\\Property\\Text', $vcal->getClassNameForPropertyValue('TEXT')); + $this->assertNull($vcal->getClassNameForPropertyValue('FOO')); + } + + public function testDestroy() + { + $vcal = new Component\VCalendar([], false); + $event = $vcal->createComponent('VEVENT'); + + $this->assertInstanceOf('Sabre\VObject\Component\VEvent', $event); + $vcal->add($event); + + $prop = $vcal->createProperty('X-PROP', '1234256', ['X-PARAM' => '3']); + + $event->add($prop); + + $this->assertEquals($event, $prop->parent); + + $vcal->destroy(); + + $this->assertNull($prop->parent); + } +} + +class MockDocument extends Document +{ +} diff --git a/vendor/sabre/vobject/tests/VObject/ElementListTest.php b/vendor/sabre/vobject/tests/VObject/ElementListTest.php new file mode 100644 index 000000000..1842ca963 --- /dev/null +++ b/vendor/sabre/vobject/tests/VObject/ElementListTest.php @@ -0,0 +1,30 @@ +<?php + +namespace Sabre\VObject; + +use PHPUnit\Framework\TestCase; + +class ElementListTest extends TestCase +{ + public function testIterate() + { + $cal = new Component\VCalendar(); + $sub = $cal->createComponent('VEVENT'); + + $elems = [ + $sub, + clone $sub, + clone $sub, + ]; + + $elemList = new ElementList($elems); + + $count = 0; + foreach ($elemList as $key => $subcomponent) { + ++$count; + $this->assertInstanceOf('Sabre\\VObject\\Component', $subcomponent); + } + $this->assertEquals(3, $count); + $this->assertEquals(2, $key); + } +} diff --git a/vendor/sabre/vobject/tests/VObject/EmClientTest.php b/vendor/sabre/vobject/tests/VObject/EmClientTest.php new file mode 100644 index 000000000..bb586ba97 --- /dev/null +++ b/vendor/sabre/vobject/tests/VObject/EmClientTest.php @@ -0,0 +1,55 @@ +<?php + +namespace Sabre\VObject; + +use DateTimeImmutable; +use PHPUnit\Framework\TestCase; + +class EmClientTest extends TestCase +{ + public function testParseTz() + { + $str = 'BEGIN:VCALENDAR +X-WR-CALNAME:Blackhawks Schedule 2011-12 +X-APPLE-CALENDAR-COLOR:#E51717 +X-WR-TIMEZONE:America/Chicago +CALSCALE:GREGORIAN +PRODID:-//eM Client/4.0.13961.0 +VERSION:2.0 +BEGIN:VTIMEZONE +TZID:America/Chicago +BEGIN:DAYLIGHT +TZOFFSETFROM:-0600 +RRULE:FREQ=YEARLY;BYDAY=2SU;BYMONTH=3 +DTSTART:20070311T020000 +TZNAME:CDT +TZOFFSETTO:-0500 +END:DAYLIGHT +BEGIN:STANDARD +TZOFFSETFROM:-0500 +RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=11 +DTSTART:20071104T020000 +TZNAME:CST +TZOFFSETTO:-0600 +END:STANDARD +END:VTIMEZONE +BEGIN:VEVENT +CREATED:20110624T181236Z +UID:be3bbfff-96e8-4c66-9908-ab791a62231d +DTEND;TZID="America/Chicago":20111008T223000 +TRANSP:OPAQUE +SUMMARY:Stars @ Blackhawks (Home Opener) +DTSTART;TZID="America/Chicago":20111008T193000 +DTSTAMP:20120330T013232Z +SEQUENCE:2 +X-MICROSOFT-CDO-BUSYSTATUS:BUSY +LAST-MODIFIED:20120330T013237Z +CLASS:PUBLIC +END:VEVENT +END:VCALENDAR'; + + $vObject = Reader::read($str); + $dt = $vObject->VEVENT->DTSTART->getDateTime(); + $this->assertEquals(new DateTimeImmutable('2011-10-08 19:30:00', new \DateTimeZone('America/Chicago')), $dt); + } +} diff --git a/vendor/sabre/vobject/tests/VObject/EmptyParameterTest.php b/vendor/sabre/vobject/tests/VObject/EmptyParameterTest.php new file mode 100644 index 000000000..213e69ab8 --- /dev/null +++ b/vendor/sabre/vobject/tests/VObject/EmptyParameterTest.php @@ -0,0 +1,69 @@ +<?php + +namespace Sabre\VObject; + +use PHPUnit\Framework\TestCase; + +class EmptyParameterTest extends TestCase +{ + public function testRead() + { + $input = <<<VCF +BEGIN:VCARD +VERSION:2.1 +N:Doe;Jon;;; +FN:Jon Doe +EMAIL;X-INTERN:foo@example.org +UID:foo +END:VCARD +VCF; + + $vcard = Reader::read($input); + + $this->assertInstanceOf('Sabre\\VObject\\Component\\VCard', $vcard); + $vcard = $vcard->convert(\Sabre\VObject\Document::VCARD30); + $vcard = $vcard->serialize(); + + $converted = Reader::read($vcard); + $converted->validate(); + + $this->assertTrue(isset($converted->EMAIL['X-INTERN'])); + + $version = Version::VERSION; + + $expected = <<<VCF +BEGIN:VCARD +VERSION:3.0 +PRODID:-//Sabre//Sabre VObject $version//EN +N:Doe;Jon;;; +FN:Jon Doe +EMAIL;X-INTERN=:foo@example.org +UID:foo +END:VCARD + +VCF; + + $this->assertEquals($expected, str_replace("\r", '', $vcard)); + } + + public function testVCard21Parameter() + { + $vcard = new Component\VCard([], false); + $vcard->VERSION = '2.1'; + $vcard->PHOTO = 'random_stuff'; + $vcard->PHOTO->add(null, 'BASE64'); + $vcard->UID = 'foo-bar'; + + $result = $vcard->serialize(); + $expected = [ + 'BEGIN:VCARD', + 'VERSION:2.1', + 'PHOTO;BASE64:'.base64_encode('random_stuff'), + 'UID:foo-bar', + 'END:VCARD', + '', + ]; + + $this->assertEquals(implode("\r\n", $expected), $result); + } +} diff --git a/vendor/sabre/vobject/tests/VObject/EmptyValueIssueTest.php b/vendor/sabre/vobject/tests/VObject/EmptyValueIssueTest.php new file mode 100644 index 000000000..91a4d84f6 --- /dev/null +++ b/vendor/sabre/vobject/tests/VObject/EmptyValueIssueTest.php @@ -0,0 +1,30 @@ +<?php + +namespace Sabre\VObject; + +use PHPUnit\Framework\TestCase; + +/** + * This test is written for Issue 68:. + * + * https://github.com/fruux/sabre-vobject/issues/68 + */ +class EmptyValueIssueTest extends TestCase +{ + public function testDecodeValue() + { + $input = <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +BEGIN:VEVENT +DESCRIPTION:This is a descpription\\nwith a linebreak and a \\; \\, and : +END:VEVENT +END:VCALENDAR +ICS; + + $vobj = Reader::read($input); + + // Before this bug was fixed, getValue() would return nothing. + $this->assertEquals("This is a descpription\nwith a linebreak and a ; , and :", $vobj->VEVENT->DESCRIPTION->getValue()); + } +} diff --git a/vendor/sabre/vobject/tests/VObject/FreeBusyDataTest.php b/vendor/sabre/vobject/tests/VObject/FreeBusyDataTest.php new file mode 100644 index 000000000..9e5143f65 --- /dev/null +++ b/vendor/sabre/vobject/tests/VObject/FreeBusyDataTest.php @@ -0,0 +1,311 @@ +<?php + +namespace Sabre\VObject; + +use PHPUnit\Framework\TestCase; + +class FreeBusyDataTest extends TestCase +{ + public function testGetData() + { + $fb = new FreeBusyData(100, 200); + + $this->assertEquals( + [ + [ + 'start' => 100, + 'end' => 200, + 'type' => 'FREE', + ], + ], + $fb->getData() + ); + } + + /** + * @depends testGetData + */ + public function testAddBeginning() + { + $fb = new FreeBusyData(100, 200); + + // Overwriting the first half + $fb->add(100, 150, 'BUSY'); + + $this->assertEquals( + [ + [ + 'start' => 100, + 'end' => 150, + 'type' => 'BUSY', + ], + [ + 'start' => 150, + 'end' => 200, + 'type' => 'FREE', + ], + ], + $fb->getData() + ); + + // Overwriting the first half again + $fb->add(100, 150, 'BUSY-TENTATIVE'); + + $this->assertEquals( + [ + [ + 'start' => 100, + 'end' => 150, + 'type' => 'BUSY-TENTATIVE', + ], + [ + 'start' => 150, + 'end' => 200, + 'type' => 'FREE', + ], + ], + $fb->getData() + ); + } + + /** + * @depends testAddBeginning + */ + public function testAddEnd() + { + $fb = new FreeBusyData(100, 200); + + // Overwriting the first half + $fb->add(150, 200, 'BUSY'); + + $this->assertEquals( + [ + [ + 'start' => 100, + 'end' => 150, + 'type' => 'FREE', + ], + [ + 'start' => 150, + 'end' => 200, + 'type' => 'BUSY', + ], + ], + $fb->getData() + ); + } + + /** + * @depends testAddEnd + */ + public function testAddMiddle() + { + $fb = new FreeBusyData(100, 200); + + // Overwriting the first half + $fb->add(150, 160, 'BUSY'); + + $this->assertEquals( + [ + [ + 'start' => 100, + 'end' => 150, + 'type' => 'FREE', + ], + [ + 'start' => 150, + 'end' => 160, + 'type' => 'BUSY', + ], + [ + 'start' => 160, + 'end' => 200, + 'type' => 'FREE', + ], + ], + $fb->getData() + ); + } + + /** + * @depends testAddMiddle + */ + public function testAddMultiple() + { + $fb = new FreeBusyData(100, 200); + + $fb->add(110, 120, 'BUSY'); + $fb->add(130, 140, 'BUSY'); + + $this->assertEquals( + [ + [ + 'start' => 100, + 'end' => 110, + 'type' => 'FREE', + ], + [ + 'start' => 110, + 'end' => 120, + 'type' => 'BUSY', + ], + [ + 'start' => 120, + 'end' => 130, + 'type' => 'FREE', + ], + [ + 'start' => 130, + 'end' => 140, + 'type' => 'BUSY', + ], + [ + 'start' => 140, + 'end' => 200, + 'type' => 'FREE', + ], + ], + $fb->getData() + ); + } + + /** + * @depends testAddMultiple + */ + public function testAddMultipleOverlap() + { + $fb = new FreeBusyData(100, 200); + + $fb->add(110, 120, 'BUSY'); + $fb->add(130, 140, 'BUSY'); + + $this->assertEquals( + [ + [ + 'start' => 100, + 'end' => 110, + 'type' => 'FREE', + ], + [ + 'start' => 110, + 'end' => 120, + 'type' => 'BUSY', + ], + [ + 'start' => 120, + 'end' => 130, + 'type' => 'FREE', + ], + [ + 'start' => 130, + 'end' => 140, + 'type' => 'BUSY', + ], + [ + 'start' => 140, + 'end' => 200, + 'type' => 'FREE', + ], + ], + $fb->getData() + ); + + $fb->add(115, 135, 'BUSY-TENTATIVE'); + + $this->assertEquals( + [ + [ + 'start' => 100, + 'end' => 110, + 'type' => 'FREE', + ], + [ + 'start' => 110, + 'end' => 115, + 'type' => 'BUSY', + ], + [ + 'start' => 115, + 'end' => 135, + 'type' => 'BUSY-TENTATIVE', + ], + [ + 'start' => 135, + 'end' => 140, + 'type' => 'BUSY', + ], + [ + 'start' => 140, + 'end' => 200, + 'type' => 'FREE', + ], + ], + $fb->getData() + ); + } + + /** + * @depends testAddMultipleOverlap + */ + public function testAddMultipleOverlapAndMerge() + { + $fb = new FreeBusyData(100, 200); + + $fb->add(110, 120, 'BUSY'); + $fb->add(130, 140, 'BUSY'); + + $this->assertEquals( + [ + [ + 'start' => 100, + 'end' => 110, + 'type' => 'FREE', + ], + [ + 'start' => 110, + 'end' => 120, + 'type' => 'BUSY', + ], + [ + 'start' => 120, + 'end' => 130, + 'type' => 'FREE', + ], + [ + 'start' => 130, + 'end' => 140, + 'type' => 'BUSY', + ], + [ + 'start' => 140, + 'end' => 200, + 'type' => 'FREE', + ], + ], + $fb->getData() + ); + + $fb->add(115, 135, 'BUSY'); + + $this->assertEquals( + [ + [ + 'start' => 100, + 'end' => 110, + 'type' => 'FREE', + ], + [ + 'start' => 110, + 'end' => 140, + 'type' => 'BUSY', + ], + [ + 'start' => 140, + 'end' => 200, + 'type' => 'FREE', + ], + ], + $fb->getData() + ); + } +} diff --git a/vendor/sabre/vobject/tests/VObject/FreeBusyGeneratorTest.php b/vendor/sabre/vobject/tests/VObject/FreeBusyGeneratorTest.php new file mode 100644 index 000000000..e2dd59409 --- /dev/null +++ b/vendor/sabre/vobject/tests/VObject/FreeBusyGeneratorTest.php @@ -0,0 +1,721 @@ +<?php + +namespace Sabre\VObject; + +use PHPUnit\Framework\TestCase; + +class FreeBusyGeneratorTest extends TestCase +{ + use PHPUnitAssertions; + + public function testGeneratorBaseObject() + { + $obj = new Component\VCalendar(); + $obj->METHOD = 'PUBLISH'; + + $gen = new FreeBusyGenerator(); + $gen->setObjects([]); + $gen->setBaseObject($obj); + + $result = $gen->getResult(); + + $this->assertEquals('PUBLISH', $result->METHOD->getValue()); + } + + /** + * @expectedException \InvalidArgumentException + */ + public function testInvalidArg() + { + $gen = new FreeBusyGenerator( + new \DateTime('2012-01-01'), + new \DateTime('2012-12-31'), + new \stdClass() + ); + } + + /** + * This function takes a list of objects (icalendar objects), and turns + * them into a freebusy report. + * + * Then it takes the expected output and compares it to what we actually + * got. + * + * It only generates the freebusy report for the following time-range: + * 2011-01-01 11:00:00 until 2011-01-03 11:11:11 + * + * @param string $expected + * @param array $input + * @param string|null $timeZone + * @param string $vavailability + */ + public function assertFreeBusyReport($expected, $input, $timeZone = null, $vavailability = null) + { + $gen = new FreeBusyGenerator( + new \DateTime('20110101T110000Z', new \DateTimeZone('UTC')), + new \DateTime('20110103T110000Z', new \DateTimeZone('UTC')), + $input, + $timeZone + ); + + if ($vavailability) { + if (is_string($vavailability)) { + $vavailability = Reader::read($vavailability); + } + $gen->setVAvailability($vavailability); + } + + $output = $gen->getResult(); + + // Removing DTSTAMP because it changes every time. + unset($output->VFREEBUSY->DTSTAMP); + + $expected = <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +BEGIN:VFREEBUSY +DTSTART:20110101T110000Z +DTEND:20110103T110000Z +$expected +END:VFREEBUSY +END:VCALENDAR +ICS; + + $this->assertVObjectEqualsVObject($expected, $output); + } + + public function testSimple() + { + $blob = <<<ICS +BEGIN:VCALENDAR +BEGIN:VEVENT +UID:foobar +DTSTART:20110101T120000Z +DTEND:20110101T130000Z +END:VEVENT +END:VCALENDAR +ICS; + + $this->assertFreeBusyReport( + 'FREEBUSY:20110101T120000Z/20110101T130000Z', + $blob + ); + } + + public function testSource() + { + $blob = <<<ICS +BEGIN:VCALENDAR +BEGIN:VEVENT +UID:foobar +DTSTART:20110101T120000Z +DTEND:20110101T130000Z +END:VEVENT +END:VCALENDAR +ICS; + $h = fopen('php://memory', 'r+'); + fwrite($h, $blob); + rewind($h); + + $this->assertFreeBusyReport( + 'FREEBUSY:20110101T120000Z/20110101T130000Z', + $h + ); + } + + /** + * Testing TRANSP:OPAQUE. + */ + public function testOpaque() + { + $blob = <<<ICS +BEGIN:VCALENDAR +BEGIN:VEVENT +UID:foobar2 +TRANSP:OPAQUE +DTSTART:20110101T130000Z +DTEND:20110101T140000Z +END:VEVENT +END:VCALENDAR +ICS; + + $this->assertFreeBusyReport( + 'FREEBUSY:20110101T130000Z/20110101T140000Z', + $blob + ); + } + + /** + * Testing TRANSP:TRANSPARENT. + */ + public function testTransparent() + { + // transparent, hidden + $blob = <<<ICS +BEGIN:VCALENDAR +BEGIN:VEVENT +UID:foobar3 +TRANSP:TRANSPARENT +DTSTART:20110101T140000Z +DTEND:20110101T150000Z +END:VEVENT +END:VCALENDAR +ICS; + + $this->assertFreeBusyReport( + '', + $blob + ); + } + + /** + * Testing STATUS:CANCELLED. + */ + public function testCancelled() + { + // transparent, hidden + $blob = <<<ICS +BEGIN:VCALENDAR +BEGIN:VEVENT +UID:foobar4 +STATUS:CANCELLED +DTSTART:20110101T160000Z +DTEND:20110101T170000Z +END:VEVENT +END:VCALENDAR +ICS; + + $this->assertFreeBusyReport( + '', + $blob + ); + } + + /** + * Testing STATUS:TENTATIVE. + */ + public function testTentative() + { + // tentative, shows up + $blob = <<<ICS +BEGIN:VCALENDAR +BEGIN:VEVENT +UID:foobar5 +STATUS:TENTATIVE +DTSTART:20110101T180000Z +DTEND:20110101T190000Z +END:VEVENT +END:VCALENDAR +ICS; + + $this->assertFreeBusyReport( + 'FREEBUSY;FBTYPE=BUSY-TENTATIVE:20110101T180000Z/20110101T190000Z', + $blob + ); + } + + /** + * Testing an event that falls outside of the report time-range. + */ + public function testOutsideTimeRange() + { + // outside of time-range, hidden + $blob = <<<ICS +BEGIN:VCALENDAR +BEGIN:VEVENT +UID:foobar6 +DTSTART:20110101T090000Z +DTEND:20110101T100000Z +END:VEVENT +END:VCALENDAR +ICS; + + $this->assertFreeBusyReport( + '', + $blob + ); + } + + /** + * Testing an event that falls outside of the report time-range. + */ + public function testOutsideTimeRange2() + { + // outside of time-range, hidden + $blob = <<<ICS +BEGIN:VCALENDAR +BEGIN:VEVENT +UID:foobar7 +DTSTART:20110104T090000Z +DTEND:20110104T100000Z +END:VEVENT +END:VCALENDAR +ICS; + + $this->assertFreeBusyReport( + '', + $blob + ); + } + + /** + * Testing an event that uses DURATION. + */ + public function testDuration() + { + // using duration, shows up + $blob = <<<ICS +BEGIN:VCALENDAR +BEGIN:VEVENT +UID:foobar8 +DTSTART:20110101T190000Z +DURATION:PT1H +END:VEVENT +END:VCALENDAR +ICS; + + $this->assertFreeBusyReport( + 'FREEBUSY:20110101T190000Z/20110101T200000Z', + $blob + ); + } + + /** + * Testing an all-day event. + */ + public function testAllDay() + { + // Day-long event, shows up + $blob = <<<ICS +BEGIN:VCALENDAR +BEGIN:VEVENT +UID:foobar9 +DTSTART;VALUE=DATE:20110102 +END:VEVENT +END:VCALENDAR +ICS; + + $this->assertFreeBusyReport( + 'FREEBUSY:20110102T000000Z/20110103T000000Z', + $blob + ); + } + + /** + * Testing an event that has no end or duration. + */ + public function testNoDuration() + { + // No duration, does not show up + $blob = <<<ICS +BEGIN:VCALENDAR +BEGIN:VEVENT +UID:foobar10 +DTSTART:20110101T200000Z +END:VEVENT +END:VCALENDAR +ICS; + + $this->assertFreeBusyReport( + '', + $blob + ); + } + + /** + * Testing feeding the freebusy generator an object instead of a string. + */ + public function testObject() + { + // encoded as object, shows up + $blob = <<<ICS +BEGIN:VCALENDAR +BEGIN:VEVENT +UID:foobar11 +DTSTART:20110101T210000Z +DURATION:PT1H +END:VEVENT +END:VCALENDAR +ICS; + + $this->assertFreeBusyReport( + 'FREEBUSY:20110101T210000Z/20110101T220000Z', + Reader::read($blob) + ); + } + + /** + * Testing feeding VFREEBUSY objects instead of VEVENT. + */ + public function testVFreeBusy() + { + // Freebusy. Some parts show up + $blob = <<<ICS +BEGIN:VCALENDAR +BEGIN:VFREEBUSY +FREEBUSY:20110103T010000Z/20110103T020000Z +FREEBUSY;FBTYPE=FREE:20110103T020000Z/20110103T030000Z +FREEBUSY:20110103T030000Z/20110103T040000Z,20110103T040000Z/20110103T050000Z +FREEBUSY:20120101T000000Z/20120101T010000Z +FREEBUSY:20110103T050000Z/PT1H +END:VFREEBUSY +END:VCALENDAR +ICS; + + $this->assertFreeBusyReport( + "FREEBUSY:20110103T010000Z/20110103T020000Z\n". + 'FREEBUSY:20110103T030000Z/20110103T060000Z', + $blob + ); + } + + public function testYearlyRecurrence() + { + // Yearly recurrence rule, shows up + $blob = <<<ICS +BEGIN:VCALENDAR +BEGIN:VEVENT +UID:foobar13 +DTSTART:20100101T220000Z +DTEND:20100101T230000Z +RRULE:FREQ=YEARLY +END:VEVENT +END:VCALENDAR +ICS; + + $this->assertFreeBusyReport( + 'FREEBUSY:20110101T220000Z/20110101T230000Z', + $blob + ); + } + + public function testYearlyRecurrenceDuration() + { + // Yearly recurrence rule + duration, shows up + $blob = <<<ICS +BEGIN:VCALENDAR +BEGIN:VEVENT +UID:foobar14 +DTSTART:20100101T230000Z +DURATION:PT1H +RRULE:FREQ=YEARLY +END:VEVENT +END:VCALENDAR +ICS; + + $this->assertFreeBusyReport( + 'FREEBUSY:20110101T230000Z/20110102T000000Z', + $blob + ); + } + + public function testFloatingTime() + { + // Floating time, no timezone + $blob = <<<ICS +BEGIN:VCALENDAR +BEGIN:VEVENT +UID:foobar +DTSTART:20110101T120000 +DTEND:20110101T130000 +END:VEVENT +END:VCALENDAR +ICS; + + $this->assertFreeBusyReport( + 'FREEBUSY:20110101T120000Z/20110101T130000Z', + $blob + ); + } + + public function testFloatingTimeReferenceTimeZone() + { + // Floating time + reference timezone + $blob = <<<ICS +BEGIN:VCALENDAR +BEGIN:VEVENT +UID:foobar +DTSTART:20110101T120000 +DTEND:20110101T130000 +END:VEVENT +END:VCALENDAR +ICS; + + $this->assertFreeBusyReport( + 'FREEBUSY:20110101T170000Z/20110101T180000Z', + $blob, + new \DateTimeZone('America/Toronto') + ); + } + + public function testAllDay2() + { + // All-day event, slightly outside of the VFREEBUSY range. + $blob = <<<ICS +BEGIN:VCALENDAR +BEGIN:VEVENT +UID:foobar +DTSTART;VALUE=DATE:20110101 +END:VEVENT +END:VCALENDAR +ICS; + + $this->assertFreeBusyReport( + 'FREEBUSY:20110101T110000Z/20110102T000000Z', + $blob + ); + } + + public function testAllDayReferenceTimeZone() + { + // All-day event + reference timezone + $blob = <<<ICS +BEGIN:VCALENDAR +BEGIN:VEVENT +UID:foobar +DTSTART;VALUE=DATE:20110101 +END:VEVENT +END:VCALENDAR +ICS; + + $this->assertFreeBusyReport( + 'FREEBUSY:20110101T110000Z/20110102T050000Z', + $blob, + new \DateTimeZone('America/Toronto') + ); + } + + public function testNoValidInstances() + { + // Recurrence rule with no valid instances + $blob = <<<ICS +BEGIN:VCALENDAR +BEGIN:VEVENT +UID:foobar +DTSTART:20110101T100000Z +DTEND:20110103T120000Z +RRULE:FREQ=WEEKLY;COUNT=1 +EXDATE:20110101T100000Z +END:VEVENT +END:VCALENDAR +ICS; + + $this->assertFreeBusyReport( + '', + $blob + ); + } + + /** + * This VAVAILABILITY object overlaps with the time-range, but we're just + * busy the entire time. + */ + public function testVAvailabilitySimple() + { + $blob = <<<ICS +BEGIN:VCALENDAR +BEGIN:VEVENT +UID:lalala +DTSTART:20110101T120000Z +DTEND:20110101T130000Z +END:VEVENT +END:VCALENDAR +ICS; + + $vavail = <<<ICS +BEGIN:VCALENDAR +BEGIN:VAVAILABILITY +DTSTART:20110101T000000Z +DTEND:20120101T000000Z +BEGIN:AVAILABLE +DTSTART:20110101T000000Z +DTEND:20110101T010000Z +END:AVAILABLE +END:VAVAILABILITY +END:VCALENDAR +ICS; + + $this->assertFreeBusyReport( + "FREEBUSY;FBTYPE=BUSY-UNAVAILABLE:20110101T110000Z/20110101T120000Z\n". + "FREEBUSY:20110101T120000Z/20110101T130000Z\n". + 'FREEBUSY;FBTYPE=BUSY-UNAVAILABLE:20110101T130000Z/20110103T110000Z', + $blob, + null, + $vavail + ); + } + + /** + * This VAVAILABILITY object does not overlap at all with the freebusy + * report, so it should be ignored. + */ + public function testVAvailabilityIrrelevant() + { + $blob = <<<ICS +BEGIN:VCALENDAR +BEGIN:VEVENT +UID:lalala +DTSTART:20110101T120000Z +DTEND:20110101T130000Z +END:VEVENT +END:VCALENDAR +ICS; + + $vavail = <<<ICS +BEGIN:VCALENDAR +BEGIN:VAVAILABILITY +DTSTART:20150101T000000Z +DTEND:20160101T000000Z +BEGIN:AVAILABLE +DTSTART:20150101T000000Z +DTEND:20150101T010000Z +END:AVAILABLE +END:VAVAILABILITY +END:VCALENDAR +ICS; + + $this->assertFreeBusyReport( + 'FREEBUSY:20110101T120000Z/20110101T130000Z', + $blob, + null, + $vavail + ); + } + + /** + * This VAVAILABILITY object has a 9am-5pm AVAILABLE object for office + * hours. + */ + public function testVAvailabilityOfficeHours() + { + $blob = <<<ICS +BEGIN:VCALENDAR +BEGIN:VEVENT +UID:lalala +DTSTART:20110101T120000Z +DTEND:20110101T130000Z +END:VEVENT +END:VCALENDAR +ICS; + + $vavail = <<<ICS +BEGIN:VCALENDAR +BEGIN:VAVAILABILITY +DTSTART:20100101T000000Z +DTEND:20120101T000000Z +BUSYTYPE:BUSY-TENTATIVE +BEGIN:AVAILABLE +DTSTART:20101213T090000Z +DTEND:20101213T170000Z +RRULE:FREQ=WEEKLY;BYDAY=MO,TU,WE,TH,FR +END:AVAILABLE +END:VAVAILABILITY +END:VCALENDAR +ICS; + + $this->assertFreeBusyReport( + "FREEBUSY;FBTYPE=BUSY-TENTATIVE:20110101T110000Z/20110101T120000Z\n". + "FREEBUSY:20110101T120000Z/20110101T130000Z\n". + "FREEBUSY;FBTYPE=BUSY-TENTATIVE:20110101T130000Z/20110103T090000Z\n", + $blob, + null, + $vavail + ); + } + + /** + * This test has the same office hours, but has a vacation blocked off for + * the relevant time, using a higher priority. (lower number). + */ + public function testVAvailabilityOfficeHoursVacation() + { + $blob = <<<ICS +BEGIN:VCALENDAR +BEGIN:VEVENT +UID:lalala +DTSTART:20110101T120000Z +DTEND:20110101T130000Z +END:VEVENT +END:VCALENDAR +ICS; + + $vavail = <<<ICS +BEGIN:VCALENDAR +BEGIN:VAVAILABILITY +DTSTART:20100101T000000Z +DTEND:20120101T000000Z +BUSYTYPE:BUSY-TENTATIVE +PRIORITY:2 +BEGIN:AVAILABLE +DTSTART:20101213T090000Z +DTEND:20101213T170000Z +RRULE:FREQ=WEEKLY;BYDAY=MO,TU,WE,TH,FR +END:AVAILABLE +END:VAVAILABILITY +BEGIN:VAVAILABILITY +PRIORITY:1 +DTSTART:20101214T000000Z +DTEND:20110107T000000Z +BUSYTYPE:BUSY +END:VAVAILABILITY +END:VCALENDAR +ICS; + + $this->assertFreeBusyReport( + 'FREEBUSY:20110101T110000Z/20110103T110000Z', + $blob, + null, + $vavail + ); + } + + /** + * This test has the same input as the last, except somebody mixed up the + * PRIORITY values. + * + * The end-result is that the vacation VAVAILABILITY is completely ignored. + */ + public function testVAvailabilityOfficeHoursVacation2() + { + $blob = <<<ICS +BEGIN:VCALENDAR +BEGIN:VEVENT +UID:lalala +DTSTART:20110101T120000Z +DTEND:20110101T130000Z +END:VEVENT +END:VCALENDAR +ICS; + + $vavail = <<<ICS +BEGIN:VCALENDAR +BEGIN:VAVAILABILITY +DTSTART:20100101T000000Z +DTEND:20120101T000000Z +BUSYTYPE:BUSY-TENTATIVE +PRIORITY:1 +BEGIN:AVAILABLE +DTSTART:20101213T090000Z +DTEND:20101213T170000Z +RRULE:FREQ=WEEKLY;BYDAY=MO,TU,WE,TH,FR +END:AVAILABLE +END:VAVAILABILITY +BEGIN:VAVAILABILITY +PRIORITY:2 +DTSTART:20101214T000000Z +DTEND:20110107T000000Z +BUSYTYPE:BUSY +END:VAVAILABILITY +END:VCALENDAR +ICS; + + $this->assertFreeBusyReport( + "FREEBUSY;FBTYPE=BUSY-TENTATIVE:20110101T110000Z/20110101T120000Z\n". + "FREEBUSY:20110101T120000Z/20110101T130000Z\n". + "FREEBUSY;FBTYPE=BUSY-TENTATIVE:20110101T130000Z/20110103T090000Z\n", + $blob, + null, + $vavail + ); + } +} diff --git a/vendor/sabre/vobject/tests/VObject/GoogleColonEscapingTest.php b/vendor/sabre/vobject/tests/VObject/GoogleColonEscapingTest.php new file mode 100644 index 000000000..48bbde07b --- /dev/null +++ b/vendor/sabre/vobject/tests/VObject/GoogleColonEscapingTest.php @@ -0,0 +1,31 @@ +<?php + +namespace Sabre\VObject; + +use PHPUnit\Framework\TestCase; + +/** + * Google produces vcards with a weird escaping of urls. + * + * VObject will provide a workaround for this, so end-user still get expected + * values. + */ +class GoogleColonEscapingTest extends TestCase +{ + public function testDecode() + { + $vcard = <<<VCF +BEGIN:VCARD +VERSION:3.0 +FN:Evert Pot +N:Pot;Evert;;; +EMAIL;TYPE=INTERNET;TYPE=WORK:evert@fruux.com +BDAY:1985-04-07 +item7.URL:http\://www.rooftopsolutions.nl/ +END:VCARD +VCF; + + $vobj = Reader::read($vcard); + $this->assertEquals('http://www.rooftopsolutions.nl/', $vobj->URL->getValue()); + } +} diff --git a/vendor/sabre/vobject/tests/VObject/ICalendar/AttachParseTest.php b/vendor/sabre/vobject/tests/VObject/ICalendar/AttachParseTest.php new file mode 100644 index 000000000..a32a2462e --- /dev/null +++ b/vendor/sabre/vobject/tests/VObject/ICalendar/AttachParseTest.php @@ -0,0 +1,29 @@ +<?php + +namespace Sabre\VObject\ICalendar; + +use PHPUnit\Framework\TestCase; +use Sabre\VObject\Reader; + +class AttachParseTest extends TestCase +{ + /** + * See issue #128 for more info. + */ + public function testParseAttach() + { + $vcal = <<<ICS +BEGIN:VCALENDAR +BEGIN:VEVENT +ATTACH;FMTTYPE=application/postscript:ftp://example.com/pub/reports/r-960812.ps +END:VEVENT +END:VCALENDAR +ICS; + + $vcal = Reader::read($vcal); + $prop = $vcal->VEVENT->ATTACH; + + $this->assertInstanceOf('Sabre\\VObject\\Property\\URI', $prop); + $this->assertEquals('ftp://example.com/pub/reports/r-960812.ps', $prop->getValue()); + } +} diff --git a/vendor/sabre/vobject/tests/VObject/ITip/BrokerAttendeeReplyTest.php b/vendor/sabre/vobject/tests/VObject/ITip/BrokerAttendeeReplyTest.php new file mode 100644 index 000000000..71008c6ae --- /dev/null +++ b/vendor/sabre/vobject/tests/VObject/ITip/BrokerAttendeeReplyTest.php @@ -0,0 +1,1213 @@ +<?php + +namespace Sabre\VObject\ITip; + +class BrokerAttendeeReplyTest extends BrokerTester +{ + public function testAccepted() + { + $oldMessage = <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +BEGIN:VEVENT +UID:foobar +SUMMARY:B-day party +SEQUENCE:1 +ORGANIZER;CN=Strunk:mailto:strunk@example.org +ATTENDEE;CN=One:mailto:one@example.org +DTSTART:20140716T120000Z +END:VEVENT +END:VCALENDAR +ICS; + + $newMessage = <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +BEGIN:VEVENT +UID:foobar +SUMMARY:B-day party +SEQUENCE:1 +ORGANIZER;CN=Strunk:mailto:strunk@example.org +ATTENDEE;PARTSTAT=ACCEPTED;CN=One:mailto:one@example.org +DTSTART:20140716T120000Z +END:VEVENT +END:VCALENDAR +ICS; + + $version = \Sabre\VObject\Version::VERSION; + + $expected = [ + [ + 'uid' => 'foobar', + 'method' => 'REPLY', + 'component' => 'VEVENT', + 'sender' => 'mailto:one@example.org', + 'senderName' => 'One', + 'recipient' => 'mailto:strunk@example.org', + 'recipientName' => 'Strunk', + 'message' => <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +PRODID:-//Sabre//Sabre VObject $version//EN +CALSCALE:GREGORIAN +METHOD:REPLY +BEGIN:VEVENT +UID:foobar +DTSTAMP:**ANY** +SEQUENCE:1 +DTSTART:20140716T120000Z +SUMMARY:B-day party +ORGANIZER;CN=Strunk:mailto:strunk@example.org +ATTENDEE;PARTSTAT=ACCEPTED;CN=One:mailto:one@example.org +END:VEVENT +END:VCALENDAR +ICS + ], + ]; + + $this->parse($oldMessage, $newMessage, $expected); + } + + public function testAcceptedWithTz() + { + $oldMessage = <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +BEGIN:VTIMEZONE +TZID:(UTC+01:00) Brussels\, Copenhagen\, Madrid\, Paris +BEGIN:DAYLIGHT +TZOFFSETFROM:+0100 +TZOFFSETTO:+0200 +TZNAME:CEST +DTSTART:19700329T020000 +RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU +END:DAYLIGHT +BEGIN:STANDARD +TZOFFSETFROM:+0200 +TZOFFSETTO:+0100 +TZNAME:CET +DTSTART:19701025T030000 +RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU +END:STANDARD +END:VTIMEZONE +BEGIN:VEVENT +UID:foobar +SUMMARY:B-day party +SEQUENCE:1 +ORGANIZER;CN=Strunk:mailto:strunk@example.org +ATTENDEE;CN=One:mailto:one@example.org +DTSTART;TZID="(UTC+01:00) Brussels, Copenhagen, Madrid, Paris":20140716T120000Z +DTEND;TZID="(UTC+01:00) Brussels, Copenhagen, Madrid, Paris":20140716T130000Z +END:VEVENT +END:VCALENDAR +ICS; + + $newMessage = <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +BEGIN:VTIMEZONE +TZID:(UTC+01:00) Brussels\, Copenhagen\, Madrid\, Paris +BEGIN:DAYLIGHT +TZOFFSETFROM:+0100 +TZOFFSETTO:+0200 +TZNAME:CEST +DTSTART:19700329T020000 +RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU +END:DAYLIGHT +BEGIN:STANDARD +TZOFFSETFROM:+0200 +TZOFFSETTO:+0100 +TZNAME:CET +DTSTART:19701025T030000 +RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU +END:STANDARD +END:VTIMEZONE +BEGIN:VEVENT +UID:foobar +SUMMARY:B-day party +SEQUENCE:1 +ORGANIZER;CN=Strunk:mailto:strunk@example.org +ATTENDEE;PARTSTAT=ACCEPTED;CN=One:mailto:one@example.org +DTSTART;TZID="(UTC+01:00) Brussels, Copenhagen, Madrid, Paris":20140716T120000Z +DTEND;TZID="(UTC+01:00) Brussels, Copenhagen, Madrid, Paris":20140716T130000Z +END:VEVENT +END:VCALENDAR +ICS; + + $version = \Sabre\VObject\Version::VERSION; + + $expected = [ + [ + 'uid' => 'foobar', + 'method' => 'REPLY', + 'component' => 'VEVENT', + 'sender' => 'mailto:one@example.org', + 'senderName' => 'One', + 'recipient' => 'mailto:strunk@example.org', + 'recipientName' => 'Strunk', + 'message' => <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +PRODID:-//Sabre//Sabre VObject $version//EN +CALSCALE:GREGORIAN +METHOD:REPLY +BEGIN:VTIMEZONE +TZID:(UTC+01:00) Brussels\, Copenhagen\, Madrid\, Paris +BEGIN:DAYLIGHT +TZOFFSETFROM:+0100 +TZOFFSETTO:+0200 +TZNAME:CEST +DTSTART:19700329T020000 +RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU +END:DAYLIGHT +BEGIN:STANDARD +TZOFFSETFROM:+0200 +TZOFFSETTO:+0100 +TZNAME:CET +DTSTART:19701025T030000 +RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU +END:STANDARD +END:VTIMEZONE +BEGIN:VEVENT +UID:foobar +DTSTAMP:**ANY** +SEQUENCE:1 +DTSTART;TZID="(UTC+01:00) Brussels, Copenhagen, Madrid, Paris":20140716T120000Z +DTEND;TZID="(UTC+01:00) Brussels, Copenhagen, Madrid, Paris":20140716T130000Z +SUMMARY:B-day party +ORGANIZER;CN=Strunk:mailto:strunk@example.org +ATTENDEE;PARTSTAT=ACCEPTED;CN=One:mailto:one@example.org +END:VEVENT +END:VCALENDAR +ICS + ], + ]; + + $this->parse($oldMessage, $newMessage, $expected); + } + + public function testRecurringReply() + { + $oldMessage = <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +BEGIN:VEVENT +UID:foobar +SEQUENCE:1 +ORGANIZER;CN=Strunk:mailto:strunk@example.org +ATTENDEE;CN=One:mailto:one@example.org +DTSTART:20140724T120000Z +SUMMARY:Daily sprint +RRULE;FREQ=DAILY +END:VEVENT +END:VCALENDAR +ICS; + + $newMessage = <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +BEGIN:VEVENT +UID:foobar +SEQUENCE:1 +ORGANIZER;CN=Strunk:mailto:strunk@example.org +ATTENDEE;PARTSTAT=NEEDS-ACTION;CN=One:mailto:one@example.org +DTSTART:20140724T120000Z +SUMMARY:Daily sprint +END:VEVENT +BEGIN:VEVENT +UID:foobar +SEQUENCE:1 +ORGANIZER;CN=Strunk:mailto:strunk@example.org +ATTENDEE;PARTSTAT=ACCEPTED;CN=One:mailto:one@example.org +DTSTART:20140726T120000Z +RECURRENCE-ID:20140726T120000Z +END:VEVENT +BEGIN:VEVENT +UID:foobar +SEQUENCE:1 +ORGANIZER;CN=Strunk:mailto:strunk@example.org +ATTENDEE;PARTSTAT=DECLINED;CN=One:mailto:one@example.org +DTSTART:20140724T120000Z +RECURRENCE-ID:20140724T120000Z +END:VEVENT +BEGIN:VEVENT +UID:foobar +SEQUENCE:1 +ORGANIZER;CN=Strunk:mailto:strunk@example.org +ATTENDEE;PARTSTAT=TENTATIVE;CN=One:mailto:one@example.org +DTSTART:20140728T120000Z +RECURRENCE-ID:20140728T120000Z +END:VEVENT +BEGIN:VEVENT +UID:foobar +SEQUENCE:1 +ORGANIZER;CN=Strunk:mailto:strunk@example.org +ATTENDEE;PARTSTAT=ACCEPTED;CN=One:mailto:one@example.org +DTSTART:20140729T120000Z +RECURRENCE-ID:20140729T120000Z +END:VEVENT +BEGIN:VEVENT +UID:foobar +SEQUENCE:1 +ORGANIZER;CN=Strunk:mailto:strunk@example.org +ATTENDEE;PARTSTAT=DECLINED;CN=One:mailto:one@example.org +DTSTART:20140725T120000Z +RECURRENCE-ID:20140725T120000Z +END:VEVENT +END:VCALENDAR +ICS; + + $version = \Sabre\VObject\Version::VERSION; + + $expected = [ + [ + 'uid' => 'foobar', + 'method' => 'REPLY', + 'component' => 'VEVENT', + 'sender' => 'mailto:one@example.org', + 'senderName' => 'One', + 'recipient' => 'mailto:strunk@example.org', + 'recipientName' => 'Strunk', + 'message' => <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +PRODID:-//Sabre//Sabre VObject $version//EN +CALSCALE:GREGORIAN +METHOD:REPLY +BEGIN:VEVENT +UID:foobar +DTSTAMP:**ANY** +SEQUENCE:1 +DTSTART:20140726T120000Z +SUMMARY:Daily sprint +RECURRENCE-ID:20140726T120000Z +ORGANIZER;CN=Strunk:mailto:strunk@example.org +ATTENDEE;PARTSTAT=ACCEPTED;CN=One:mailto:one@example.org +END:VEVENT +BEGIN:VEVENT +UID:foobar +DTSTAMP:**ANY** +SEQUENCE:1 +DTSTART:20140724T120000Z +SUMMARY:Daily sprint +RECURRENCE-ID:20140724T120000Z +ORGANIZER;CN=Strunk:mailto:strunk@example.org +ATTENDEE;PARTSTAT=DECLINED;CN=One:mailto:one@example.org +END:VEVENT +BEGIN:VEVENT +UID:foobar +DTSTAMP:**ANY** +SEQUENCE:1 +DTSTART:20140728T120000Z +SUMMARY:Daily sprint +RECURRENCE-ID:20140728T120000Z +ORGANIZER;CN=Strunk:mailto:strunk@example.org +ATTENDEE;PARTSTAT=TENTATIVE;CN=One:mailto:one@example.org +END:VEVENT +BEGIN:VEVENT +UID:foobar +DTSTAMP:**ANY** +SEQUENCE:1 +DTSTART:20140729T120000Z +SUMMARY:Daily sprint +RECURRENCE-ID:20140729T120000Z +ORGANIZER;CN=Strunk:mailto:strunk@example.org +ATTENDEE;PARTSTAT=ACCEPTED;CN=One:mailto:one@example.org +END:VEVENT +BEGIN:VEVENT +UID:foobar +DTSTAMP:**ANY** +SEQUENCE:1 +DTSTART:20140725T120000Z +SUMMARY:Daily sprint +RECURRENCE-ID:20140725T120000Z +ORGANIZER;CN=Strunk:mailto:strunk@example.org +ATTENDEE;PARTSTAT=DECLINED;CN=One:mailto:one@example.org +END:VEVENT +END:VCALENDAR +ICS + ], + ]; + + $this->parse($oldMessage, $newMessage, $expected); + } + + public function testRecurringAllDay() + { + $oldMessage = <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +BEGIN:VEVENT +UID:foobar +SEQUENCE:1 +ORGANIZER;CN=Strunk:mailto:strunk@example.org +ATTENDEE;CN=One:mailto:one@example.org +DTSTART;VALUE=DATE:20140724 +RRULE;FREQ=DAILY +END:VEVENT +END:VCALENDAR +ICS; + + $newMessage = <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +BEGIN:VEVENT +UID:foobar +SEQUENCE:1 +ORGANIZER;CN=Strunk:mailto:strunk@example.org +ATTENDEE;PARTSTAT=NEEDS-ACTION;CN=One:mailto:one@example.org +DTSTART;VALUE=DATE:20140724 +END:VEVENT +BEGIN:VEVENT +UID:foobar +SEQUENCE:1 +ORGANIZER;CN=Strunk:mailto:strunk@example.org +ATTENDEE;PARTSTAT=ACCEPTED;CN=One:mailto:one@example.org +DTSTART;VALUE=DATE:20140726 +RECURRENCE-ID;VALUE=DATE:20140726 +END:VEVENT +BEGIN:VEVENT +UID:foobar +SEQUENCE:1 +ORGANIZER;CN=Strunk:mailto:strunk@example.org +ATTENDEE;PARTSTAT=DECLINED;CN=One:mailto:one@example.org +DTSTART;VALUE=DATE:20140724 +RECURRENCE-ID;VALUE=DATE:20140724 +END:VEVENT +BEGIN:VEVENT +UID:foobar +SEQUENCE:1 +ORGANIZER;CN=Strunk:mailto:strunk@example.org +ATTENDEE;PARTSTAT=TENTATIVE;CN=One:mailto:one@example.org +DTSTART;VALUE=DATE:20140728 +RECURRENCE-ID;VALUE=DATE:20140728 +END:VEVENT +BEGIN:VEVENT +UID:foobar +SEQUENCE:1 +ORGANIZER;CN=Strunk:mailto:strunk@example.org +ATTENDEE;PARTSTAT=ACCEPTED;CN=One:mailto:one@example.org +DTSTART;VALUE=DATE:20140729 +RECURRENCE-ID;VALUE=DATE:20140729 +END:VEVENT +BEGIN:VEVENT +UID:foobar +SEQUENCE:1 +ORGANIZER;CN=Strunk:mailto:strunk@example.org +ATTENDEE;PARTSTAT=DECLINED;CN=One:mailto:one@example.org +DTSTART;VALUE=DATE:20140725 +RECURRENCE-ID;VALUE=DATE:20140725 +END:VEVENT +END:VCALENDAR +ICS; + + $version = \Sabre\VObject\Version::VERSION; + + $expected = [ + [ + 'uid' => 'foobar', + 'method' => 'REPLY', + 'component' => 'VEVENT', + 'sender' => 'mailto:one@example.org', + 'senderName' => 'One', + 'recipient' => 'mailto:strunk@example.org', + 'recipientName' => 'Strunk', + 'message' => <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +PRODID:-//Sabre//Sabre VObject $version//EN +CALSCALE:GREGORIAN +METHOD:REPLY +BEGIN:VEVENT +UID:foobar +DTSTAMP:**ANY** +SEQUENCE:1 +DTSTART;VALUE=DATE:20140726 +RECURRENCE-ID;VALUE=DATE:20140726 +ORGANIZER;CN=Strunk:mailto:strunk@example.org +ATTENDEE;PARTSTAT=ACCEPTED;CN=One:mailto:one@example.org +END:VEVENT +BEGIN:VEVENT +UID:foobar +DTSTAMP:**ANY** +SEQUENCE:1 +DTSTART;VALUE=DATE:20140724 +RECURRENCE-ID;VALUE=DATE:20140724 +ORGANIZER;CN=Strunk:mailto:strunk@example.org +ATTENDEE;PARTSTAT=DECLINED;CN=One:mailto:one@example.org +END:VEVENT +BEGIN:VEVENT +UID:foobar +DTSTAMP:**ANY** +SEQUENCE:1 +DTSTART;VALUE=DATE:20140728 +RECURRENCE-ID;VALUE=DATE:20140728 +ORGANIZER;CN=Strunk:mailto:strunk@example.org +ATTENDEE;PARTSTAT=TENTATIVE;CN=One:mailto:one@example.org +END:VEVENT +BEGIN:VEVENT +UID:foobar +DTSTAMP:**ANY** +SEQUENCE:1 +DTSTART;VALUE=DATE:20140729 +RECURRENCE-ID;VALUE=DATE:20140729 +ORGANIZER;CN=Strunk:mailto:strunk@example.org +ATTENDEE;PARTSTAT=ACCEPTED;CN=One:mailto:one@example.org +END:VEVENT +BEGIN:VEVENT +UID:foobar +DTSTAMP:**ANY** +SEQUENCE:1 +DTSTART;VALUE=DATE:20140725 +RECURRENCE-ID;VALUE=DATE:20140725 +ORGANIZER;CN=Strunk:mailto:strunk@example.org +ATTENDEE;PARTSTAT=DECLINED;CN=One:mailto:one@example.org +END:VEVENT +END:VCALENDAR +ICS + ], + ]; + + $this->parse($oldMessage, $newMessage, $expected); + } + + public function testNoChange() + { + $oldMessage = <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +BEGIN:VEVENT +UID:foobar +SEQUENCE:1 +ORGANIZER;CN=Strunk:mailto:strunk@example.org +ATTENDEE;CN=One:mailto:one@example.org +DTSTART:20140716T120000Z +END:VEVENT +END:VCALENDAR +ICS; + + $newMessage = <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +BEGIN:VEVENT +UID:foobar +SEQUENCE:1 +ORGANIZER;CN=Strunk:mailto:strunk@example.org +ATTENDEE;PARTSTAT=NEEDS-ACTION;CN=One:mailto:one@example.org +DTSTART:20140716T120000Z +END:VEVENT +END:VCALENDAR +ICS; + + $expected = []; + $this->parse($oldMessage, $newMessage, $expected); + } + + public function testNoChangeForceSend() + { + $oldMessage = <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +BEGIN:VEVENT +UID:foobar +SEQUENCE:1 +ORGANIZER;CN=Strunk:mailto:strunk@example.org +ATTENDEE;CN=One:mailto:one@example.org +DTSTART:20140716T120000Z +END:VEVENT +END:VCALENDAR +ICS; + + $newMessage = <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +BEGIN:VEVENT +UID:foobar +SEQUENCE:1 +ORGANIZER;SCHEDULE-FORCE-SEND=REPLY;CN=Strunk:mailto:strunk@example.org +ATTENDEE;PARTSTAT=NEEDS-ACTION;CN=One:mailto:one@example.org +DTSTART:20140716T120000Z +END:VEVENT +END:VCALENDAR +ICS; + + $version = \Sabre\VObject\Version::VERSION; + $expected = [ + [ + 'uid' => 'foobar', + 'method' => 'REPLY', + 'component' => 'VEVENT', + 'sender' => 'mailto:one@example.org', + 'senderName' => 'One', + 'recipient' => 'mailto:strunk@example.org', + 'recipientName' => 'Strunk', + 'message' => <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +PRODID:-//Sabre//Sabre VObject $version//EN +CALSCALE:GREGORIAN +METHOD:REPLY +BEGIN:VEVENT +UID:foobar +DTSTAMP:**ANY** +SEQUENCE:1 +DTSTART:20140716T120000Z +ORGANIZER;CN=Strunk:mailto:strunk@example.org +ATTENDEE;PARTSTAT=NEEDS-ACTION;CN=One:mailto:one@example.org +END:VEVENT +END:VCALENDAR +ICS + ], + ]; + $this->parse($oldMessage, $newMessage, $expected); + } + + public function testNoRelevantAttendee() + { + $oldMessage = <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +BEGIN:VEVENT +UID:foobar +SEQUENCE:1 +ORGANIZER;CN=Strunk:mailto:strunk@example.org +ATTENDEE;CN=Two:mailto:two@example.org +DTSTART:20140716T120000Z +END:VEVENT +END:VCALENDAR +ICS; + + $newMessage = <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +BEGIN:VEVENT +UID:foobar +SEQUENCE:1 +ORGANIZER;CN=Strunk:mailto:strunk@example.org +ATTENDEE;PARTSTAT=ACCEPTED;CN=Two:mailto:two@example.org +DTSTART:20140716T120000Z +END:VEVENT +END:VCALENDAR +ICS; + + $expected = []; + $this->parse($oldMessage, $newMessage, $expected); + } + + /** + * In this test, an event exists in an attendees calendar. The event + * is recurring, and the attendee deletes 1 instance of the event. + * This instance shows up in EXDATE. + * + * This should automatically generate a DECLINED message for that + * specific instance. + */ + public function testCreateReplyByException() + { + $oldMessage = <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +BEGIN:VEVENT +UID:foobar +SEQUENCE:1 +DTSTART:20140811T200000Z +RRULE:FREQ=WEEKLY +ORGANIZER:mailto:organizer@example.org +ATTENDEE:mailto:one@example.org +END:VEVENT +END:VCALENDAR +ICS; + + $newMessage = <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +BEGIN:VEVENT +UID:foobar +SEQUENCE:1 +DTSTART:20140811T200000Z +RRULE:FREQ=WEEKLY +ORGANIZER:mailto:organizer@example.org +ATTENDEE:mailto:one@example.org +EXDATE:20140818T200000Z +END:VEVENT +END:VCALENDAR +ICS; + + $version = \Sabre\VObject\Version::VERSION; + $expected = [ + [ + 'uid' => 'foobar', + 'method' => 'REPLY', + 'component' => 'VEVENT', + 'sender' => 'mailto:one@example.org', + 'senderName' => null, + 'recipient' => 'mailto:organizer@example.org', + 'recipientName' => null, + 'message' => <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +PRODID:-//Sabre//Sabre VObject $version//EN +CALSCALE:GREGORIAN +METHOD:REPLY +BEGIN:VEVENT +UID:foobar +DTSTAMP:**ANY** +SEQUENCE:1 +DTSTART:20140818T200000Z +RECURRENCE-ID:20140818T200000Z +ORGANIZER:mailto:organizer@example.org +ATTENDEE;PARTSTAT=DECLINED:mailto:one@example.org +END:VEVENT +END:VCALENDAR +ICS + ], + ]; + $this->parse($oldMessage, $newMessage, $expected); + } + + /** + * This test is identical to the last, but now we're working with + * timezones. + * + * @depends testCreateReplyByException + */ + public function testCreateReplyByExceptionTz() + { + $oldMessage = <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +BEGIN:VEVENT +UID:foobar +SEQUENCE:1 +DTSTART;TZID=America/Toronto:20140811T200000 +RRULE:FREQ=WEEKLY +ORGANIZER:mailto:organizer@example.org +ATTENDEE:mailto:one@example.org +END:VEVENT +END:VCALENDAR +ICS; + + $newMessage = <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +BEGIN:VEVENT +UID:foobar +SEQUENCE:1 +DTSTART;TZID=America/Toronto:20140811T200000 +RRULE:FREQ=WEEKLY +ORGANIZER:mailto:organizer@example.org +ATTENDEE:mailto:one@example.org +EXDATE;TZID=America/Toronto:20140818T200000 +END:VEVENT +END:VCALENDAR +ICS; + + $version = \Sabre\VObject\Version::VERSION; + $expected = [ + [ + 'uid' => 'foobar', + 'method' => 'REPLY', + 'component' => 'VEVENT', + 'sender' => 'mailto:one@example.org', + 'senderName' => null, + 'recipient' => 'mailto:organizer@example.org', + 'recipientName' => null, + 'message' => <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +PRODID:-//Sabre//Sabre VObject $version//EN +CALSCALE:GREGORIAN +METHOD:REPLY +BEGIN:VEVENT +UID:foobar +DTSTAMP:**ANY** +SEQUENCE:1 +DTSTART;TZID=America/Toronto:20140818T200000 +RECURRENCE-ID;TZID=America/Toronto:20140818T200000 +ORGANIZER:mailto:organizer@example.org +ATTENDEE;PARTSTAT=DECLINED:mailto:one@example.org +END:VEVENT +END:VCALENDAR +ICS + ], + ]; + $this->parse($oldMessage, $newMessage, $expected); + } + + /** + * @depends testCreateReplyByException + */ + public function testCreateReplyByExceptionAllDay() + { + $oldMessage = <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +BEGIN:VEVENT +SUMMARY:Weekly meeting +UID:foobar +SEQUENCE:1 +DTSTART;VALUE=DATE:20140811 +RRULE:FREQ=WEEKLY +ORGANIZER:mailto:organizer@example.org +ATTENDEE:mailto:one@example.org +END:VEVENT +END:VCALENDAR +ICS; + + $newMessage = <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +BEGIN:VEVENT +SUMMARY:Weekly meeting +UID:foobar +SEQUENCE:1 +DTSTART;VALUE=DATE:20140811 +RRULE:FREQ=WEEKLY +ORGANIZER:mailto:organizer@example.org +ATTENDEE:mailto:one@example.org +EXDATE;VALUE=DATE:20140818 +END:VEVENT +END:VCALENDAR +ICS; + + $version = \Sabre\VObject\Version::VERSION; + $expected = [ + [ + 'uid' => 'foobar', + 'method' => 'REPLY', + 'component' => 'VEVENT', + 'sender' => 'mailto:one@example.org', + 'senderName' => null, + 'recipient' => 'mailto:organizer@example.org', + 'recipientName' => null, + 'message' => <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +PRODID:-//Sabre//Sabre VObject $version//EN +CALSCALE:GREGORIAN +METHOD:REPLY +BEGIN:VEVENT +UID:foobar +DTSTAMP:**ANY** +SEQUENCE:1 +DTSTART;VALUE=DATE:20140818 +SUMMARY:Weekly meeting +RECURRENCE-ID;VALUE=DATE:20140818 +ORGANIZER:mailto:organizer@example.org +ATTENDEE;PARTSTAT=DECLINED:mailto:one@example.org +END:VEVENT +END:VCALENDAR +ICS + ], + ]; + $this->parse($oldMessage, $newMessage, $expected); + } + + public function testDeclined() + { + $oldMessage = <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +BEGIN:VEVENT +UID:foobar +SEQUENCE:1 +ORGANIZER;CN=Strunk:mailto:strunk@example.org +ATTENDEE;CN=One:mailto:one@example.org +DTSTART:20140716T120000Z +END:VEVENT +END:VCALENDAR +ICS; + + $newMessage = <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +BEGIN:VEVENT +UID:foobar +SEQUENCE:1 +ORGANIZER;CN=Strunk:mailto:strunk@example.org +ATTENDEE;PARTSTAT=DECLINED;CN=One:mailto:one@example.org +DTSTART:20140716T120000Z +END:VEVENT +END:VCALENDAR +ICS; + + $version = \Sabre\VObject\Version::VERSION; + + $expected = [ + [ + 'uid' => 'foobar', + 'method' => 'REPLY', + 'component' => 'VEVENT', + 'sender' => 'mailto:one@example.org', + 'senderName' => 'One', + 'recipient' => 'mailto:strunk@example.org', + 'recipientName' => 'Strunk', + 'message' => <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +PRODID:-//Sabre//Sabre VObject $version//EN +CALSCALE:GREGORIAN +METHOD:REPLY +BEGIN:VEVENT +UID:foobar +DTSTAMP:**ANY** +SEQUENCE:1 +DTSTART:20140716T120000Z +ORGANIZER;CN=Strunk:mailto:strunk@example.org +ATTENDEE;PARTSTAT=DECLINED;CN=One:mailto:one@example.org +END:VEVENT +END:VCALENDAR +ICS + ], + ]; + + $this->parse($oldMessage, $newMessage, $expected); + } + + public function testDeclinedCancelledEvent() + { + $oldMessage = <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +BEGIN:VEVENT +STATUS:CANCELLED +UID:foobar +SEQUENCE:1 +ORGANIZER;CN=Strunk:mailto:strunk@example.org +ATTENDEE;CN=One:mailto:one@example.org +DTSTART:20140716T120000Z +END:VEVENT +END:VCALENDAR +ICS; + + $newMessage = <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +BEGIN:VEVENT +STATUS:CANCELLED +UID:foobar +SEQUENCE:1 +ORGANIZER;CN=Strunk:mailto:strunk@example.org +ATTENDEE;PARTSTAT=DECLINED;CN=One:mailto:one@example.org +DTSTART:20140716T120000Z +END:VEVENT +END:VCALENDAR +ICS; + + $version = \Sabre\VObject\Version::VERSION; + + $expected = []; + + $this->parse($oldMessage, $newMessage, $expected); + } + + /** + * In this test, a new exception is created by an attendee as well. + * + * Except in this case, there was already an overridden event, and the + * overridden event was marked as cancelled by the attendee. + * + * For any other attendence status, the new status would have been + * declined, but for this, no message should we sent. + */ + public function testDontCreateReplyWhenEventWasDeclined() + { + $oldMessage = <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +BEGIN:VEVENT +UID:foobar +SEQUENCE:1 +DTSTART:20140811T200000Z +RRULE:FREQ=WEEKLY +ORGANIZER:mailto:organizer@example.org +ATTENDEE:mailto:one@example.org +END:VEVENT +BEGIN:VEVENT +RECURRENCE-ID:20140818T200000Z +UID:foobar +SEQUENCE:1 +DTSTART:20140818T200000Z +RRULE:FREQ=WEEKLY +ORGANIZER:mailto:organizer@example.org +ATTENDEE;PARTSTAT=DECLINED:mailto:one@example.org +END:VEVENT +END:VCALENDAR +ICS; + + $newMessage = <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +BEGIN:VEVENT +UID:foobar +SEQUENCE:1 +DTSTART:20140811T200000Z +RRULE:FREQ=WEEKLY +ORGANIZER:mailto:organizer@example.org +ATTENDEE:mailto:one@example.org +EXDATE:20140818T200000Z +END:VEVENT +END:VCALENDAR +ICS; + + $expected = []; + + $this->parse($oldMessage, $newMessage, $expected); + } + + public function testScheduleAgentOnOrganizer() + { + $oldMessage = <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +BEGIN:VEVENT +UID:foobar +SEQUENCE:1 +ORGANIZER;CN=Strunk:mailto:strunk@example.org +ATTENDEE;CN=One:mailto:one@example.org +DTSTART:20140716T120000Z +END:VEVENT +END:VCALENDAR +ICS; + + $newMessage = <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +BEGIN:VEVENT +UID:foobar +SEQUENCE:1 +ORGANIZER;SCHEDULE-AGENT=CLIENT;CN=Strunk:mailto:strunk@example.org +ATTENDEE;PARTSTAT=ACCEPTED;CN=One:mailto:one@example.org +DTSTART:20140716T120000Z +END:VEVENT +END:VCALENDAR +ICS; + + $version = \Sabre\VObject\Version::VERSION; + + $expected = []; + $this->parse($oldMessage, $newMessage, $expected); + } + + public function testAcceptedAllDay() + { + $oldMessage = <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +BEGIN:VEVENT +UID:foobar +SEQUENCE:1 +ORGANIZER;CN=Strunk:mailto:strunk@example.org +ATTENDEE;CN=One:mailto:one@example.org +DTSTART;VALUE=DATE:20140716 +END:VEVENT +END:VCALENDAR +ICS; + + $newMessage = <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +BEGIN:VEVENT +UID:foobar +SEQUENCE:1 +ORGANIZER;CN=Strunk:mailto:strunk@example.org +ATTENDEE;PARTSTAT=ACCEPTED;CN=One:mailto:one@example.org +DTSTART;VALUE=DATE:20140716 +END:VEVENT +END:VCALENDAR +ICS; + + $version = \Sabre\VObject\Version::VERSION; + + $expected = [ + [ + 'uid' => 'foobar', + 'method' => 'REPLY', + 'component' => 'VEVENT', + 'sender' => 'mailto:one@example.org', + 'senderName' => 'One', + 'recipient' => 'mailto:strunk@example.org', + 'recipientName' => 'Strunk', + 'message' => <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +PRODID:-//Sabre//Sabre VObject $version//EN +CALSCALE:GREGORIAN +METHOD:REPLY +BEGIN:VEVENT +UID:foobar +DTSTAMP:**ANY** +SEQUENCE:1 +DTSTART;VALUE=DATE:20140716 +ORGANIZER;CN=Strunk:mailto:strunk@example.org +ATTENDEE;PARTSTAT=ACCEPTED;CN=One:mailto:one@example.org +END:VEVENT +END:VCALENDAR +ICS + ], + ]; + + $this->parse($oldMessage, $newMessage, $expected); + } + + /** + * This function tests an attendee updating their status to an event where + * they don't have the master event of. + * + * This is possible in cases an organizer created a recurring event, and + * invited an attendee for one instance of the event. + */ + public function testReplyNoMasterEvent() + { + $oldMessage = <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +BEGIN:VEVENT +UID:foobar +SEQUENCE:1 +ORGANIZER;CN=Strunk:mailto:strunk@example.org +ATTENDEE;CN=One:mailto:one@example.org +RECURRENCE-ID:20140724T120000Z +DTSTART:20140724T120000Z +SUMMARY:Daily sprint +END:VEVENT +END:VCALENDAR +ICS; + + $newMessage = <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +BEGIN:VEVENT +UID:foobar +SEQUENCE:1 +ORGANIZER;CN=Strunk:mailto:strunk@example.org +ATTENDEE;PARTSTAT=ACCEPTED;CN=One:mailto:one@example.org +RECURRENCE-ID:20140724T120000Z +DTSTART:20140724T120000Z +SUMMARY:Daily sprint +END:VEVENT +END:VCALENDAR +ICS; + + $version = \Sabre\VObject\Version::VERSION; + + $expected = [ + [ + 'uid' => 'foobar', + 'method' => 'REPLY', + 'component' => 'VEVENT', + 'sender' => 'mailto:one@example.org', + 'senderName' => 'One', + 'recipient' => 'mailto:strunk@example.org', + 'recipientName' => 'Strunk', + 'message' => <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +CALSCALE:GREGORIAN +METHOD:REPLY +BEGIN:VEVENT +UID:foobar +DTSTAMP:**ANY** +SEQUENCE:1 +DTSTART:20140724T120000Z +SUMMARY:Daily sprint +RECURRENCE-ID:20140724T120000Z +ORGANIZER;CN=Strunk:mailto:strunk@example.org +ATTENDEE;PARTSTAT=ACCEPTED;CN=One:mailto:one@example.org +END:VEVENT +END:VCALENDAR +ICS + ], + ]; + + $this->parse($oldMessage, $newMessage, $expected); + } + + /** + * A party crasher is an attendee that accepted an event, but was not in + * any original invite. + * + * @depends testAccepted + */ + public function testPartyCrasher() + { + $oldMessage = <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +BEGIN:VEVENT +UID:foobar +SUMMARY:B-day party +SEQUENCE:1 +ORGANIZER;CN=Strunk:mailto:strunk@example.org +DTSTART:20140716T120000Z +RRULE:FREQ=DAILY +END:VEVENT +BEGIN:VEVENT +UID:foobar +RECURRENCE-ID:20140717T120000Z +SUMMARY:B-day party +SEQUENCE:1 +ORGANIZER;CN=Strunk:mailto:strunk@example.org +DTSTART:20140717T120000Z +RRULE:FREQ=DAILY +END:VEVENT +END:VCALENDAR +ICS; + + $newMessage = <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +BEGIN:VEVENT +UID:foobar +SUMMARY:B-day party +SEQUENCE:1 +ORGANIZER;CN=Strunk:mailto:strunk@example.org +DTSTART:20140716T120000Z +RRULE:FREQ=DAILY +END:VEVENT +BEGIN:VEVENT +UID:foobar +RECURRENCE-ID:20140717T120000Z +SUMMARY:B-day party +SEQUENCE:1 +ORGANIZER;CN=Strunk:mailto:strunk@example.org +ATTENDEE;PARTSTAT=ACCEPTED;CN=One:mailto:one@example.org +DTSTART:20140717T120000Z +RRULE:FREQ=DAILY +END:VEVENT +END:VCALENDAR +ICS; + + $expected = [ + [ + 'uid' => 'foobar', + 'method' => 'REPLY', + 'component' => 'VEVENT', + 'sender' => 'mailto:one@example.org', + 'senderName' => 'One', + 'recipient' => 'mailto:strunk@example.org', + 'recipientName' => 'Strunk', + 'message' => <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +CALSCALE:GREGORIAN +METHOD:REPLY +BEGIN:VEVENT +UID:foobar +DTSTAMP:**ANY** +SEQUENCE:1 +DTSTART:20140717T120000Z +SUMMARY:B-day party +RECURRENCE-ID:20140717T120000Z +ORGANIZER;CN=Strunk:mailto:strunk@example.org +ATTENDEE;PARTSTAT=ACCEPTED;CN=One:mailto:one@example.org +END:VEVENT +END:VCALENDAR + +ICS + ], + ]; + + $this->parse($oldMessage, $newMessage, $expected); + } +} diff --git a/vendor/sabre/vobject/tests/VObject/ITip/BrokerDeleteEventTest.php b/vendor/sabre/vobject/tests/VObject/ITip/BrokerDeleteEventTest.php new file mode 100644 index 000000000..88f30ec18 --- /dev/null +++ b/vendor/sabre/vobject/tests/VObject/ITip/BrokerDeleteEventTest.php @@ -0,0 +1,326 @@ +<?php + +namespace Sabre\VObject\ITip; + +class BrokerDeleteEventTest extends BrokerTester +{ + public function testOrganizerDeleteWithDtend() + { + $oldMessage = <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +BEGIN:VEVENT +UID:foobar +SEQUENCE:1 +SUMMARY:foo +ORGANIZER;CN=Strunk:mailto:strunk@example.org +ATTENDEE;CN=One:mailto:one@example.org +ATTENDEE;CN=Two:mailto:two@example.org +DTSTART:20140716T120000Z +DTEND:20140716T130000Z +END:VEVENT +END:VCALENDAR +ICS; + + $newMessage = null; + + $version = \Sabre\VObject\Version::VERSION; + + $expected = [ + [ + 'uid' => 'foobar', + 'method' => 'CANCEL', + 'component' => 'VEVENT', + 'sender' => 'mailto:strunk@example.org', + 'senderName' => 'Strunk', + 'recipient' => 'mailto:one@example.org', + 'recipientName' => 'One', + 'message' => <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +PRODID:-//Sabre//Sabre VObject $version//EN +CALSCALE:GREGORIAN +METHOD:CANCEL +BEGIN:VEVENT +UID:foobar +DTSTAMP:**ANY** +SEQUENCE:2 +SUMMARY:foo +DTSTART:20140716T120000Z +DTEND:20140716T130000Z +ORGANIZER;CN=Strunk:mailto:strunk@example.org +ATTENDEE;CN=One:mailto:one@example.org +END:VEVENT +END:VCALENDAR +ICS + ], + + [ + 'uid' => 'foobar', + 'method' => 'CANCEL', + 'component' => 'VEVENT', + 'sender' => 'mailto:strunk@example.org', + 'senderName' => 'Strunk', + 'recipient' => 'mailto:two@example.org', + 'recipientName' => 'Two', + 'message' => <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +PRODID:-//Sabre//Sabre VObject $version//EN +CALSCALE:GREGORIAN +METHOD:CANCEL +BEGIN:VEVENT +UID:foobar +DTSTAMP:**ANY** +SEQUENCE:2 +SUMMARY:foo +DTSTART:20140716T120000Z +DTEND:20140716T130000Z +ORGANIZER;CN=Strunk:mailto:strunk@example.org +ATTENDEE;CN=Two:mailto:two@example.org +END:VEVENT +END:VCALENDAR +ICS + ], + ]; + + $this->parse($oldMessage, $newMessage, $expected, 'mailto:strunk@example.org'); + } + + public function testOrganizerDeleteWithDuration() + { + $oldMessage = <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +BEGIN:VEVENT +UID:foobar +SEQUENCE:1 +SUMMARY:foo +ORGANIZER;CN=Strunk:mailto:strunk@example.org +ATTENDEE;CN=One:mailto:one@example.org +ATTENDEE;CN=Two:mailto:two@example.org +DTSTART:20140716T120000Z +DURATION:PT1H +END:VEVENT +END:VCALENDAR +ICS; + + $newMessage = null; + + $version = \Sabre\VObject\Version::VERSION; + + $expected = [ + [ + 'uid' => 'foobar', + 'method' => 'CANCEL', + 'component' => 'VEVENT', + 'sender' => 'mailto:strunk@example.org', + 'senderName' => 'Strunk', + 'recipient' => 'mailto:one@example.org', + 'recipientName' => 'One', + 'message' => <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +PRODID:-//Sabre//Sabre VObject $version//EN +CALSCALE:GREGORIAN +METHOD:CANCEL +BEGIN:VEVENT +UID:foobar +DTSTAMP:**ANY** +SEQUENCE:2 +SUMMARY:foo +DTSTART:20140716T120000Z +DURATION:PT1H +ORGANIZER;CN=Strunk:mailto:strunk@example.org +ATTENDEE;CN=One:mailto:one@example.org +END:VEVENT +END:VCALENDAR +ICS + ], + + [ + 'uid' => 'foobar', + 'method' => 'CANCEL', + 'component' => 'VEVENT', + 'sender' => 'mailto:strunk@example.org', + 'senderName' => 'Strunk', + 'recipient' => 'mailto:two@example.org', + 'recipientName' => 'Two', + 'message' => <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +PRODID:-//Sabre//Sabre VObject $version//EN +CALSCALE:GREGORIAN +METHOD:CANCEL +BEGIN:VEVENT +UID:foobar +DTSTAMP:**ANY** +SEQUENCE:2 +SUMMARY:foo +DTSTART:20140716T120000Z +DURATION:PT1H +ORGANIZER;CN=Strunk:mailto:strunk@example.org +ATTENDEE;CN=Two:mailto:two@example.org +END:VEVENT +END:VCALENDAR +ICS + ], + ]; + + $this->parse($oldMessage, $newMessage, $expected, 'mailto:strunk@example.org'); + } + + public function testAttendeeDeleteWithDtend() + { + $oldMessage = <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +BEGIN:VEVENT +UID:foobar +SEQUENCE:1 +SUMMARY:foo +ORGANIZER;CN=Strunk:mailto:strunk@example.org +ATTENDEE;CN=One:mailto:one@example.org +ATTENDEE;CN=Two:mailto:two@example.org +DTSTART:20140716T120000Z +DTEND:20140716T130000Z +END:VEVENT +END:VCALENDAR +ICS; + + $newMessage = null; + + $version = \Sabre\VObject\Version::VERSION; + + $expected = [ + [ + 'uid' => 'foobar', + 'method' => 'REPLY', + 'component' => 'VEVENT', + 'sender' => 'mailto:one@example.org', + 'senderName' => 'One', + 'recipient' => 'mailto:strunk@example.org', + 'recipientName' => 'Strunk', + 'message' => <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +PRODID:-//Sabre//Sabre VObject $version//EN +CALSCALE:GREGORIAN +METHOD:REPLY +BEGIN:VEVENT +UID:foobar +DTSTAMP:**ANY** +SEQUENCE:1 +DTSTART:20140716T120000Z +DTEND:20140716T130000Z +SUMMARY:foo +ORGANIZER;CN=Strunk:mailto:strunk@example.org +ATTENDEE;PARTSTAT=DECLINED;CN=One:mailto:one@example.org +END:VEVENT +END:VCALENDAR +ICS + ], + ]; + + $this->parse($oldMessage, $newMessage, $expected, 'mailto:one@example.org'); + } + + public function testAttendeeReplyWithDuration() + { + $oldMessage = <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +BEGIN:VEVENT +UID:foobar +SEQUENCE:1 +SUMMARY:foo +ORGANIZER;CN=Strunk:mailto:strunk@example.org +ATTENDEE;CN=One:mailto:one@example.org +ATTENDEE;CN=Two:mailto:two@example.org +DTSTART:20140716T120000Z +DURATION:PT1H +END:VEVENT +END:VCALENDAR +ICS; + + $newMessage = null; + + $version = \Sabre\VObject\Version::VERSION; + + $expected = [ + [ + 'uid' => 'foobar', + 'method' => 'REPLY', + 'component' => 'VEVENT', + 'sender' => 'mailto:one@example.org', + 'senderName' => 'One', + 'recipient' => 'mailto:strunk@example.org', + 'recipientName' => 'Strunk', + 'message' => <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +PRODID:-//Sabre//Sabre VObject $version//EN +CALSCALE:GREGORIAN +METHOD:REPLY +BEGIN:VEVENT +UID:foobar +DTSTAMP:**ANY** +SEQUENCE:1 +DTSTART:20140716T120000Z +DURATION:PT1H +SUMMARY:foo +ORGANIZER;CN=Strunk:mailto:strunk@example.org +ATTENDEE;PARTSTAT=DECLINED;CN=One:mailto:one@example.org +END:VEVENT +END:VCALENDAR +ICS + ], + ]; + + $this->parse($oldMessage, $newMessage, $expected, 'mailto:one@example.org'); + } + + public function testAttendeeDeleteCancelledEvent() + { + $oldMessage = <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +BEGIN:VEVENT +STATUS:CANCELLED +UID:foobar +SEQUENCE:1 +ORGANIZER;CN=Strunk:mailto:strunk@example.org +ATTENDEE;CN=One:mailto:one@example.org +ATTENDEE;CN=Two:mailto:two@example.org +DTSTART:20140716T120000Z +DTEND:20140716T130000Z +END:VEVENT +END:VCALENDAR +ICS; + + $newMessage = null; + + $expected = []; + + $this->parse($oldMessage, $newMessage, $expected, 'mailto:one@example.org'); + } + + public function testNoCalendar() + { + $this->parse(null, null, [], 'mailto:one@example.org'); + } + + public function testVTodo() + { + $oldMessage = <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +BEGIN:VTODO +UID:foobar +SEQUENCE:1 +END:VTODO +END:VCALENDAR +ICS; + $this->parse($oldMessage, null, [], 'mailto:one@example.org'); + } +} diff --git a/vendor/sabre/vobject/tests/VObject/ITip/BrokerNewEventTest.php b/vendor/sabre/vobject/tests/VObject/ITip/BrokerNewEventTest.php new file mode 100644 index 000000000..a727427af --- /dev/null +++ b/vendor/sabre/vobject/tests/VObject/ITip/BrokerNewEventTest.php @@ -0,0 +1,586 @@ +<?php + +namespace Sabre\VObject\ITip; + +class BrokerNewEventTest extends BrokerTester +{ + public function testNoAttendee() + { + $message = <<<ICS +BEGIN:VCALENDAR +BEGIN:VEVENT +UID:foobar +DTSTART:20140811T220000Z +DTEND:20140811T230000Z +END:VEVENT +END:VCALENDAR +ICS; + + $result = $this->parse(null, $message, []); + } + + public function testVTODO() + { + $message = <<<ICS +BEGIN:VCALENDAR +BEGIN:VTODO +UID:foobar +END:VTODO +END:VCALENDAR +ICS; + + $result = $this->parse(null, $message, []); + } + + public function testSimpleInvite() + { + $message = <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +BEGIN:VEVENT +UID:foobar +DTSTART:20140811T220000Z +DTEND:20140811T230000Z +ORGANIZER;CN=Strunk:mailto:strunk@example.org +ATTENDEE;CN=White:mailto:white@example.org +END:VEVENT +END:VCALENDAR +ICS; + + $version = \Sabre\VObject\Version::VERSION; + $expectedMessage = <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +PRODID:-//Sabre//Sabre VObject $version//EN +CALSCALE:GREGORIAN +METHOD:REQUEST +BEGIN:VEVENT +UID:foobar +DTSTART:20140811T220000Z +DTEND:20140811T230000Z +ORGANIZER;CN=Strunk:mailto:strunk@example.org +ATTENDEE;CN=White;PARTSTAT=NEEDS-ACTION:mailto:white@example.org +DTSTAMP:**ANY** +END:VEVENT +END:VCALENDAR +ICS; + + $expected = [ + [ + 'uid' => 'foobar', + 'method' => 'REQUEST', + 'component' => 'VEVENT', + 'sender' => 'mailto:strunk@example.org', + 'senderName' => 'Strunk', + 'recipient' => 'mailto:white@example.org', + 'recipientName' => 'White', + 'message' => $expectedMessage, + ], + ]; + + $this->parse(null, $message, $expected, 'mailto:strunk@example.org'); + } + + /** + * @expectedException \Sabre\VObject\ITip\ITipException + */ + public function testBrokenEventUIDMisMatch() + { + $message = <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +BEGIN:VEVENT +UID:foobar +ORGANIZER;CN=Strunk:mailto:strunk@example.org +ATTENDEE;CN=White:mailto:white@example.org +END:VEVENT +BEGIN:VEVENT +UID:foobar2 +ORGANIZER;CN=Strunk:mailto:strunk@example.org +ATTENDEE;CN=White:mailto:white@example.org +END:VEVENT +END:VCALENDAR +ICS; + + $this->parse(null, $message, [], 'mailto:strunk@example.org'); + } + + /** + * @expectedException \Sabre\VObject\ITip\ITipException + */ + public function testBrokenEventOrganizerMisMatch() + { + $message = <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +BEGIN:VEVENT +UID:foobar +ORGANIZER;CN=Strunk:mailto:strunk@example.org +ATTENDEE;CN=White:mailto:white@example.org +END:VEVENT +BEGIN:VEVENT +UID:foobar +ORGANIZER:mailto:foo@example.org +ATTENDEE;CN=White:mailto:white@example.org +END:VEVENT +END:VCALENDAR +ICS; + + $this->parse(null, $message, [], 'mailto:strunk@example.org'); + } + + public function testRecurrenceInvite() + { + $message = <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +BEGIN:VEVENT +UID:foobar +ORGANIZER;CN=Strunk:mailto:strunk@example.org +ATTENDEE;CN=One:mailto:one@example.org +ATTENDEE;CN=Two:mailto:two@example.org +DTSTART:20140716T120000Z +DURATION:PT1H +RRULE:FREQ=DAILY +EXDATE:20140717T120000Z +END:VEVENT +BEGIN:VEVENT +UID:foobar +RECURRENCE-ID:20140718T120000Z +ORGANIZER;CN=Strunk:mailto:strunk@example.org +ATTENDEE;CN=Two:mailto:two@example.org +ATTENDEE;CN=Three:mailto:three@example.org +DTSTART:20140718T120000Z +DURATION:PT1H +END:VEVENT +END:VCALENDAR +ICS; + + $version = \Sabre\VObject\Version::VERSION; + + $expected = [ + [ + 'uid' => 'foobar', + 'method' => 'REQUEST', + 'component' => 'VEVENT', + 'sender' => 'mailto:strunk@example.org', + 'senderName' => 'Strunk', + 'recipient' => 'mailto:one@example.org', + 'recipientName' => 'One', + 'message' => <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +PRODID:-//Sabre//Sabre VObject $version//EN +CALSCALE:GREGORIAN +METHOD:REQUEST +BEGIN:VEVENT +UID:foobar +ORGANIZER;CN=Strunk:mailto:strunk@example.org +ATTENDEE;CN=One;PARTSTAT=NEEDS-ACTION:mailto:one@example.org +ATTENDEE;CN=Two;PARTSTAT=NEEDS-ACTION:mailto:two@example.org +DTSTART:20140716T120000Z +DURATION:PT1H +RRULE:FREQ=DAILY +EXDATE:20140717T120000Z,20140718T120000Z +DTSTAMP:**ANY** +END:VEVENT +END:VCALENDAR +ICS + ], + [ + 'uid' => 'foobar', + 'method' => 'REQUEST', + 'component' => 'VEVENT', + 'sender' => 'mailto:strunk@example.org', + 'senderName' => 'Strunk', + 'recipient' => 'mailto:two@example.org', + 'recipientName' => 'Two', + 'message' => <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +PRODID:-//Sabre//Sabre VObject $version//EN +CALSCALE:GREGORIAN +METHOD:REQUEST +BEGIN:VEVENT +UID:foobar +ORGANIZER;CN=Strunk:mailto:strunk@example.org +ATTENDEE;CN=One;PARTSTAT=NEEDS-ACTION:mailto:one@example.org +ATTENDEE;CN=Two;PARTSTAT=NEEDS-ACTION:mailto:two@example.org +DTSTART:20140716T120000Z +DURATION:PT1H +RRULE:FREQ=DAILY +EXDATE:20140717T120000Z +DTSTAMP:**ANY** +END:VEVENT +BEGIN:VEVENT +UID:foobar +RECURRENCE-ID:20140718T120000Z +ORGANIZER;CN=Strunk:mailto:strunk@example.org +ATTENDEE;CN=Two:mailto:two@example.org +ATTENDEE;CN=Three:mailto:three@example.org +DTSTART:20140718T120000Z +DURATION:PT1H +DTSTAMP:**ANY** +END:VEVENT +END:VCALENDAR +ICS + ], + [ + 'uid' => 'foobar', + 'method' => 'REQUEST', + 'component' => 'VEVENT', + 'sender' => 'mailto:strunk@example.org', + 'senderName' => 'Strunk', + 'recipient' => 'mailto:three@example.org', + 'recipientName' => 'Three', + 'message' => <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +PRODID:-//Sabre//Sabre VObject $version//EN +CALSCALE:GREGORIAN +METHOD:REQUEST +BEGIN:VEVENT +UID:foobar +RECURRENCE-ID:20140718T120000Z +ORGANIZER;CN=Strunk:mailto:strunk@example.org +ATTENDEE;CN=Two:mailto:two@example.org +ATTENDEE;CN=Three:mailto:three@example.org +DTSTART:20140718T120000Z +DURATION:PT1H +DTSTAMP:**ANY** +END:VEVENT +END:VCALENDAR +ICS + ], + ]; + + $this->parse(null, $message, $expected, 'mailto:strunk@example.org'); + } + + public function testRecurrenceInvite2() + { + // This method tests a nearly identical path, but in this case the + // master event does not have an EXDATE. + $message = <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +BEGIN:VEVENT +UID:foobar +ORGANIZER;CN=Strunk:mailto:strunk@example.org +ATTENDEE;CN=One:mailto:one@example.org +ATTENDEE;CN=Two:mailto:two@example.org +DTSTART:20140716T120000Z +DTEND:20140716T130000Z +RRULE:FREQ=DAILY +END:VEVENT +BEGIN:VEVENT +UID:foobar +RECURRENCE-ID:20140718T120000Z +ORGANIZER;CN=Strunk:mailto:strunk@example.org +ATTENDEE;CN=Two:mailto:two@example.org +ATTENDEE;CN=Three:mailto:three@example.org +DTSTART:20140718T120000Z +DTEND:20140718T130000Z +END:VEVENT +END:VCALENDAR +ICS; + + $version = \Sabre\VObject\Version::VERSION; + + $expected = [ + [ + 'uid' => 'foobar', + 'method' => 'REQUEST', + 'component' => 'VEVENT', + 'sender' => 'mailto:strunk@example.org', + 'senderName' => 'Strunk', + 'recipient' => 'mailto:one@example.org', + 'recipientName' => 'One', + 'message' => <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +PRODID:-//Sabre//Sabre VObject $version//EN +CALSCALE:GREGORIAN +METHOD:REQUEST +BEGIN:VEVENT +UID:foobar +ORGANIZER;CN=Strunk:mailto:strunk@example.org +ATTENDEE;CN=One;PARTSTAT=NEEDS-ACTION:mailto:one@example.org +ATTENDEE;CN=Two;PARTSTAT=NEEDS-ACTION:mailto:two@example.org +DTSTART:20140716T120000Z +DTEND:20140716T130000Z +RRULE:FREQ=DAILY +EXDATE:20140718T120000Z +DTSTAMP:**ANY** +END:VEVENT +END:VCALENDAR +ICS + ], + [ + 'uid' => 'foobar', + 'method' => 'REQUEST', + 'component' => 'VEVENT', + 'sender' => 'mailto:strunk@example.org', + 'senderName' => 'Strunk', + 'recipient' => 'mailto:two@example.org', + 'recipientName' => 'Two', + 'message' => <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +PRODID:-//Sabre//Sabre VObject $version//EN +CALSCALE:GREGORIAN +METHOD:REQUEST +BEGIN:VEVENT +UID:foobar +ORGANIZER;CN=Strunk:mailto:strunk@example.org +ATTENDEE;CN=One;PARTSTAT=NEEDS-ACTION:mailto:one@example.org +ATTENDEE;CN=Two;PARTSTAT=NEEDS-ACTION:mailto:two@example.org +DTSTART:20140716T120000Z +DTEND:20140716T130000Z +RRULE:FREQ=DAILY +DTSTAMP:**ANY** +END:VEVENT +BEGIN:VEVENT +UID:foobar +RECURRENCE-ID:20140718T120000Z +ORGANIZER;CN=Strunk:mailto:strunk@example.org +ATTENDEE;CN=Two:mailto:two@example.org +ATTENDEE;CN=Three:mailto:three@example.org +DTSTART:20140718T120000Z +DTEND:20140718T130000Z +DTSTAMP:**ANY** +END:VEVENT +END:VCALENDAR +ICS + ], + [ + 'uid' => 'foobar', + 'method' => 'REQUEST', + 'component' => 'VEVENT', + 'sender' => 'mailto:strunk@example.org', + 'senderName' => 'Strunk', + 'recipient' => 'mailto:three@example.org', + 'recipientName' => 'Three', + 'message' => <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +PRODID:-//Sabre//Sabre VObject $version//EN +CALSCALE:GREGORIAN +METHOD:REQUEST +BEGIN:VEVENT +UID:foobar +RECURRENCE-ID:20140718T120000Z +ORGANIZER;CN=Strunk:mailto:strunk@example.org +ATTENDEE;CN=Two:mailto:two@example.org +ATTENDEE;CN=Three:mailto:three@example.org +DTSTART:20140718T120000Z +DTEND:20140718T130000Z +DTSTAMP:**ANY** +END:VEVENT +END:VCALENDAR +ICS + ], + ]; + + $this->parse(null, $message, $expected, 'mailto:strunk@example.org'); + } + + public function testRecurrenceInvite3() + { + // This method tests a complex rrule + $message = <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +BEGIN:VEVENT +UID:foobar +ORGANIZER;CN=Strunk:mailto:strunk@example.org +ATTENDEE;CN=One:mailto:one@example.org +DTSTART:20140716T120000Z +DTEND:20140716T130000Z +RRULE:FREQ=WEEKLY;INTERVAL=2;COUNT=8;BYDAY=SA,SU +END:VEVENT +END:VCALENDAR +ICS; + + $version = \Sabre\VObject\Version::VERSION; + + $expected = [ + [ + 'uid' => 'foobar', + 'method' => 'REQUEST', + 'component' => 'VEVENT', + 'sender' => 'mailto:strunk@example.org', + 'senderName' => 'Strunk', + 'recipient' => 'mailto:one@example.org', + 'recipientName' => 'One', + 'message' => <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +PRODID:-//Sabre//Sabre VObject $version//EN +CALSCALE:GREGORIAN +METHOD:REQUEST +BEGIN:VEVENT +UID:foobar +ORGANIZER;CN=Strunk:mailto:strunk@example.org +ATTENDEE;CN=One;PARTSTAT=NEEDS-ACTION:mailto:one@example.org +DTSTART:20140716T120000Z +DTEND:20140716T130000Z +RRULE:FREQ=WEEKLY;INTERVAL=2;COUNT=8;BYDAY=SA,SU +DTSTAMP:**ANY** +END:VEVENT +END:VCALENDAR +ICS + ], + ]; + + $this->parse(null, $message, $expected, 'mailto:strunk@example.org'); + } + + public function testScheduleAgentClient() + { + $message = <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +BEGIN:VEVENT +UID:foobar +DTSTART:20140811T220000Z +DTEND:20140811T230000Z +ORGANIZER;CN=Strunk:mailto:strunk@example.org +ATTENDEE;CN=White;SCHEDULE-AGENT=CLIENT:mailto:white@example.org +END:VEVENT +END:VCALENDAR +ICS; + + $version = \Sabre\VObject\Version::VERSION; + + $this->parse(null, $message, [], 'mailto:strunk@example.org'); + } + + /** + * @expectedException \Sabre\VObject\ITip\ITipException + */ + public function testMultipleUID() + { + $message = <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +BEGIN:VEVENT +UID:foobar +ORGANIZER;CN=Strunk:mailto:strunk@example.org +ATTENDEE;CN=One:mailto:one@example.org +ATTENDEE;CN=Two:mailto:two@example.org +DTSTART:20140716T120000Z +DTEND:20140716T130000Z +RRULE:FREQ=DAILY +END:VEVENT +BEGIN:VEVENT +UID:foobar2 +RECURRENCE-ID:20140718T120000Z +ORGANIZER;CN=Strunk:mailto:strunk@example.org +ATTENDEE;CN=Two:mailto:two@example.org +ATTENDEE;CN=Three:mailto:three@example.org +DTSTART:20140718T120000Z +DTEND:20140718T130000Z +END:VEVENT +END:VCALENDAR +ICS; + + $version = \Sabre\VObject\Version::VERSION; + $this->parse(null, $message, [], 'mailto:strunk@example.org'); + } + + /** + * @expectedException \Sabre\VObject\ITip\SameOrganizerForAllComponentsException + */ + public function testChangingOrganizers() + { + $message = <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +BEGIN:VEVENT +UID:foobar +ORGANIZER;CN=Strunk:mailto:strunk@example.org +ATTENDEE;CN=One:mailto:one@example.org +ATTENDEE;CN=Two:mailto:two@example.org +DTSTART:20140716T120000Z +DTEND:20140716T130000Z +RRULE:FREQ=DAILY +END:VEVENT +BEGIN:VEVENT +UID:foobar +RECURRENCE-ID:20140718T120000Z +ORGANIZER;CN=Strunk:mailto:ew@example.org +ATTENDEE;CN=Two:mailto:two@example.org +ATTENDEE;CN=Three:mailto:three@example.org +DTSTART:20140718T120000Z +DTEND:20140718T130000Z +END:VEVENT +END:VCALENDAR +ICS; + + $this->parse(null, $message, [], 'mailto:strunk@example.org'); + } + + public function testCaseInsensitiveOrganizers() + { + $message = <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +BEGIN:VEVENT +UID:foobar +ORGANIZER;CN=Strunk:mailto:strunk@example.org +ATTENDEE;CN=One:mailto:one@example.org +ATTENDEE;CN=Two:mailto:two@example.org +DTSTART:20140716T120000Z +DTEND:20140716T130000Z +RRULE:FREQ=DAILY +END:VEVENT +BEGIN:VEVENT +UID:foobar +RECURRENCE-ID:20140718T120000Z +ORGANIZER;CN=Strunk:mailto:Strunk@example.org +ATTENDEE;CN=Two:mailto:two@example.org +ATTENDEE;CN=Three:mailto:three@example.org +DTSTART:20140718T120000Z +DTEND:20140718T130000Z +END:VEVENT +END:VCALENDAR +ICS; + + $this->parse(null, $message, [ + [ + 'uid' => 'foobar', + 'method' => 'REQUEST', + 'component' => 'VEVENT', + 'sender' => 'mailto:strunk@example.org', + ], + [ + 'uid' => 'foobar', + 'method' => 'REQUEST', + 'component' => 'VEVENT', + 'sender' => 'mailto:strunk@example.org', + ], + ['uid' => 'foobar', + 'method' => 'REQUEST', + 'component' => 'VEVENT', + 'sender' => 'mailto:strunk@example.org', + ], + ], 'mailto:strunk@example.org'); + } + + public function testNoOrganizerHasAttendee() + { + $message = <<<ICS +BEGIN:VCALENDAR +BEGIN:VEVENT +UID:foobar +DTSTART:20140811T220000Z +DTEND:20140811T230000Z +ATTENDEE;CN=Two:mailto:two@example.org +END:VEVENT +END:VCALENDAR +ICS; + + $this->parse(null, $message, [], 'mailto:strunk@example.org'); + } +} diff --git a/vendor/sabre/vobject/tests/VObject/ITip/BrokerProcessMessageTest.php b/vendor/sabre/vobject/tests/VObject/ITip/BrokerProcessMessageTest.php new file mode 100644 index 000000000..3327be0d9 --- /dev/null +++ b/vendor/sabre/vobject/tests/VObject/ITip/BrokerProcessMessageTest.php @@ -0,0 +1,157 @@ +<?php + +namespace Sabre\VObject\ITip; + +class BrokerProcessMessageTest extends BrokerTester +{ + public function testRequestNew() + { + $itip = <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +METHOD:REQUEST +BEGIN:VEVENT +SEQUENCE:1 +UID:foobar +END:VEVENT +END:VCALENDAR +ICS; + + $expected = <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +BEGIN:VEVENT +SEQUENCE:1 +UID:foobar +END:VEVENT +END:VCALENDAR +ICS; + + $result = $this->process($itip, null, $expected); + } + + public function testRequestUpdate() + { + $itip = <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +METHOD:REQUEST +BEGIN:VEVENT +SEQUENCE:2 +UID:foobar +END:VEVENT +END:VCALENDAR +ICS; + + $old = <<<ICS +BEGIN:VCALENDAR +BEGIN:VEVENT +SEQUENCE:1 +UID:foobar +END:VEVENT +END:VCALENDAR +ICS; + + $expected = <<<ICS +BEGIN:VCALENDAR +BEGIN:VEVENT +SEQUENCE:2 +UID:foobar +END:VEVENT +END:VCALENDAR +ICS; + + $result = $this->process($itip, $old, $expected); + } + + public function testCancel() + { + $itip = <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +METHOD:CANCEL +BEGIN:VEVENT +SEQUENCE:2 +UID:foobar +END:VEVENT +END:VCALENDAR +ICS; + + $old = <<<ICS +BEGIN:VCALENDAR +BEGIN:VEVENT +SEQUENCE:1 +UID:foobar +END:VEVENT +END:VCALENDAR +ICS; + + $expected = <<<ICS +BEGIN:VCALENDAR +BEGIN:VEVENT +UID:foobar +STATUS:CANCELLED +SEQUENCE:2 +END:VEVENT +END:VCALENDAR +ICS; + + $result = $this->process($itip, $old, $expected); + } + + public function testCancelNoExistingEvent() + { + $itip = <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +METHOD:CANCEL +BEGIN:VEVENT +SEQUENCE:2 +UID:foobar +END:VEVENT +END:VCALENDAR +ICS; + + $old = null; + $expected = null; + + $result = $this->process($itip, $old, $expected); + } + + public function testUnsupportedComponent() + { + $itip = <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +BEGIN:VTODO +SEQUENCE:2 +UID:foobar +END:VTODO +END:VCALENDAR +ICS; + + $old = null; + $expected = null; + + $result = $this->process($itip, $old, $expected); + } + + public function testUnsupportedMethod() + { + $itip = <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +METHOD:PUBLISH +BEGIN:VEVENT +SEQUENCE:2 +UID:foobar +END:VEVENT +END:VCALENDAR +ICS; + + $old = null; + $expected = null; + + $result = $this->process($itip, $old, $expected); + } +} diff --git a/vendor/sabre/vobject/tests/VObject/ITip/BrokerProcessReplyTest.php b/vendor/sabre/vobject/tests/VObject/ITip/BrokerProcessReplyTest.php new file mode 100644 index 000000000..1cb685096 --- /dev/null +++ b/vendor/sabre/vobject/tests/VObject/ITip/BrokerProcessReplyTest.php @@ -0,0 +1,583 @@ +<?php + +namespace Sabre\VObject\ITip; + +class BrokerProcessReplyTest extends BrokerTester +{ + public function testReplyNoOriginal() + { + $itip = <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +METHOD:REPLY +BEGIN:VEVENT +SEQUENCE:2 +UID:foobar +ATTENDEE;PARTSTAT=ACCEPTED:mailto:foo@example.org +ORGANIZER:mailto:bar@example.org +END:VEVENT +END:VCALENDAR +ICS; + + $old = null; + $expected = null; + + $result = $this->process($itip, $old, $expected); + } + + public function testReplyAccept() + { + $itip = <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +METHOD:REPLY +BEGIN:VEVENT +ATTENDEE;PARTSTAT=ACCEPTED:mailto:foo@example.org +ORGANIZER:mailto:bar@example.org +SEQUENCE:2 +UID:foobar +END:VEVENT +END:VCALENDAR +ICS; + + $old = <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +BEGIN:VEVENT +SEQUENCE:2 +UID:foobar +ATTENDEE:mailto:foo@example.org +ORGANIZER:mailto:bar@example.org +END:VEVENT +END:VCALENDAR +ICS; + + $expected = <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +BEGIN:VEVENT +SEQUENCE:2 +UID:foobar +ATTENDEE;PARTSTAT=ACCEPTED;SCHEDULE-STATUS=2.0:mailto:foo@example.org +ORGANIZER:mailto:bar@example.org +END:VEVENT +END:VCALENDAR +ICS; + + $result = $this->process($itip, $old, $expected); + } + + public function testReplyWithTz() + { + $itip = <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +METHOD:REPLY +BEGIN:VTIMEZONE +TZID:(UTC+01:00) Brussels\, Copenhagen\, Madrid\, Paris +BEGIN:DAYLIGHT +TZOFFSETFROM:+0100 +TZOFFSETTO:+0200 +TZNAME:CEST +DTSTART:19700329T020000 +RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU +END:DAYLIGHT +BEGIN:STANDARD +TZOFFSETFROM:+0200 +TZOFFSETTO:+0100 +TZNAME:CET +DTSTART:19701025T030000 +RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU +END:STANDARD +END:VTIMEZONE +BEGIN:VEVENT +ATTENDEE;PARTSTAT=ACCEPTED:mailto:foo@example.org +ORGANIZER:mailto:bar@example.org +SEQUENCE:2 +UID:foobar +DTSTART;TZID="(UTC+01:00) Brussels, Copenhagen, Madrid, Paris":20140716T120000Z +DTEND;TZID="(UTC+01:00) Brussels, Copenhagen, Madrid, Paris":20140716T130000Z +END:VEVENT +END:VCALENDAR +ICS; + + $old = <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +BEGIN:VTIMEZONE +TZID:(UTC+01:00) Brussels\, Copenhagen\, Madrid\, Paris +BEGIN:DAYLIGHT +TZOFFSETFROM:+0100 +TZOFFSETTO:+0200 +TZNAME:CEST +DTSTART:19700329T020000 +RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU +END:DAYLIGHT +BEGIN:STANDARD +TZOFFSETFROM:+0200 +TZOFFSETTO:+0100 +TZNAME:CET +DTSTART:19701025T030000 +RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU +END:STANDARD +END:VTIMEZONE +BEGIN:VEVENT +SEQUENCE:2 +UID:foobar +ATTENDEE:mailto:foo@example.org +ORGANIZER:mailto:bar@example.org +DTSTART;TZID="(UTC+01:00) Brussels, Copenhagen, Madrid, Paris":20140716T120000Z +DTEND;TZID="(UTC+01:00) Brussels, Copenhagen, Madrid, Paris":20140716T130000Z +END:VEVENT +END:VCALENDAR +ICS; + + $expected = <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +BEGIN:VTIMEZONE +TZID:(UTC+01:00) Brussels\, Copenhagen\, Madrid\, Paris +BEGIN:DAYLIGHT +TZOFFSETFROM:+0100 +TZOFFSETTO:+0200 +TZNAME:CEST +DTSTART:19700329T020000 +RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU +END:DAYLIGHT +BEGIN:STANDARD +TZOFFSETFROM:+0200 +TZOFFSETTO:+0100 +TZNAME:CET +DTSTART:19701025T030000 +RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU +END:STANDARD +END:VTIMEZONE +BEGIN:VEVENT +SEQUENCE:2 +UID:foobar +ATTENDEE;PARTSTAT=ACCEPTED;SCHEDULE-STATUS=2.0:mailto:foo@example.org +ORGANIZER:mailto:bar@example.org +DTSTART;TZID="(UTC+01:00) Brussels, Copenhagen, Madrid, Paris":20140716T120000Z +DTEND;TZID="(UTC+01:00) Brussels, Copenhagen, Madrid, Paris":20140716T130000Z +END:VEVENT +END:VCALENDAR +ICS; + + $result = $this->process($itip, $old, $expected); + } + + public function testReplyRequestStatus() + { + $itip = <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +METHOD:REPLY +BEGIN:VEVENT +UID:foobar +REQUEST-STATUS:2.3;foo-bar! +ATTENDEE;PARTSTAT=ACCEPTED:mailto:foo@example.org +ORGANIZER:mailto:bar@example.org +SEQUENCE:2 +UID:foobar +END:VEVENT +END:VCALENDAR +ICS; + + $old = <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +BEGIN:VEVENT +UID:foobar +SEQUENCE:2 +ATTENDEE:mailto:foo@example.org +ORGANIZER:mailto:bar@example.org +END:VEVENT +END:VCALENDAR +ICS; + + $expected = <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +BEGIN:VEVENT +UID:foobar +SEQUENCE:2 +ATTENDEE;PARTSTAT=ACCEPTED;SCHEDULE-STATUS=2.3:mailto:foo@example.org +ORGANIZER:mailto:bar@example.org +END:VEVENT +END:VCALENDAR +ICS; + + $result = $this->process($itip, $old, $expected); + } + + public function testReplyPartyCrasher() + { + $itip = <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +METHOD:REPLY +BEGIN:VEVENT +ATTENDEE;PARTSTAT=ACCEPTED:mailto:crasher@example.org +ORGANIZER:mailto:bar@example.org +SEQUENCE:2 +UID:foobar +END:VEVENT +END:VCALENDAR +ICS; + + $old = <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +BEGIN:VEVENT +SEQUENCE:2 +UID:foobar +ATTENDEE:mailto:foo@example.org +ORGANIZER:mailto:bar@example.org +END:VEVENT +END:VCALENDAR +ICS; + + $expected = <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +BEGIN:VEVENT +SEQUENCE:2 +UID:foobar +ATTENDEE:mailto:foo@example.org +ORGANIZER:mailto:bar@example.org +ATTENDEE;PARTSTAT=ACCEPTED:mailto:crasher@example.org +END:VEVENT +END:VCALENDAR +ICS; + + $result = $this->process($itip, $old, $expected); + } + + public function testReplyNewException() + { + // This is a reply to 1 instance of a recurring event. This should + // automatically create an exception. + $itip = <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +METHOD:REPLY +BEGIN:VEVENT +ATTENDEE;PARTSTAT=ACCEPTED:mailto:foo@example.org +ORGANIZER:mailto:bar@example.org +SEQUENCE:2 +RECURRENCE-ID:20140725T000000Z +UID:foobar +END:VEVENT +END:VCALENDAR +ICS; + + $old = <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +BEGIN:VEVENT +SEQUENCE:2 +UID:foobar +RRULE:FREQ=DAILY +DTSTART:20140724T000000Z +DTEND:20140724T010000Z +ATTENDEE:mailto:foo@example.org +ORGANIZER:mailto:bar@example.org +END:VEVENT +END:VCALENDAR +ICS; + + $expected = <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +BEGIN:VEVENT +SEQUENCE:2 +UID:foobar +RRULE:FREQ=DAILY +DTSTART:20140724T000000Z +DTEND:20140724T010000Z +ATTENDEE:mailto:foo@example.org +ORGANIZER:mailto:bar@example.org +END:VEVENT +BEGIN:VEVENT +SEQUENCE:2 +UID:foobar +DTSTART:20140725T000000Z +DTEND:20140725T010000Z +ATTENDEE;PARTSTAT=ACCEPTED:mailto:foo@example.org +ORGANIZER:mailto:bar@example.org +RECURRENCE-ID:20140725T000000Z +END:VEVENT +END:VCALENDAR +ICS; + + $result = $this->process($itip, $old, $expected); + } + + public function testReplyNewExceptionTz() + { + // This is a reply to 1 instance of a recurring event. This should + // automatically create an exception. + $itip = <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +METHOD:REPLY +BEGIN:VEVENT +ATTENDEE;PARTSTAT=ACCEPTED:mailto:foo@example.org +ORGANIZER:mailto:bar@example.org +SEQUENCE:2 +RECURRENCE-ID;TZID=America/Toronto:20140725T000000 +UID:foobar +END:VEVENT +END:VCALENDAR +ICS; + + $old = <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +BEGIN:VEVENT +SEQUENCE:2 +UID:foobar +RRULE:FREQ=DAILY +DTSTART;TZID=America/Toronto:20140724T000000 +DTEND;TZID=America/Toronto:20140724T010000 +ATTENDEE:mailto:foo@example.org +ORGANIZER:mailto:bar@example.org +END:VEVENT +END:VCALENDAR +ICS; + + $expected = <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +BEGIN:VEVENT +SEQUENCE:2 +UID:foobar +RRULE:FREQ=DAILY +DTSTART;TZID=America/Toronto:20140724T000000 +DTEND;TZID=America/Toronto:20140724T010000 +ATTENDEE:mailto:foo@example.org +ORGANIZER:mailto:bar@example.org +END:VEVENT +BEGIN:VEVENT +SEQUENCE:2 +UID:foobar +DTSTART;TZID=America/Toronto:20140725T000000 +DTEND;TZID=America/Toronto:20140725T010000 +ATTENDEE;PARTSTAT=ACCEPTED:mailto:foo@example.org +ORGANIZER:mailto:bar@example.org +RECURRENCE-ID;TZID=America/Toronto:20140725T000000 +END:VEVENT +END:VCALENDAR +ICS; + + $result = $this->process($itip, $old, $expected); + } + + public function testReplyPartyCrashCreateExcepton() + { + // IN this test there's a recurring event that has an exception. The + // exception is missing the attendee. + // + // The attendee party crashes the instance, so it should show up in the + // resulting object. + $itip = <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +METHOD:REPLY +BEGIN:VEVENT +ATTENDEE;PARTSTAT=ACCEPTED;CN=Crasher!:mailto:crasher@example.org +ORGANIZER:mailto:bar@example.org +SEQUENCE:2 +RECURRENCE-ID:20140725T000000Z +UID:foobar +END:VEVENT +END:VCALENDAR +ICS; + + $old = <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +BEGIN:VEVENT +SEQUENCE:2 +UID:foobar +RRULE:FREQ=DAILY +DTSTART:20140724T000000Z +DTEND:20140724T010000Z +ORGANIZER:mailto:bar@example.org +END:VEVENT +END:VCALENDAR +ICS; + + $expected = <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +BEGIN:VEVENT +SEQUENCE:2 +UID:foobar +RRULE:FREQ=DAILY +DTSTART:20140724T000000Z +DTEND:20140724T010000Z +ORGANIZER:mailto:bar@example.org +END:VEVENT +BEGIN:VEVENT +SEQUENCE:2 +UID:foobar +DTSTART:20140725T000000Z +DTEND:20140725T010000Z +ORGANIZER:mailto:bar@example.org +RECURRENCE-ID:20140725T000000Z +ATTENDEE;PARTSTAT=ACCEPTED;CN=Crasher!:mailto:crasher@example.org +END:VEVENT +END:VCALENDAR +ICS; + + $result = $this->process($itip, $old, $expected); + } + + public function testReplyNewExceptionNoMasterEvent() + { + /** + * This iTip message would normally create a new exception, but the + * server is not able to create this new instance, because there's no + * master event to clone from. + * + * This test checks if the message is ignored. + */ + $itip = <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +METHOD:REPLY +BEGIN:VEVENT +ATTENDEE;PARTSTAT=ACCEPTED;CN=Crasher!:mailto:crasher@example.org +ORGANIZER:mailto:bar@example.org +SEQUENCE:2 +RECURRENCE-ID:20140725T000000Z +UID:foobar +END:VEVENT +END:VCALENDAR +ICS; + + $old = <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +BEGIN:VEVENT +SEQUENCE:2 +UID:foobar +RRULE:FREQ=DAILY +DTSTART:20140724T000000Z +DTEND:20140724T010000Z +RECURRENCE-ID:20140724T000000Z +ORGANIZER:mailto:bar@example.org +END:VEVENT +END:VCALENDAR +ICS; + + $expected = null; + $result = $this->process($itip, $old, $expected); + } + + /** + * @depends testReplyAccept + */ + public function testReplyAcceptUpdateRSVP() + { + $itip = <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +METHOD:REPLY +BEGIN:VEVENT +ATTENDEE;PARTSTAT=ACCEPTED:mailto:foo@example.org +ORGANIZER:mailto:bar@example.org +SEQUENCE:2 +UID:foobar +END:VEVENT +END:VCALENDAR +ICS; + + $old = <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +BEGIN:VEVENT +SEQUENCE:2 +UID:foobar +ATTENDEE;RSVP=TRUE:mailto:foo@example.org +ORGANIZER:mailto:bar@example.org +END:VEVENT +END:VCALENDAR +ICS; + + $expected = <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +BEGIN:VEVENT +SEQUENCE:2 +UID:foobar +ATTENDEE;PARTSTAT=ACCEPTED;SCHEDULE-STATUS=2.0:mailto:foo@example.org +ORGANIZER:mailto:bar@example.org +END:VEVENT +END:VCALENDAR +ICS; + + $result = $this->process($itip, $old, $expected); + } + + public function testReplyNewExceptionFirstOccurence() + { + // This is a reply to 1 instance of a recurring event. This should + // automatically create an exception. + $itip = <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +METHOD:REPLY +BEGIN:VEVENT +ATTENDEE;PARTSTAT=ACCEPTED:mailto:foo@example.org +ORGANIZER:mailto:bar@example.org +SEQUENCE:2 +RECURRENCE-ID:20140724T000000Z +UID:foobar +END:VEVENT +END:VCALENDAR +ICS; + + $old = <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +BEGIN:VEVENT +SEQUENCE:2 +UID:foobar +RRULE:FREQ=DAILY +DTSTART:20140724T000000Z +DTEND:20140724T010000Z +ATTENDEE:mailto:foo@example.org +ORGANIZER:mailto:bar@example.org +END:VEVENT +END:VCALENDAR +ICS; + + $expected = <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +BEGIN:VEVENT +SEQUENCE:2 +UID:foobar +RRULE:FREQ=DAILY +DTSTART:20140724T000000Z +DTEND:20140724T010000Z +ATTENDEE:mailto:foo@example.org +ORGANIZER:mailto:bar@example.org +END:VEVENT +BEGIN:VEVENT +SEQUENCE:2 +UID:foobar +DTSTART:20140724T000000Z +DTEND:20140724T010000Z +ATTENDEE;PARTSTAT=ACCEPTED:mailto:foo@example.org +ORGANIZER:mailto:bar@example.org +RECURRENCE-ID:20140724T000000Z +END:VEVENT +END:VCALENDAR +ICS; + + $result = $this->process($itip, $old, $expected); + } +} diff --git a/vendor/sabre/vobject/tests/VObject/ITip/BrokerSignificantChangesTest.php b/vendor/sabre/vobject/tests/VObject/ITip/BrokerSignificantChangesTest.php new file mode 100644 index 000000000..a225cb98c --- /dev/null +++ b/vendor/sabre/vobject/tests/VObject/ITip/BrokerSignificantChangesTest.php @@ -0,0 +1,108 @@ +<?php + +namespace Sabre\VObject\ITip; + +class BrokerSignificantChangesTest extends BrokerTester +{ + /** + * Check significant changes detection (no change). + */ + public function testSignificantChangesNoChange() + { + $old = <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +CALSCALE:GREGORIAN +PRODID:-//Ximian//NONSGML Evolution Calendar//EN +BEGIN:VEVENT +UID:20140813T153116Z-12176-1000-1065-6@johnny-lubuntu +DTSTAMP:20140813T142829Z +DTSTART;TZID=America/Toronto:20140815T110000 +SEQUENCE:2 +SUMMARY:Evo makes a Meeting +LOCATION:fruux HQ +CLASS:PUBLIC +RRULE:FREQ=WEEKLY +ORGANIZER:MAILTO:martin@fruux.com +ATTENDEE;CUTYPE=INDIVIDUAL;ROLE=REQ-PARTICIPANT;PARTSTAT=NEEDS-ACTION;RSVP= + TRUE;LANGUAGE=en:MAILTO:dominik@fruux.com +CREATED:20140813T153211Z +LAST-MODIFIED:20140813T155353Z +END:VEVENT +END:VCALENDAR +ICS; + + $new = $old; + $expected = [['significantChange' => false]]; + + $this->parse($old, $new, $expected, 'mailto:martin@fruux.com'); + } + + /** + * Check significant changes detection (no change). + */ + public function testSignificantChangesRRuleNoChange() + { + $old = <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +CALSCALE:GREGORIAN +PRODID:-//Ximian//NONSGML Evolution Calendar//EN +BEGIN:VEVENT +UID:20140813T153116Z-12176-1000-1065-6@johnny-lubuntu +DTSTAMP:20140813T142829Z +DTSTART;TZID=America/Toronto:20140815T110000 +SEQUENCE:2 +SUMMARY:Evo makes a Meeting +LOCATION:fruux HQ +CLASS:PUBLIC +RRULE:FREQ=WEEKLY +ORGANIZER:MAILTO:martin@fruux.com +ATTENDEE;CUTYPE=INDIVIDUAL;ROLE=REQ-PARTICIPANT;PARTSTAT=NEEDS-ACTION;RSVP= + TRUE;LANGUAGE=en:MAILTO:dominik@fruux.com +CREATED:20140813T153211Z +LAST-MODIFIED:20140813T155353Z +END:VEVENT +END:VCALENDAR +ICS; + + $new = str_replace('FREQ=WEEKLY', 'FREQ=WEEKLY;INTERVAL=1', $old); + $expected = [['significantChange' => false]]; + + $this->parse($old, $new, $expected, 'mailto:martin@fruux.com'); + } + + /** + * Check significant changes detection (no change). + */ + public function testSignificantChangesRRuleOrderNoChange() + { + $old = <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +CALSCALE:GREGORIAN +PRODID:-//Ximian//NONSGML Evolution Calendar//EN +BEGIN:VEVENT +UID:20140813T153116Z-12176-1000-1065-6@johnny-lubuntu +DTSTAMP:20140813T142829Z +DTSTART;TZID=America/Toronto:20140815T110000 +SEQUENCE:2 +SUMMARY:Evo makes a Meeting +LOCATION:fruux HQ +CLASS:PUBLIC +RRULE:FREQ=WEEKLY;BYDAY=MO +ORGANIZER:MAILTO:martin@fruux.com +ATTENDEE;CUTYPE=INDIVIDUAL;ROLE=REQ-PARTICIPANT;PARTSTAT=NEEDS-ACTION;RSVP= + TRUE;LANGUAGE=en:MAILTO:dominik@fruux.com +CREATED:20140813T153211Z +LAST-MODIFIED:20140813T155353Z +END:VEVENT +END:VCALENDAR +ICS; + + $new = str_replace('FREQ=WEEKLY;BYDAY=MO', 'BYDAY=MO;FREQ=WEEKLY', $old); + $expected = [['significantChange' => false]]; + + $this->parse($old, $new, $expected, 'mailto:martin@fruux.com'); + } +} diff --git a/vendor/sabre/vobject/tests/VObject/ITip/BrokerTester.php b/vendor/sabre/vobject/tests/VObject/ITip/BrokerTester.php new file mode 100644 index 000000000..350e37e23 --- /dev/null +++ b/vendor/sabre/vobject/tests/VObject/ITip/BrokerTester.php @@ -0,0 +1,92 @@ +<?php + +namespace Sabre\VObject\ITip; + +use PHPUnit\Framework\TestCase; +use Sabre\VObject\Reader; + +/** + * Utilities for testing the broker. + * + * @copyright Copyright (C) fruux GmbH (https://fruux.com/) + * @author Evert Pot (http://evertpot.com/) + * @license http://sabre.io/license/ Modified BSD License + */ +abstract class BrokerTester extends TestCase +{ + use \Sabre\VObject\PHPUnitAssertions; + + public function parse($oldMessage, $newMessage, $expected = [], $currentUser = 'mailto:one@example.org') + { + $broker = new Broker(); + $result = $broker->parseEvent($newMessage, $currentUser, $oldMessage); + + $this->assertEquals(count($expected), count($result)); + + foreach ($expected as $index => $ex) { + $message = $result[$index]; + + foreach ($ex as $key => $val) { + if ('message' === $key) { + $this->assertVObjectEqualsVObject( + $val, + $message->message->serialize() + ); + } else { + $this->assertEquals($val, $message->$key); + } + } + } + } + + public function process($input, $existingObject = null, $expected = false) + { + $version = \Sabre\VObject\Version::VERSION; + + $vcal = Reader::read($input); + + foreach ($vcal->getComponents() as $mainComponent) { + if ('VEVENT' === $mainComponent->name) { + break; + } + } + + $message = new Message(); + $message->message = $vcal; + $message->method = isset($vcal->METHOD) ? $vcal->METHOD->getValue() : null; + $message->component = $mainComponent->name; + $message->uid = $mainComponent->UID->getValue(); + $message->sequence = isset($vcal->VEVENT[0]) ? (string) $vcal->VEVENT[0]->SEQUENCE : null; + + if ('REPLY' === $message->method) { + $message->sender = $mainComponent->ATTENDEE->getValue(); + $message->senderName = isset($mainComponent->ATTENDEE['CN']) ? $mainComponent->ATTENDEE['CN']->getValue() : null; + $message->recipient = $mainComponent->ORGANIZER->getValue(); + $message->recipientName = isset($mainComponent->ORGANIZER['CN']) ? $mainComponent->ORGANIZER['CN'] : null; + } + + $broker = new Broker(); + + if (is_string($existingObject)) { + $existingObject = str_replace( + '%foo%', + "VERSION:2.0\nPRODID:-//Sabre//Sabre VObject $version//EN\nCALSCALE:GREGORIAN", + $existingObject + ); + $existingObject = Reader::read($existingObject); + } + + $result = $broker->processMessage($message, $existingObject); + + if (is_null($expected)) { + $this->assertTrue(!$result); + + return; + } + + $this->assertVObjectEqualsVObject( + $expected, + $result + ); + } +} diff --git a/vendor/sabre/vobject/tests/VObject/ITip/BrokerTimezoneInParseEventInfoWithoutMasterTest.php b/vendor/sabre/vobject/tests/VObject/ITip/BrokerTimezoneInParseEventInfoWithoutMasterTest.php new file mode 100644 index 000000000..1635be742 --- /dev/null +++ b/vendor/sabre/vobject/tests/VObject/ITip/BrokerTimezoneInParseEventInfoWithoutMasterTest.php @@ -0,0 +1,78 @@ +<?php + +namespace Sabre\VObject\ITip; + +use PHPUnit\Framework\TestCase; +use Sabre\VObject\Reader; + +class BrokerTimezoneInParseEventInfoWithoutMasterTest extends TestCase +{ + public function testTimezoneInParseEventInfoWithoutMaster() + { + $calendar = <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +PRODID:-//Apple Inc.//Mac OS X 10.9.5//EN +CALSCALE:GREGORIAN +BEGIN:VTIMEZONE +TZID:Europe/Minsk +BEGIN:DAYLIGHT +TZOFFSETFROM:+0200 +RRULE:FREQ=YEARLY;UNTIL=20100328T000000Z;BYMONTH=3;BYDAY=-1SU +DTSTART:19930328T020000 +TZNAME:GMT+3 +TZOFFSETTO:+0300 +END:DAYLIGHT +BEGIN:STANDARD +TZOFFSETFROM:+0200 +DTSTART:20110327T020000 +TZNAME:GMT+3 +TZOFFSETTO:+0300 +RDATE:20110327T020000 +END:STANDARD +END:VTIMEZONE +BEGIN:VEVENT +CREATED:20160331T163031Z +UID:B9301437-417C-4136-8DB3-8D1555863791 +DTEND;TZID=Europe/Minsk:20160405T100000 +TRANSP:OPAQUE +ATTENDEE;CN=User Invitee;CUTYPE=INDIVIDUAL;EMAIL=invitee@test.com;PARTSTAT= + ACCEPTED;ROLE=REQ-PARTICIPANT:mailto:invitee@test.com +ATTENDEE;CN=User Organizer;CUTYPE=INDIVIDUAL;PARTSTAT=ACCEPTED:mailto:organ + izer@test.com +SUMMARY:Event title +DTSTART;TZID=Europe/Minsk:20160405T090000 +DTSTAMP:20160331T164108Z +ORGANIZER;CN=User Organizer:mailto:organizer@test.com +SEQUENCE:6 +RECURRENCE-ID;TZID=Europe/Minsk:20160405T090000 +END:VEVENT +BEGIN:VEVENT +CREATED:20160331T163031Z +UID:B9301437-417C-4136-8DB3-8D1555863791 +DTEND;TZID=Europe/Minsk:20160406T100000 +TRANSP:OPAQUE +ATTENDEE;CN=User Invitee;CUTYPE=INDIVIDUAL;EMAIL=invitee@test.com;PARTSTAT= + ACCEPTED;ROLE=REQ-PARTICIPANT:mailto:invitee@test.com +ATTENDEE;CN=User Organizer;CUTYPE=INDIVIDUAL;PARTSTAT=ACCEPTED:mailto:organ + izer@test.com +SUMMARY:Event title +DTSTART;TZID=Europe/Minsk:20160406T090000 +DTSTAMP:20160331T165845Z +ORGANIZER;CN=User Organizer:mailto:organizer@test.com +SEQUENCE:6 +RECURRENCE-ID;TZID=Europe/Minsk:20160406T090000 +END:VEVENT +END:VCALENDAR +ICS; + + $calendar = Reader::read($calendar); + $broker = new Broker(); + + $reflectionMethod = new \ReflectionMethod($broker, 'parseEventInfo'); + $reflectionMethod->setAccessible(true); + $data = $reflectionMethod->invoke($broker, $calendar); + $this->assertInstanceOf('DateTimeZone', $data['timezone']); + $this->assertEquals($data['timezone']->getName(), 'Europe/Minsk'); + } +} diff --git a/vendor/sabre/vobject/tests/VObject/ITip/BrokerUpdateEventTest.php b/vendor/sabre/vobject/tests/VObject/ITip/BrokerUpdateEventTest.php new file mode 100644 index 000000000..e93f89652 --- /dev/null +++ b/vendor/sabre/vobject/tests/VObject/ITip/BrokerUpdateEventTest.php @@ -0,0 +1,817 @@ +<?php + +namespace Sabre\VObject\ITip; + +class BrokerUpdateEventTest extends BrokerTester +{ + public function testInviteChange() + { + $oldMessage = <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +BEGIN:VEVENT +UID:foobar +SEQUENCE:1 +SUMMARY:foo +ORGANIZER;CN=Strunk:mailto:strunk@example.org +ATTENDEE;CN=Strunk;PARTSTAT=ACCEPTED:mailto:strunk@example.org +ATTENDEE;CN=One:mailto:one@example.org +ATTENDEE;CN=Two:mailto:two@example.org +DTSTART:20140716T120000Z +DTEND:20140716T130000Z +END:VEVENT +END:VCALENDAR +ICS; + + $newMessage = <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +BEGIN:VEVENT +UID:foobar +SEQUENCE:2 +SUMMARY:foo +ORGANIZER;CN=Strunk:mailto:strunk@example.org +ATTENDEE;CN=Strunk;PARTSTAT=ACCEPTED:mailto:strunk@example.org +ATTENDEE;CN=Two:mailto:two@example.org +ATTENDEE;CN=Three:mailto:three@example.org +DTSTART:20140716T120000Z +DTEND:20140716T130000Z +END:VEVENT +END:VCALENDAR +ICS; + + $version = \Sabre\VObject\Version::VERSION; + + $expected = [ + [ + 'uid' => 'foobar', + 'method' => 'CANCEL', + 'component' => 'VEVENT', + 'sender' => 'mailto:strunk@example.org', + 'senderName' => 'Strunk', + 'recipient' => 'mailto:one@example.org', + 'recipientName' => 'One', + 'significantChange' => true, + 'message' => <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +PRODID:-//Sabre//Sabre VObject $version//EN +CALSCALE:GREGORIAN +METHOD:CANCEL +BEGIN:VEVENT +UID:foobar +DTSTAMP:**ANY** +SEQUENCE:2 +SUMMARY:foo +DTSTART:20140716T120000Z +DTEND:20140716T130000Z +ORGANIZER;CN=Strunk:mailto:strunk@example.org +ATTENDEE;CN=One:mailto:one@example.org +END:VEVENT +END:VCALENDAR +ICS + ], + [ + 'uid' => 'foobar', + 'method' => 'REQUEST', + 'component' => 'VEVENT', + 'sender' => 'mailto:strunk@example.org', + 'senderName' => 'Strunk', + 'recipient' => 'mailto:two@example.org', + 'recipientName' => 'Two', + 'significantChange' => false, + 'message' => <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +PRODID:-//Sabre//Sabre VObject $version//EN +CALSCALE:GREGORIAN +METHOD:REQUEST +BEGIN:VEVENT +UID:foobar +SEQUENCE:2 +SUMMARY:foo +ORGANIZER;CN=Strunk:mailto:strunk@example.org +ATTENDEE;CN=Strunk;PARTSTAT=ACCEPTED:mailto:strunk@example.org +ATTENDEE;CN=Two;PARTSTAT=NEEDS-ACTION:mailto:two@example.org +ATTENDEE;CN=Three;PARTSTAT=NEEDS-ACTION:mailto:three@example.org +DTSTART:20140716T120000Z +DTEND:20140716T130000Z +DTSTAMP:**ANY** +END:VEVENT +END:VCALENDAR +ICS + ], + [ + 'uid' => 'foobar', + 'method' => 'REQUEST', + 'component' => 'VEVENT', + 'sender' => 'mailto:strunk@example.org', + 'senderName' => 'Strunk', + 'recipient' => 'mailto:three@example.org', + 'recipientName' => 'Three', + 'significantChange' => true, + 'message' => <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +PRODID:-//Sabre//Sabre VObject $version//EN +CALSCALE:GREGORIAN +METHOD:REQUEST +BEGIN:VEVENT +UID:foobar +SEQUENCE:2 +SUMMARY:foo +ORGANIZER;CN=Strunk:mailto:strunk@example.org +ATTENDEE;CN=Strunk;PARTSTAT=ACCEPTED:mailto:strunk@example.org +ATTENDEE;CN=Two;PARTSTAT=NEEDS-ACTION:mailto:two@example.org +ATTENDEE;CN=Three;PARTSTAT=NEEDS-ACTION:mailto:three@example.org +DTSTART:20140716T120000Z +DTEND:20140716T130000Z +DTSTAMP:**ANY** +END:VEVENT +END:VCALENDAR +ICS + ], + ]; + + $this->parse($oldMessage, $newMessage, $expected, 'mailto:strunk@example.org'); + } + + public function testInviteChangeFromNonSchedulingToSchedulingObject() + { + $oldMessage = <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +BEGIN:VEVENT +UID:foobar +SEQUENCE:1 +DTSTART:20140716T120000Z +DTEND:20140716T130000Z +END:VEVENT +END:VCALENDAR +ICS; + + $newMessage = <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +BEGIN:VEVENT +UID:foobar +SEQUENCE:2 +ORGANIZER;CN=Strunk:mailto:strunk@example.org +ATTENDEE;CN=One:mailto:one@example.org +DTSTART:20140716T120000Z +DTEND:20140716T130000Z +END:VEVENT +END:VCALENDAR +ICS; + + $version = \Sabre\VObject\Version::VERSION; + + $expected = [ + [ + 'uid' => 'foobar', + 'method' => 'REQUEST', + 'component' => 'VEVENT', + 'sender' => 'mailto:strunk@example.org', + 'senderName' => 'Strunk', + 'recipient' => 'mailto:one@example.org', + 'recipientName' => 'One', + 'message' => <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +PRODID:-//Sabre//Sabre VObject $version//EN +CALSCALE:GREGORIAN +METHOD:REQUEST +BEGIN:VEVENT +UID:foobar +SEQUENCE:2 +ORGANIZER;CN=Strunk:mailto:strunk@example.org +ATTENDEE;CN=One;PARTSTAT=NEEDS-ACTION:mailto:one@example.org +DTSTART:20140716T120000Z +DTEND:20140716T130000Z +DTSTAMP:**ANY** +END:VEVENT +END:VCALENDAR +ICS + ], + ]; + + $this->parse($oldMessage, $newMessage, $expected, 'mailto:strunk@example.org'); + } + + public function testInviteChangeFromSchedulingToNonSchedulingObject() + { + $oldMessage = <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +BEGIN:VEVENT +UID:foobar +SEQUENCE:2 +ORGANIZER;CN=Strunk:mailto:strunk@example.org +ATTENDEE;CN=One:mailto:one@example.org +DTSTART:20140716T120000Z +DTEND:20140716T130000Z +END:VEVENT +END:VCALENDAR +ICS; + + $newMessage = <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +BEGIN:VEVENT +UID:foobar +SEQUENCE:1 +DTSTART:20140716T120000Z +DTEND:20140716T130000Z +END:VEVENT +END:VCALENDAR +ICS; + + $version = \Sabre\VObject\Version::VERSION; + + $expected = [ + [ + 'uid' => 'foobar', + 'method' => 'CANCEL', + 'component' => 'VEVENT', + 'message' => <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +PRODID:-//Sabre//Sabre VObject $version//EN +CALSCALE:GREGORIAN +METHOD:CANCEL +BEGIN:VEVENT +UID:foobar +DTSTAMP:**ANY** +SEQUENCE:1 +DTSTART:20140716T120000Z +DTEND:20140716T130000Z +ORGANIZER;CN=Strunk:mailto:strunk@example.org +ATTENDEE;CN=One:mailto:one@example.org +END:VEVENT +END:VCALENDAR +ICS + ], + ]; + + $this->parse($oldMessage, $newMessage, $expected, 'mailto:strunk@example.org'); + } + + public function testNoAttendees() + { + $oldMessage = <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +BEGIN:VEVENT +UID:foobar +SEQUENCE:1 +DTSTART:20140716T120000Z +DTEND:20140716T130000Z +END:VEVENT +END:VCALENDAR +ICS; + + $newMessage = <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +BEGIN:VEVENT +UID:foobar +SEQUENCE:2 +DTSTART:20140716T120000Z +DTEND:20140716T130000Z +END:VEVENT +END:VCALENDAR +ICS; + + $version = \Sabre\VObject\Version::VERSION; + + $expected = []; + $this->parse($oldMessage, $newMessage, $expected, 'mailto:strunk@example.org'); + } + + public function testRemoveInstance() + { + $oldMessage = <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +BEGIN:VEVENT +UID:foobar +SEQUENCE:1 +ORGANIZER;CN=Strunk:mailto:strunk@example.org +ATTENDEE;CN=One:mailto:one@example.org +DTSTART;TZID=America/Toronto:20140716T120000 +DTEND;TZID=America/Toronto:20140716T130000 +RRULE:FREQ=WEEKLY +END:VEVENT +END:VCALENDAR +ICS; + + $newMessage = <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +BEGIN:VEVENT +UID:foobar +SEQUENCE:2 +ORGANIZER;CN=Strunk:mailto:strunk@example.org +ATTENDEE;CN=One:mailto:one@example.org +DTSTART;TZID=America/Toronto:20140716T120000 +DTEND;TZID=America/Toronto:20140716T130000 +RRULE:FREQ=WEEKLY +EXDATE;TZID=America/Toronto:20140724T120000 +END:VEVENT +END:VCALENDAR +ICS; + + $version = \Sabre\VObject\Version::VERSION; + + $expected = [ + [ + 'uid' => 'foobar', + 'method' => 'REQUEST', + 'component' => 'VEVENT', + 'sender' => 'mailto:strunk@example.org', + 'senderName' => 'Strunk', + 'recipient' => 'mailto:one@example.org', + 'recipientName' => 'One', + 'message' => <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +PRODID:-//Sabre//Sabre VObject $version//EN +CALSCALE:GREGORIAN +METHOD:REQUEST +BEGIN:VEVENT +UID:foobar +SEQUENCE:2 +ORGANIZER;CN=Strunk:mailto:strunk@example.org +ATTENDEE;CN=One;PARTSTAT=NEEDS-ACTION:mailto:one@example.org +DTSTART;TZID=America/Toronto:20140716T120000 +DTEND;TZID=America/Toronto:20140716T130000 +RRULE:FREQ=WEEKLY +EXDATE;TZID=America/Toronto:20140724T120000 +DTSTAMP:**ANY** +END:VEVENT +END:VCALENDAR +ICS + ], + ]; + + $this->parse($oldMessage, $newMessage, $expected, 'mailto:strunk@example.org'); + } + + /** + * This test is identical to the first test, except this time we change the + * DURATION property. + * + * This should ensure that the message is significant for every attendee, + */ + public function testInviteChangeSignificantChange() + { + $oldMessage = <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +BEGIN:VEVENT +UID:foobar +DURATION:PT1H +SEQUENCE:1 +ORGANIZER;CN=Strunk:mailto:strunk@example.org +ATTENDEE;CN=Strunk;PARTSTAT=ACCEPTED:mailto:strunk@example.org +ATTENDEE;CN=One:mailto:one@example.org +ATTENDEE;CN=Two:mailto:two@example.org +DTSTART:20140716T120000Z +DTEND:20140716T130000Z +END:VEVENT +END:VCALENDAR +ICS; + + $newMessage = <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +BEGIN:VEVENT +UID:foobar +DURATION:PT2H +SEQUENCE:2 +ORGANIZER;CN=Strunk:mailto:strunk@example.org +ATTENDEE;CN=Strunk;PARTSTAT=ACCEPTED:mailto:strunk@example.org +ATTENDEE;CN=Two:mailto:two@example.org +ATTENDEE;CN=Three:mailto:three@example.org +DTSTART:20140716T120000Z +DTEND:20140716T130000Z +END:VEVENT +END:VCALENDAR +ICS; + + $version = \Sabre\VObject\Version::VERSION; + + $expected = [ + [ + 'uid' => 'foobar', + 'method' => 'CANCEL', + 'component' => 'VEVENT', + 'sender' => 'mailto:strunk@example.org', + 'senderName' => 'Strunk', + 'recipient' => 'mailto:one@example.org', + 'recipientName' => 'One', + 'significantChange' => true, + 'message' => <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +PRODID:-//Sabre//Sabre VObject $version//EN +CALSCALE:GREGORIAN +METHOD:CANCEL +BEGIN:VEVENT +UID:foobar +DTSTAMP:**ANY** +SEQUENCE:2 +DTSTART:20140716T120000Z +DTEND:20140716T130000Z +ORGANIZER;CN=Strunk:mailto:strunk@example.org +ATTENDEE;CN=One:mailto:one@example.org +END:VEVENT +END:VCALENDAR +ICS + ], + [ + 'uid' => 'foobar', + 'method' => 'REQUEST', + 'component' => 'VEVENT', + 'sender' => 'mailto:strunk@example.org', + 'senderName' => 'Strunk', + 'recipient' => 'mailto:two@example.org', + 'recipientName' => 'Two', + 'significantChange' => true, + 'message' => <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +PRODID:-//Sabre//Sabre VObject $version//EN +CALSCALE:GREGORIAN +METHOD:REQUEST +BEGIN:VEVENT +UID:foobar +DURATION:PT2H +SEQUENCE:2 +ORGANIZER;CN=Strunk:mailto:strunk@example.org +ATTENDEE;CN=Strunk;PARTSTAT=ACCEPTED:mailto:strunk@example.org +ATTENDEE;CN=Two;PARTSTAT=NEEDS-ACTION:mailto:two@example.org +ATTENDEE;CN=Three;PARTSTAT=NEEDS-ACTION:mailto:three@example.org +DTSTART:20140716T120000Z +DTEND:20140716T130000Z +DTSTAMP:**ANY** +END:VEVENT +END:VCALENDAR +ICS + ], + [ + 'uid' => 'foobar', + 'method' => 'REQUEST', + 'component' => 'VEVENT', + 'sender' => 'mailto:strunk@example.org', + 'senderName' => 'Strunk', + 'recipient' => 'mailto:three@example.org', + 'recipientName' => 'Three', + 'significantChange' => true, + 'message' => <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +PRODID:-//Sabre//Sabre VObject $version//EN +CALSCALE:GREGORIAN +METHOD:REQUEST +BEGIN:VEVENT +UID:foobar +DURATION:PT2H +SEQUENCE:2 +ORGANIZER;CN=Strunk:mailto:strunk@example.org +ATTENDEE;CN=Strunk;PARTSTAT=ACCEPTED:mailto:strunk@example.org +ATTENDEE;CN=Two;PARTSTAT=NEEDS-ACTION:mailto:two@example.org +ATTENDEE;CN=Three;PARTSTAT=NEEDS-ACTION:mailto:three@example.org +DTSTART:20140716T120000Z +DTEND:20140716T130000Z +DTSTAMP:**ANY** +END:VEVENT +END:VCALENDAR +ICS + ], + ]; + + $this->parse($oldMessage, $newMessage, $expected, 'mailto:strunk@example.org'); + } + + public function testInviteNoChange() + { + $oldMessage = <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +BEGIN:VEVENT +UID:foobar +SEQUENCE:1 +ORGANIZER;CN=Strunk:mailto:strunk@example.org +ATTENDEE;CN=Strunk;PARTSTAT=ACCEPTED:mailto:strunk@example.org +ATTENDEE;CN=One:mailto:one@example.org +DTSTART:20140716T120000Z +DTEND:20140716T130000Z +END:VEVENT +END:VCALENDAR +ICS; + + $newMessage = <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +BEGIN:VEVENT +UID:foobar +SEQUENCE:2 +ORGANIZER;CN=Strunk:mailto:strunk@example.org +ATTENDEE;CN=Strunk;PARTSTAT=ACCEPTED:mailto:strunk@example.org +ATTENDEE;CN=One:mailto:one@example.org +DTSTART:20140716T120000Z +DTEND:20140716T130000Z +END:VEVENT +END:VCALENDAR +ICS; + + $version = \Sabre\VObject\Version::VERSION; + + $expected = [ + [ + 'uid' => 'foobar', + 'method' => 'REQUEST', + 'component' => 'VEVENT', + 'sender' => 'mailto:strunk@example.org', + 'senderName' => 'Strunk', + 'recipient' => 'mailto:one@example.org', + 'recipientName' => 'One', + 'significantChange' => false, + 'message' => <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +PRODID:-//Sabre//Sabre VObject $version//EN +CALSCALE:GREGORIAN +METHOD:REQUEST +BEGIN:VEVENT +UID:foobar +SEQUENCE:2 +ORGANIZER;CN=Strunk:mailto:strunk@example.org +ATTENDEE;CN=Strunk;PARTSTAT=ACCEPTED:mailto:strunk@example.org +ATTENDEE;CN=One;PARTSTAT=NEEDS-ACTION:mailto:one@example.org +DTSTART:20140716T120000Z +DTEND:20140716T130000Z +DTSTAMP:**ANY** +END:VEVENT +END:VCALENDAR +ICS + ], + ]; + + $this->parse($oldMessage, $newMessage, $expected, 'mailto:strunk@example.org'); + } + + public function testInviteNoChangeForceSend() + { + $oldMessage = <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +BEGIN:VEVENT +UID:foobar +SEQUENCE:1 +ORGANIZER;CN=Strunk:mailto:strunk@example.org +ATTENDEE;CN=Strunk;PARTSTAT=ACCEPTED:mailto:strunk@example.org +ATTENDEE;CN=One:mailto:one@example.org +DTSTART:20140716T120000Z +DTEND:20140716T130000Z +END:VEVENT +END:VCALENDAR +ICS; + + $newMessage = <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +BEGIN:VEVENT +UID:foobar +SEQUENCE:2 +ORGANIZER;CN=Strunk:mailto:strunk@example.org +ATTENDEE;CN=Strunk;PARTSTAT=ACCEPTED:mailto:strunk@example.org +ATTENDEE;SCHEDULE-FORCE-SEND=REQUEST;CN=One:mailto:one@example.org +DTSTART:20140716T120000Z +DTEND:20140716T130000Z +END:VEVENT +END:VCALENDAR +ICS; + + $version = \Sabre\VObject\Version::VERSION; + + $expected = [ + [ + 'uid' => 'foobar', + 'method' => 'REQUEST', + 'component' => 'VEVENT', + 'sender' => 'mailto:strunk@example.org', + 'senderName' => 'Strunk', + 'recipient' => 'mailto:one@example.org', + 'recipientName' => 'One', + 'significantChange' => true, + 'message' => <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +PRODID:-//Sabre//Sabre VObject $version//EN +CALSCALE:GREGORIAN +METHOD:REQUEST +BEGIN:VEVENT +UID:foobar +SEQUENCE:2 +ORGANIZER;CN=Strunk:mailto:strunk@example.org +ATTENDEE;CN=Strunk;PARTSTAT=ACCEPTED:mailto:strunk@example.org +ATTENDEE;CN=One;PARTSTAT=NEEDS-ACTION:mailto:one@example.org +DTSTART:20140716T120000Z +DTEND:20140716T130000Z +DTSTAMP:**ANY** +END:VEVENT +END:VCALENDAR +ICS + ], + ]; + + $this->parse($oldMessage, $newMessage, $expected, 'mailto:strunk@example.org'); + } + + public function testInviteRemoveAttendees() + { + $oldMessage = <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +BEGIN:VEVENT +UID:foobar +SEQUENCE:1 +SUMMARY:foo +ORGANIZER;CN=Strunk:mailto:strunk@example.org +ATTENDEE;CN=Strunk:mailto:strunk@example.org +ATTENDEE;CN=One:mailto:one@example.org +ATTENDEE;CN=Two:mailto:two@example.org +DTSTART:20140716T120000Z +DTEND:20140716T130000Z +END:VEVENT +END:VCALENDAR +ICS; + + $newMessage = <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +BEGIN:VEVENT +UID:foobar +SEQUENCE:2 +SUMMARY:foo +DTSTART:20140716T120000Z +DTEND:20140716T130000Z +END:VEVENT +END:VCALENDAR +ICS; + + $version = \Sabre\VObject\Version::VERSION; + + $expected = [ + [ + 'uid' => 'foobar', + 'method' => 'CANCEL', + 'component' => 'VEVENT', + 'sender' => 'mailto:strunk@example.org', + 'senderName' => 'Strunk', + 'recipient' => 'mailto:one@example.org', + 'recipientName' => 'One', + 'significantChange' => true, + 'message' => <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +PRODID:-//Sabre//Sabre VObject $version//EN +CALSCALE:GREGORIAN +METHOD:CANCEL +BEGIN:VEVENT +UID:foobar +DTSTAMP:**ANY** +SEQUENCE:2 +SUMMARY:foo +DTSTART:20140716T120000Z +DTEND:20140716T130000Z +ORGANIZER;CN=Strunk:mailto:strunk@example.org +ATTENDEE;CN=One:mailto:one@example.org +END:VEVENT +END:VCALENDAR +ICS + ], + [ + 'uid' => 'foobar', + 'method' => 'CANCEL', + 'component' => 'VEVENT', + 'sender' => 'mailto:strunk@example.org', + 'senderName' => 'Strunk', + 'recipient' => 'mailto:two@example.org', + 'recipientName' => 'Two', + 'significantChange' => true, + 'message' => <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +PRODID:-//Sabre//Sabre VObject $version//EN +CALSCALE:GREGORIAN +METHOD:CANCEL +BEGIN:VEVENT +UID:foobar +DTSTAMP:**ANY** +SEQUENCE:2 +SUMMARY:foo +DTSTART:20140716T120000Z +DTEND:20140716T130000Z +ORGANIZER;CN=Strunk:mailto:strunk@example.org +ATTENDEE;CN=Two:mailto:two@example.org +END:VEVENT +END:VCALENDAR +ICS + ], + ]; + + $result = $this->parse($oldMessage, $newMessage, $expected, 'mailto:strunk@example.org'); + } + + public function testInviteChangeExdateOrder() + { + $oldMessage = <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +PRODID:-//Apple Inc.//Mac OS X 10.10.1//EN +CALSCALE:GREGORIAN +BEGIN:VEVENT +UID:foobar +SEQUENCE:0 +ORGANIZER;CN=Strunk:mailto:strunk@example.org +ATTENDEE;CN=Strunk;CUTYPE=INDIVIDUAL;EMAIL=strunk@example.org;PARTSTAT=ACCE + PTED:mailto:strunk@example.org +ATTENDEE;CN=One;CUTYPE=INDIVIDUAL;EMAIL=one@example.org;PARTSTAT=ACCEPTED;R + OLE=REQ-PARTICIPANT;SCHEDULE-STATUS="1.2;Message delivered locally":mailto + :one@example.org +SUMMARY:foo +DTSTART:20141211T160000Z +DTEND:20141211T170000Z +RRULE:FREQ=WEEKLY +EXDATE:20141225T160000Z,20150101T160000Z +EXDATE:20150108T160000Z +END:VEVENT +END:VCALENDAR +ICS; + + $newMessage = <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +PRODID:-//Apple Inc.//Mac OS X 10.10.1//EN +CALSCALE:GREGORIAN +BEGIN:VEVENT +UID:foobar +SEQUENCE:1 +ORGANIZER;CN=Strunk:mailto:strunk@example.org +ATTENDEE;CN=Strunk;CUTYPE=INDIVIDUAL;EMAIL=strunk@example.org;PARTSTAT=ACCE + PTED:mailto:strunk@example.org +ATTENDEE;CN=One;CUTYPE=INDIVIDUAL;EMAIL=one@example.org;PARTSTAT=ACCEPTED;R + OLE=REQ-PARTICIPANT;SCHEDULE-STATUS=1.2:mailto:one@example.org +DTSTART:20141211T160000Z +DTEND:20141211T170000Z +RRULE:FREQ=WEEKLY +EXDATE:20150101T160000Z +EXDATE:20150108T160000Z,20141225T160000Z +END:VEVENT +END:VCALENDAR +ICS; + + $version = \Sabre\VObject\Version::VERSION; + + $expected = [ + [ + 'uid' => 'foobar', + 'method' => 'REQUEST', + 'component' => 'VEVENT', + 'sender' => 'mailto:strunk@example.org', + 'senderName' => 'Strunk', + 'recipient' => 'mailto:one@example.org', + 'recipientName' => 'One', + 'significantChange' => false, + 'message' => <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +PRODID:-//Sabre//Sabre VObject $version//EN +CALSCALE:GREGORIAN +METHOD:REQUEST +BEGIN:VEVENT +UID:foobar +SEQUENCE:1 +ORGANIZER;CN=Strunk:mailto:strunk@example.org +ATTENDEE;CN=Strunk;CUTYPE=INDIVIDUAL;EMAIL=strunk@example.org;PARTSTAT=ACCE + PTED:mailto:strunk@example.org +ATTENDEE;CN=One;CUTYPE=INDIVIDUAL;EMAIL=one@example.org;PARTSTAT=ACCEPTED;R + OLE=REQ-PARTICIPANT:mailto:one@example.org +DTSTART:20141211T160000Z +DTEND:20141211T170000Z +RRULE:FREQ=WEEKLY +EXDATE:20150101T160000Z +EXDATE:20150108T160000Z,20141225T160000Z +DTSTAMP:**ANY** +END:VEVENT +END:VCALENDAR +ICS + ], + ]; + + $this->parse($oldMessage, $newMessage, $expected, 'mailto:strunk@example.org'); + } +} diff --git a/vendor/sabre/vobject/tests/VObject/ITip/EvolutionTest.php b/vendor/sabre/vobject/tests/VObject/ITip/EvolutionTest.php new file mode 100644 index 000000000..686a94db1 --- /dev/null +++ b/vendor/sabre/vobject/tests/VObject/ITip/EvolutionTest.php @@ -0,0 +1,2647 @@ +<?php + +namespace Sabre\VObject\ITip; + +class EvolutionTest extends BrokerTester +{ + /** + * Evolution does things as usual a little bit differently. + * + * We're adding a separate test just for it. + */ + public function testNewEvolutionEvent() + { + $ics = <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +CALSCALE:GREGORIAN +PRODID:-//Ximian//NONSGML Evolution Calendar//EN +BEGIN:VTIMEZONE +TZID:/freeassociation.sourceforge.net/Tzfile/America/Toronto +X-LIC-LOCATION:America/Toronto +BEGIN:STANDARD +TZNAME:EST +DTSTART:19691026T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:19700426T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:19701025T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:19710425T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:19711031T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:19720430T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:19721029T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:19730429T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:19731028T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:19740428T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:19741027T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:19750427T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:19751026T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:19760425T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:19761031T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:19770424T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:19771030T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:19780430T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:19781029T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:19790429T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:19791028T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:19800427T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:19801026T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:19810426T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:19811025T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:19820425T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:19821031T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:19830424T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:19831030T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:19840429T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:19841028T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:19850428T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:19851027T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:19860427T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:19861026T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:19870405T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:19871025T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:19880403T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:19881030T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:19890402T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:19891029T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:19900401T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:19901028T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:19910407T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:19911027T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:19920405T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:19921025T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:19930404T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:19931031T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:19940403T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:19941030T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:19950402T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:19951029T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:19960407T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:19961027T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:19970406T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:19971026T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:19980405T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:19981025T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:19990404T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:19991031T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:20000402T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:20001029T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:20010401T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:20011028T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:20020407T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:20021027T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:20030406T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:20031026T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:20040404T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:20041031T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:20050403T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:20051030T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:20060402T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:20061029T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:20070311T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:20071104T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:20080309T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:20081102T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:20090308T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:20091101T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:20100314T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:20101107T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:20110313T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:20111106T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:20120311T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:20121104T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:20130310T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:20131103T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:20140309T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:20141102T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:20150308T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:20151101T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:20160313T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:20161106T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:20170312T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:20171105T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:20180311T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:20181104T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:20190310T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:20191103T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:20200308T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:20201101T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:20210314T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:20211107T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:20220313T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:20221106T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:20230312T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:20231105T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:20240310T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:20241103T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:20250309T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:20251102T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:20260308T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:20261101T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:20270314T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:20271107T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:20280312T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:20281105T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:20290311T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:20291104T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:20300310T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:20301103T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:20310309T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:20311102T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:20320314T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:20321107T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:20330313T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:20331106T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:20340312T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:20341105T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:20350311T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:20351104T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:20360309T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:20361102T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:20370308T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:20371101T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +END:VTIMEZONE +BEGIN:VEVENT +UID:20140813T153116Z-12176-1000-1065-6@johnny-lubuntu +DTSTART;TZID=/freeassociation.sourceforge.net/Tzfile/America/Toronto:201408 + 15T110000 +DTEND;TZID=/freeassociation.sourceforge.net/Tzfile/America/Toronto:20140815 + T113000 +TRANSP:OPAQUE +SEQUENCE:2 +SUMMARY:Evo makes a Meeting (fruux HQ) (fruux HQ) +LOCATION:fruux HQ +CLASS:PUBLIC +ORGANIZER;SENT-BY="MAILTO:martin+johnny@fruux.com":MAILTO:martin@fruux.com +ATTENDEE;CUTYPE=INDIVIDUAL;ROLE=REQ-PARTICIPANT;PARTSTAT=ACCEPTED;RSVP=TRUE + ;SENT-BY="MAILTO:martin+johnny@fruux.com";LANGUAGE=en:MAILTO:martin@fruux. + com +ATTENDEE;CUTYPE=INDIVIDUAL;ROLE=REQ-PARTICIPANT;PARTSTAT=NEEDS-ACTION;RSVP= + TRUE;LANGUAGE=en:MAILTO:dominik@fruux.com +CREATED:20140813T153211Z +LAST-MODIFIED:20140813T155353Z +END:VEVENT +END:VCALENDAR +ICS; + + $version = \Sabre\VObject\Version::VERSION; + $expectedICS = <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +PRODID:-//Sabre//Sabre VObject $version//EN +CALSCALE:GREGORIAN +METHOD:REQUEST +BEGIN:VTIMEZONE +TZID:/freeassociation.sourceforge.net/Tzfile/America/Toronto +X-LIC-LOCATION:America/Toronto +BEGIN:STANDARD +TZNAME:EST +DTSTART:19691026T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:19700426T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:19701025T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:19710425T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:19711031T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:19720430T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:19721029T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:19730429T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:19731028T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:19740428T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:19741027T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:19750427T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:19751026T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:19760425T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:19761031T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:19770424T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:19771030T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:19780430T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:19781029T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:19790429T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:19791028T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:19800427T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:19801026T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:19810426T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:19811025T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:19820425T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:19821031T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:19830424T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:19831030T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:19840429T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:19841028T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:19850428T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:19851027T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:19860427T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:19861026T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:19870405T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:19871025T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:19880403T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:19881030T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:19890402T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:19891029T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:19900401T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:19901028T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:19910407T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:19911027T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:19920405T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:19921025T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:19930404T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:19931031T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:19940403T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:19941030T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:19950402T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:19951029T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:19960407T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:19961027T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:19970406T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:19971026T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:19980405T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:19981025T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:19990404T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:19991031T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:20000402T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:20001029T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:20010401T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:20011028T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:20020407T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:20021027T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:20030406T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:20031026T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:20040404T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:20041031T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:20050403T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:20051030T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:20060402T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:20061029T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:20070311T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:20071104T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:20080309T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:20081102T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:20090308T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:20091101T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:20100314T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:20101107T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:20110313T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:20111106T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:20120311T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:20121104T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:20130310T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:20131103T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:20140309T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:20141102T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:20150308T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:20151101T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:20160313T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:20161106T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:20170312T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:20171105T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:20180311T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:20181104T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:20190310T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:20191103T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:20200308T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:20201101T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:20210314T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:20211107T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:20220313T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:20221106T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:20230312T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:20231105T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:20240310T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:20241103T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:20250309T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:20251102T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:20260308T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:20261101T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:20270314T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:20271107T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:20280312T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:20281105T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:20290311T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:20291104T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:20300310T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:20301103T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:20310309T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:20311102T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:20320314T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:20321107T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:20330313T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:20331106T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:20340312T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:20341105T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:20350311T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:20351104T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:20360309T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:20361102T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:20370308T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:20371101T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +END:VTIMEZONE +BEGIN:VEVENT +UID:20140813T153116Z-12176-1000-1065-6@johnny-lubuntu +DTSTART;TZID=/freeassociation.sourceforge.net/Tzfile/America/Toronto:201408 + 15T110000 +DTEND;TZID=/freeassociation.sourceforge.net/Tzfile/America/Toronto:20140815 + T113000 +TRANSP:OPAQUE +SEQUENCE:2 +SUMMARY:Evo makes a Meeting (fruux HQ) (fruux HQ) +LOCATION:fruux HQ +CLASS:PUBLIC +ORGANIZER;SENT-BY="MAILTO:martin+johnny@fruux.com":MAILTO:martin@fruux.com +ATTENDEE;CUTYPE=INDIVIDUAL;ROLE=REQ-PARTICIPANT;PARTSTAT=ACCEPTED;RSVP=TRUE + ;SENT-BY="MAILTO:martin+johnny@fruux.com";LANGUAGE=en:MAILTO:martin@fruux. + com +ATTENDEE;CUTYPE=INDIVIDUAL;ROLE=REQ-PARTICIPANT;PARTSTAT=NEEDS-ACTION;RSVP= + TRUE;LANGUAGE=en:MAILTO:dominik@fruux.com +CREATED:20140813T153211Z +LAST-MODIFIED:20140813T155353Z +DTSTAMP:**ANY** +END:VEVENT +END:VCALENDAR +ICS; + + $expected = [ + [ + 'uid' => '20140813T153116Z-12176-1000-1065-6@johnny-lubuntu', + 'method' => 'REQUEST', + 'sender' => 'mailto:martin@fruux.com', + 'senderName' => null, + 'recipient' => 'mailto:dominik@fruux.com', + 'recipientName' => null, + 'message' => $expectedICS, + ], + ]; + $this->parse(null, $ics, $expected, 'mailto:martin@fruux.com'); + } + + /** + * This is an event originally from evolution, then parsed by sabredav and + * again mangled by iCal. This triggered a few bugs related to email + * address scheme casing. + */ + public function testAttendeeModify() + { + $old = <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +PRODID:-//Sabre//Sabre VObject 3.3.1//EN +CALSCALE:GREGORIAN +BEGIN:VTIMEZONE +TZID:/freeassociation.sourceforge.net/Tzfile/America/Toronto +X-LIC-LOCATION:America/Toronto +BEGIN:STANDARD +TZNAME:EST +DTSTART:19691026T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:19700426T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:19701025T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:19710425T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:19711031T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:19720430T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:19721029T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:19730429T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:19731028T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:19740428T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:19741027T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:19750427T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:19751026T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:19760425T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:19761031T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:19770424T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:19771030T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:19780430T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:19781029T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:19790429T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:19791028T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:19800427T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:19801026T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:19810426T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:19811025T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:19820425T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:19821031T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:19830424T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:19831030T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:19840429T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:19841028T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:19850428T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:19851027T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:19860427T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:19861026T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:19870405T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:19871025T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:19880403T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:19881030T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:19890402T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:19891029T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:19900401T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:19901028T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:19910407T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:19911027T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:19920405T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:19921025T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:19930404T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:19931031T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:19940403T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:19941030T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:19950402T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:19951029T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:19960407T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:19961027T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:19970406T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:19971026T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:19980405T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:19981025T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:19990404T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:19991031T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:20000402T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:20001029T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:20010401T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:20011028T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:20020407T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:20021027T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:20030406T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:20031026T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:20040404T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:20041031T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:20050403T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:20051030T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:20060402T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:20061029T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:20070311T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:20071104T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:20080309T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:20081102T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:20090308T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:20091101T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:20100314T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:20101107T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:20110313T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:20111106T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:20120311T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:20121104T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:20130310T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:20131103T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:20140309T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:20141102T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:20150308T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:20151101T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:20160313T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:20161106T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:20170312T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:20171105T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:20180311T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:20181104T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:20190310T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:20191103T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:20200308T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:20201101T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:20210314T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:20211107T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:20220313T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:20221106T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:20230312T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:20231105T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:20240310T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:20241103T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:20250309T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:20251102T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:20260308T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:20261101T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:20270314T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:20271107T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:20280312T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:20281105T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:20290311T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:20291104T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:20300310T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:20301103T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:20310309T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:20311102T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:20320314T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:20321107T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:20330313T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:20331106T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:20340312T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:20341105T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:20350311T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:20351104T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:20360309T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:20361102T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:EDT +DTSTART:20370308T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZNAME:EST +DTSTART:20371101T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +END:STANDARD +END:VTIMEZONE +BEGIN:VEVENT +UID:20140813T212317Z-6646-1000-1221-23@evert-ubuntu +DTSTAMP:20140813T212221Z +DTSTART;TZID=/freeassociation.sourceforge.net/Tzfile/America/Toronto:201408 + 13T180000 +DTEND;TZID=/freeassociation.sourceforge.net/Tzfile/America/Toronto:20140813 + T200000 +TRANSP:OPAQUE +SEQUENCE:4 +SUMMARY:Testing evolution +LOCATION:Online +CLASS:PUBLIC +ORGANIZER:MAILTO:o@example.org +CREATED:20140813T212510Z +LAST-MODIFIED:20140813T212541Z +ATTENDEE;CUTYPE=INDIVIDUAL;ROLE=REQ-PARTICIPANT;PARTSTAT=ACCEPTED;RSVP=TRUE;LANGUAGE=en:MAILTO:o@example.org +ATTENDEE;CUTYPE=INDIVIDUAL;ROLE=REQ-PARTICIPANT;PARTSTAT=NEEDS-ACTION;RSVP=TRUE;LANGUAGE=en:MAILTO:a1@example.org +ATTENDEE;CUTYPE=INDIVIDUAL;ROLE=REQ-PARTICIPANT;PARTSTAT=NEEDS-ACTION;RSVP=TRUE;LANGUAGE=en:MAILTO:a2@example.org +ATTENDEE;CUTYPE=INDIVIDUAL;ROLE=REQ-PARTICIPANT;PARTSTAT=NEEDS-ACTION;RSVP=TRUE;LANGUAGE=en:MAILTO:a3@example.org +STATUS:CANCELLED +END:VEVENT +END:VCALENDAR +ICS; + + $new = <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +PRODID:-//Apple Inc.//Mac OS X 10.9.4//EN +CALSCALE:GREGORIAN +BEGIN:VTIMEZONE +TZID:America/Toronto +BEGIN:DAYLIGHT +TZOFFSETFROM:-0500 +RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=2SU +DTSTART:20070311T020000 +TZNAME:EDT +TZOFFSETTO:-0400 +END:DAYLIGHT +BEGIN:STANDARD +TZOFFSETFROM:-0400 +RRULE:FREQ=YEARLY;BYMONTH=11;BYDAY=1SU +DTSTART:20071104T020000 +TZNAME:EST +TZOFFSETTO:-0500 +END:STANDARD +END:VTIMEZONE +BEGIN:VEVENT +TRANSP:OPAQUE +DTEND;TZID=America/Toronto:20140813T200000 +ORGANIZER:MAILTO:o@example.org +UID:20140813T212317Z-6646-1000-1221-23@evert-ubuntu +DTSTAMP:20140813T212221Z +LOCATION:Online +STATUS:CANCELLED +SEQUENCE:4 +CLASS:PUBLIC +SUMMARY:Testing evolution +LAST-MODIFIED:20140813T212541Z +DTSTART;TZID=America/Toronto:20140813T180000 +CREATED:20140813T212510Z +ATTENDEE;CUTYPE=INDIVIDUAL;LANGUAGE=en;PARTSTAT=NEEDS-ACTION;ROLE=REQ-PARTICIPANT;RSVP=TRUE:MAILTO:a2@example.org +ATTENDEE;CUTYPE=INDIVIDUAL;LANGUAGE=en;PARTSTAT=ACCEPTED;ROLE=REQ-PARTICIPANT;RSVP=TRUE:MAILTO:o@example.org +ATTENDEE;CUTYPE=INDIVIDUAL;LANGUAGE=en;PARTSTAT=NEEDS-ACTION;ROLE=REQ-PARTICIPANT;RSVP=TRUE:MAILTO:a1@example.org +ATTENDEE;CUTYPE=INDIVIDUAL;LANGUAGE=en;PARTSTAT=NEEDS-ACTION;ROLE=REQ-PARTICIPANT;RSVP=TRUE:MAILTO:a3@example.org +END:VEVENT +END:VCALENDAR +ICS; + + $this->parse($old, $new, [], 'mailto:a1@example.org'); + } +} diff --git a/vendor/sabre/vobject/tests/VObject/ITip/MessageTest.php b/vendor/sabre/vobject/tests/VObject/ITip/MessageTest.php new file mode 100644 index 000000000..56fcf8274 --- /dev/null +++ b/vendor/sabre/vobject/tests/VObject/ITip/MessageTest.php @@ -0,0 +1,30 @@ +<?php + +namespace Sabre\VObject\ITip; + +use PHPUnit\Framework\TestCase; + +class MessageTest extends TestCase +{ + public function testNoScheduleStatus() + { + $message = new Message(); + $this->assertFalse($message->getScheduleStatus()); + } + + public function testScheduleStatus() + { + $message = new Message(); + $message->scheduleStatus = '1.2;Delivered'; + + $this->assertEquals('1.2', $message->getScheduleStatus()); + } + + public function testUnexpectedScheduleStatus() + { + $message = new Message(); + $message->scheduleStatus = '9.9.9'; + + $this->assertEquals('9.9.9', $message->getScheduleStatus()); + } +} diff --git a/vendor/sabre/vobject/tests/VObject/Issue153Test.php b/vendor/sabre/vobject/tests/VObject/Issue153Test.php new file mode 100644 index 000000000..309025041 --- /dev/null +++ b/vendor/sabre/vobject/tests/VObject/Issue153Test.php @@ -0,0 +1,14 @@ +<?php + +namespace Sabre\VObject; + +use PHPUnit\Framework\TestCase; + +class Issue153Test extends TestCase +{ + public function testRead() + { + $obj = Reader::read(file_get_contents(dirname(__FILE__).'/issue153.vcf')); + $this->assertEquals('Test Benutzer', (string) $obj->FN); + } +} diff --git a/vendor/sabre/vobject/tests/VObject/Issue259Test.php b/vendor/sabre/vobject/tests/VObject/Issue259Test.php new file mode 100644 index 000000000..3227fcd56 --- /dev/null +++ b/vendor/sabre/vobject/tests/VObject/Issue259Test.php @@ -0,0 +1,23 @@ +<?php + +namespace Sabre\VObject; + +use PHPUnit\Framework\TestCase; + +class Issue259Test extends TestCase +{ + public function testParsingJcalWithUntil() + { + $jcalWithUntil = '["vcalendar",[],[["vevent",[["uid",{},"text","dd1f7d29"],["organizer",{"cn":"robert"},"cal-address","mailto:robert@robert.com"],["dtstart",{"tzid":"Europe/Berlin"},"date-time","2015-10-21T12:00:00"],["dtend",{"tzid":"Europe/Berlin"},"date-time","2015-10-21T13:00:00"],["transp",{},"text","OPAQUE"],["rrule",{},"recur",{"freq":"MONTHLY","until":"2016-01-01T22:00:00Z"}]],[]]]]'; + $parser = new Parser\Json(); + $parser->setInput($jcalWithUntil); + + $vcalendar = $parser->parse(); + $eventAsArray = $vcalendar->select('VEVENT'); + $event = reset($eventAsArray); + $rruleAsArray = $event->select('RRULE'); + $rrule = reset($rruleAsArray); + $this->assertNotNull($rrule); + $this->assertEquals($rrule->getValue(), 'FREQ=MONTHLY;UNTIL=20160101T220000Z'); + } +} diff --git a/vendor/sabre/vobject/tests/VObject/Issue36WorkAroundTest.php b/vendor/sabre/vobject/tests/VObject/Issue36WorkAroundTest.php new file mode 100644 index 000000000..332aace39 --- /dev/null +++ b/vendor/sabre/vobject/tests/VObject/Issue36WorkAroundTest.php @@ -0,0 +1,39 @@ +<?php + +namespace Sabre\VObject; + +use PHPUnit\Framework\TestCase; + +class Issue36WorkAroundTest extends TestCase +{ + public function testWorkaround() + { + // See https://github.com/fruux/sabre-vobject/issues/36 + $event = <<<ICS +BEGIN:VCALENDAR +VERSION:2.0 +BEGIN:VEVENT +SUMMARY:Titel +SEQUENCE:1 +TRANSP:TRANSPARENT +RRULE:FREQ=YEARLY +LAST-MODIFIED:20130323T225737Z +DTSTAMP:20130323T225737Z +UID:1833bd44-188b-405c-9f85-1a12105318aa +CATEGORIES:Jubiläum +X-MOZ-GENERATION:3 +RECURRENCE-ID;RANGE=THISANDFUTURE;VALUE=DATE:20131013 +DTSTART;VALUE=DATE:20131013 +CREATED:20100721T121914Z +DURATION:P1D +END:VEVENT +END:VCALENDAR +ICS; + + $obj = Reader::read($event); + + // If this does not throw an exception, it's all good. + $it = new Recur\EventIterator($obj, '1833bd44-188b-405c-9f85-1a12105318aa'); + $this->assertInstanceOf('Sabre\\VObject\\Recur\\EventIterator', $it); + } +} diff --git a/vendor/sabre/vobject/tests/VObject/Issue40Test.php b/vendor/sabre/vobject/tests/VObject/Issue40Test.php new file mode 100644 index 000000000..1cf9986e9 --- /dev/null +++ b/vendor/sabre/vobject/tests/VObject/Issue40Test.php @@ -0,0 +1,32 @@ +<?php + +namespace Sabre\VObject; + +use PHPUnit\Framework\TestCase; + +/** + * This test is created to handle the issues brought forward by issue 40. + * + * https://github.com/fruux/sabre-vobject/issues/40 + */ +class Issue40Test extends TestCase +{ + public function testEncode() + { + $card = new Component\VCard(); + $card->add('N', ['van der Harten', ['Rene', 'J.'], '', 'Sir', 'R.D.O.N.'], ['SORT-AS' => ['Harten', 'Rene']]); + + unset($card->UID); + + $expected = implode("\r\n", [ + 'BEGIN:VCARD', + 'VERSION:4.0', + 'PRODID:-//Sabre//Sabre VObject '.Version::VERSION.'//EN', + 'N;SORT-AS=Harten,Rene:van der Harten;Rene,J.;;Sir;R.D.O.N.', + 'END:VCARD', + '', + ]); + + $this->assertEquals($expected, $card->serialize()); + } +} diff --git a/vendor/sabre/vobject/tests/VObject/Issue64Test.php b/vendor/sabre/vobject/tests/VObject/Issue64Test.php new file mode 100644 index 000000000..9dc2bb984 --- /dev/null +++ b/vendor/sabre/vobject/tests/VObject/Issue64Test.php @@ -0,0 +1,19 @@ +<?php + +namespace Sabre\VObject; + +use PHPUnit\Framework\TestCase; + +class Issue64Test extends TestCase +{ + public function testRead() + { + $vcard = Reader::read(file_get_contents(dirname(__FILE__).'/issue64.vcf')); + $vcard = $vcard->convert(\Sabre\VObject\Document::VCARD30); + $vcard = $vcard->serialize(); + + $converted = Reader::read($vcard); + + $this->assertInstanceOf('Sabre\\VObject\\Component\\VCard', $converted); + } +} diff --git a/vendor/sabre/vobject/tests/VObject/Issue96Test.php b/vendor/sabre/vobject/tests/VObject/Issue96Test.php new file mode 100644 index 000000000..22d1fed2f --- /dev/null +++ b/vendor/sabre/vobject/tests/VObject/Issue96Test.php @@ -0,0 +1,24 @@ +<?php + +namespace Sabre\VObject; + +use PHPUnit\Framework\TestCase; + +class Issue96Test extends TestCase +{ + public function testRead() + { + $input = <<<VCF +BEGIN:VCARD +VERSION:2.1 +SOURCE:Yahoo Contacts (http://contacts.yahoo.com) +URL;CHARSET=utf-8;ENCODING=QUOTED-PRINTABLE:= +http://www.example.org +END:VCARD +VCF; + + $vcard = Reader::read($input, Reader::OPTION_FORGIVING); + $this->assertInstanceOf('Sabre\\VObject\\Component\\VCard', $vcard); + $this->assertEquals('http://www.example.org', $vcard->URL->getValue()); + } +} diff --git a/vendor/sabre/vobject/tests/VObject/IssueUndefinedIndexTest.php b/vendor/sabre/vobject/tests/VObject/IssueUndefinedIndexTest.php new file mode 100644 index 000000000..5a70b0885 --- /dev/null +++ b/vendor/sabre/vobject/tests/VObject/IssueUndefinedIndexTest.php @@ -0,0 +1,29 @@ +<?php + +namespace Sabre\VObject; + +use PHPUnit\Framework\TestCase; + +class IssueUndefinedIndexTest extends TestCase +{ + /** + * @expectedException \Sabre\VObject\ParseException + */ + public function testRead() + { + $input = <<<VCF +BEGIN:VCARD +VERSION:3.0 +PRODID:foo +N:Holmes;Sherlock;;; +FN:Sherlock Holmes +ORG:Acme Inc; +ADR;type=WORK;type=pref:;;, +\\n221B,Baker Street;London;;12345;United Kingdom +UID:foo +END:VCARD +VCF; + + $vcard = Reader::read($input, Reader::OPTION_FORGIVING); + } +} diff --git a/vendor/sabre/vobject/tests/VObject/JCalTest.php b/vendor/sabre/vobject/tests/VObject/JCalTest.php new file mode 100644 index 000000000..9332b6413 --- /dev/null +++ b/vendor/sabre/vobject/tests/VObject/JCalTest.php @@ -0,0 +1,149 @@ +<?php + +namespace Sabre\VObject; + +use PHPUnit\Framework\TestCase; + +class JCalTest extends TestCase +{ + public function testToJCal() + { + $cal = new Component\VCalendar(); + + $event = $cal->add('VEVENT', [ + 'UID' => 'foo', + 'DTSTART' => new \DateTime('2013-05-26 18:10:00Z'), + 'DURATION' => 'P1D', + 'CATEGORIES' => ['home', 'testing'], + 'CREATED' => new \DateTime('2013-05-26 18:10:00Z'), + + 'ATTENDEE' => 'mailto:armin@example.org', + 'GEO' => [51.96668, 7.61876], + 'SEQUENCE' => 5, + 'FREEBUSY' => ['20130526T210213Z/PT1H', '20130626T120000Z/20130626T130000Z'], + 'URL' => 'http://example.org/', + 'TZOFFSETFROM' => '+0500', + 'RRULE' => ['FREQ' => 'WEEKLY', 'BYDAY' => ['MO', 'TU']], + ], false); + + // Modifying DTSTART to be a date-only. + $event->dtstart['VALUE'] = 'DATE'; + $event->add('X-BOOL', true, ['VALUE' => 'BOOLEAN']); + $event->add('X-TIME', '08:00:00', ['VALUE' => 'TIME']); + $event->add('ATTACH', 'attachment', ['VALUE' => 'BINARY']); + $event->add('ATTENDEE', 'mailto:dominik@example.org', ['CN' => 'Dominik', 'PARTSTAT' => 'DECLINED']); + + $event->add('REQUEST-STATUS', ['2.0', 'Success']); + $event->add('REQUEST-STATUS', ['3.7', 'Invalid Calendar User', 'ATTENDEE:mailto:jsmith@example.org']); + + $event->add('DTEND', '20150108T133000'); + + $expected = [ + 'vcalendar', + [ + [ + 'version', + new \stdClass(), + 'text', + '2.0', + ], + [ + 'prodid', + new \stdClass(), + 'text', + '-//Sabre//Sabre VObject '.Version::VERSION.'//EN', + ], + [ + 'calscale', + new \stdClass(), + 'text', + 'GREGORIAN', + ], + ], + [ + ['vevent', + [ + [ + 'uid', new \stdClass(), 'text', 'foo', + ], + [ + 'dtstart', new \stdClass(), 'date', '2013-05-26', + ], + [ + 'duration', new \stdClass(), 'duration', 'P1D', + ], + [ + 'categories', new \stdClass(), 'text', 'home', 'testing', + ], + [ + 'created', new \stdClass(), 'date-time', '2013-05-26T18:10:00Z', + ], + [ + 'attendee', new \stdClass(), 'cal-address', 'mailto:armin@example.org', + ], + [ + 'attendee', + (object) [ + 'cn' => 'Dominik', + 'partstat' => 'DECLINED', + ], + 'cal-address', + 'mailto:dominik@example.org', + ], + [ + 'geo', new \stdClass(), 'float', [51.96668, 7.61876], + ], + [ + 'sequence', new \stdClass(), 'integer', 5, + ], + [ + 'freebusy', new \stdClass(), 'period', ['2013-05-26T21:02:13', 'PT1H'], ['2013-06-26T12:00:00', '2013-06-26T13:00:00'], + ], + [ + 'url', new \stdClass(), 'uri', 'http://example.org/', + ], + [ + 'tzoffsetfrom', new \stdClass(), 'utc-offset', '+05:00', + ], + [ + 'rrule', new \stdClass(), 'recur', [ + 'freq' => 'WEEKLY', + 'byday' => ['MO', 'TU'], + ], + ], + [ + 'x-bool', new \stdClass(), 'boolean', true, + ], + [ + 'x-time', new \stdClass(), 'time', '08:00:00', + ], + [ + 'attach', new \stdClass(), 'binary', base64_encode('attachment'), + ], + [ + 'request-status', + new \stdClass(), + 'text', + ['2.0', 'Success'], + ], + [ + 'request-status', + new \stdClass(), + 'text', + ['3.7', 'Invalid Calendar User', 'ATTENDEE:mailto:jsmith@example.org'], + ], + [ + 'dtend', + new \stdClass(), + 'date-time', + '2015-01-08T13:30:00', + ], + ], + [], + ], + ], + ]; + + $this->assertEquals($expected, $cal->jsonSerialize()); + } +} diff --git a/vendor/sabre/vobject/tests/VObject/JCardTest.php b/vendor/sabre/vobject/tests/VObject/JCardTest.php new file mode 100644 index 000000000..1864f666d --- /dev/null +++ b/vendor/sabre/vobject/tests/VObject/JCardTest.php @@ -0,0 +1,194 @@ +<?php + +namespace Sabre\VObject; + +use PHPUnit\Framework\TestCase; + +class JCardTest extends TestCase +{ + public function testToJCard() + { + $card = new Component\VCard([ + 'VERSION' => '4.0', + 'UID' => 'foo', + 'BDAY' => '19850407', + 'REV' => '19951031T222710Z', + 'LANG' => 'nl', + 'N' => ['Last', 'First', 'Middle', '', ''], + 'item1.TEL' => '+1 555 123456', + 'item1.X-AB-LABEL' => 'Walkie Talkie', + 'ADR' => [ + '', + '', + ['My Street', 'Left Side', 'Second Shack'], + 'Hometown', + 'PA', + '18252', + 'U.S.A', + ], + ]); + + $card->add('BDAY', '1979-12-25', ['VALUE' => 'DATE', 'X-PARAM' => [1, 2]]); + $card->add('BDAY', '1979-12-25T02:00:00', ['VALUE' => 'DATE-TIME']); + + $card->add('X-TRUNCATED', '--1225', ['VALUE' => 'DATE']); + $card->add('X-TIME-LOCAL', '123000', ['VALUE' => 'TIME']); + $card->add('X-TIME-UTC', '12:30:00Z', ['VALUE' => 'TIME']); + $card->add('X-TIME-OFFSET', '12:30:00-08:00', ['VALUE' => 'TIME']); + $card->add('X-TIME-REDUCED', '23', ['VALUE' => 'TIME']); + $card->add('X-TIME-TRUNCATED', '--30', ['VALUE' => 'TIME']); + + $card->add('X-KARMA-POINTS', '42', ['VALUE' => 'INTEGER']); + $card->add('X-GRADE', '1.3', ['VALUE' => 'FLOAT']); + + $card->add('TZ', '-0500', ['VALUE' => 'UTC-OFFSET']); + + $expected = [ + 'vcard', + [ + [ + 'version', + new \stdClass(), + 'text', + '4.0', + ], + [ + 'prodid', + new \stdClass(), + 'text', + '-//Sabre//Sabre VObject '.Version::VERSION.'//EN', + ], + [ + 'uid', + new \stdClass(), + 'text', + 'foo', + ], + [ + 'bday', + new \stdClass(), + 'date-and-or-time', + '1985-04-07', + ], + [ + 'bday', + (object) [ + 'x-param' => [1, 2], + ], + 'date', + '1979-12-25', + ], + [ + 'bday', + new \stdClass(), + 'date-time', + '1979-12-25T02:00:00', + ], + [ + 'rev', + new \stdClass(), + 'timestamp', + '1995-10-31T22:27:10Z', + ], + [ + 'lang', + new \stdClass(), + 'language-tag', + 'nl', + ], + [ + 'n', + new \stdClass(), + 'text', + ['Last', 'First', 'Middle', '', ''], + ], + [ + 'tel', + (object) [ + 'group' => 'item1', + ], + 'text', + '+1 555 123456', + ], + [ + 'x-ab-label', + (object) [ + 'group' => 'item1', + ], + 'unknown', + 'Walkie Talkie', + ], + [ + 'adr', + new \stdClass(), + 'text', + [ + '', + '', + ['My Street', 'Left Side', 'Second Shack'], + 'Hometown', + 'PA', + '18252', + 'U.S.A', + ], + ], + [ + 'x-truncated', + new \stdClass(), + 'date', + '--12-25', + ], + [ + 'x-time-local', + new \stdClass(), + 'time', + '12:30:00', + ], + [ + 'x-time-utc', + new \stdClass(), + 'time', + '12:30:00Z', + ], + [ + 'x-time-offset', + new \stdClass(), + 'time', + '12:30:00-08:00', + ], + [ + 'x-time-reduced', + new \stdClass(), + 'time', + '23', + ], + [ + 'x-time-truncated', + new \stdClass(), + 'time', + '--30', + ], + [ + 'x-karma-points', + new \stdClass(), + 'integer', + 42, + ], + [ + 'x-grade', + new \stdClass(), + 'float', + 1.3, + ], + [ + 'tz', + new \stdClass(), + 'utc-offset', + '-05:00', + ], + ], + ]; + + $this->assertEquals($expected, $card->jsonSerialize()); + } +} diff --git a/vendor/sabre/vobject/tests/VObject/LineFoldingIssueTest.php b/vendor/sabre/vobject/tests/VObject/LineFoldingIssueTest.php new file mode 100644 index 000000000..3d4f26af5 --- /dev/null +++ b/vendor/sabre/vobject/tests/VObject/LineFoldingIssueTest.php @@ -0,0 +1,23 @@ +<?php + +namespace Sabre\VObject; + +use PHPUnit\Framework\TestCase; + +class LineFoldingIssueTest extends TestCase +{ + public function testRead() + { + $event = <<<ICS +BEGIN:VCALENDAR\r +BEGIN:VEVENT\r +DESCRIPTION:TEST\\n\\n \\n\\nTEST\\n\\n \\n\\nTEST\\n\\n \\n\\nTEST\\n\\nTEST\\nTEST, TEST\r +END:VEVENT\r +END:VCALENDAR\r + +ICS; + + $obj = Reader::read($event); + $this->assertEquals($event, $obj->serialize()); + } +} diff --git a/vendor/sabre/vobject/tests/VObject/ParameterTest.php b/vendor/sabre/vobject/tests/VObject/ParameterTest.php new file mode 100644 index 000000000..0e23b0620 --- /dev/null +++ b/vendor/sabre/vobject/tests/VObject/ParameterTest.php @@ -0,0 +1,124 @@ +<?php + +namespace Sabre\VObject; + +use PHPUnit\Framework\TestCase; + +class ParameterTest extends TestCase +{ + public function testSetup() + { + $cal = new Component\VCalendar(); + + $param = new Parameter($cal, 'name', 'value'); + $this->assertEquals('NAME', $param->name); + $this->assertEquals('value', $param->getValue()); + } + + public function testSetupNameLess() + { + $card = new Component\VCard(); + + $param = new Parameter($card, null, 'URL'); + $this->assertEquals('VALUE', $param->name); + $this->assertEquals('URL', $param->getValue()); + $this->assertTrue($param->noName); + } + + public function testModify() + { + $cal = new Component\VCalendar(); + + $param = new Parameter($cal, 'name', null); + $param->addValue(1); + $this->assertEquals([1], $param->getParts()); + + $param->setParts([1, 2]); + $this->assertEquals([1, 2], $param->getParts()); + + $param->addValue(3); + $this->assertEquals([1, 2, 3], $param->getParts()); + + $param->setValue(4); + $param->addValue(5); + $this->assertEquals([4, 5], $param->getParts()); + } + + public function testCastToString() + { + $cal = new Component\VCalendar(); + $param = new Parameter($cal, 'name', 'value'); + $this->assertEquals('value', $param->__toString()); + $this->assertEquals('value', (string) $param); + } + + public function testCastNullToString() + { + $cal = new Component\VCalendar(); + $param = new Parameter($cal, 'name', null); + $this->assertEquals('', $param->__toString()); + $this->assertEquals('', (string) $param); + } + + public function testSerialize() + { + $cal = new Component\VCalendar(); + $param = new Parameter($cal, 'name', 'value'); + $this->assertEquals('NAME=value', $param->serialize()); + } + + public function testSerializeEmpty() + { + $cal = new Component\VCalendar(); + $param = new Parameter($cal, 'name', null); + $this->assertEquals('NAME=', $param->serialize()); + } + + public function testSerializeComplex() + { + $cal = new Component\VCalendar(); + $param = new Parameter($cal, 'name', ['val1', 'val2;', 'val3^', "val4\n", 'val5"']); + $this->assertEquals('NAME=val1,"val2;","val3^^","val4^n","val5^\'"', $param->serialize()); + } + + /** + * iCal 7.0 (OSX 10.9) has major issues with the EMAIL property, when the + * value contains a plus sign, and it's not quoted. + * + * So we specifically added support for that. + */ + public function testSerializePlusSign() + { + $cal = new Component\VCalendar(); + $param = new Parameter($cal, 'EMAIL', 'user+something@example.org'); + $this->assertEquals('EMAIL="user+something@example.org"', $param->serialize()); + } + + public function testIterate() + { + $cal = new Component\VCalendar(); + + $param = new Parameter($cal, 'name', [1, 2, 3, 4]); + $result = []; + + foreach ($param as $value) { + $result[] = $value; + } + + $this->assertEquals([1, 2, 3, 4], $result); + } + + public function testSerializeColon() + { + $cal = new Component\VCalendar(); + $param = new Parameter($cal, 'name', 'va:lue'); + $this->assertEquals('NAME="va:lue"', $param->serialize()); + } + + public function testSerializeSemiColon() + { + $cal = new Component\VCalendar(); + $param = new Parameter($cal, 'name', 'va;lue'); + $this->assertEquals('NAME="va;lue"', $param->serialize()); + } +} diff --git a/vendor/sabre/vobject/tests/VObject/Parser/JsonTest.php b/vendor/sabre/vobject/tests/VObject/Parser/JsonTest.php new file mode 100644 index 000000000..2aa0d9dab --- /dev/null +++ b/vendor/sabre/vobject/tests/VObject/Parser/JsonTest.php @@ -0,0 +1,391 @@ +<?php + +namespace Sabre\VObject\Parser; + +use PHPUnit\Framework\TestCase; +use Sabre\VObject; + +class JsonTest extends TestCase +{ + public function testRoundTripJCard() + { + $input = [ + 'vcard', + [ + [ + 'version', + new \stdClass(), + 'text', + '4.0', + ], + [ + 'prodid', + new \stdClass(), + 'text', + '-//Sabre//Sabre VObject '.VObject\Version::VERSION.'//EN', + ], + [ + 'uid', + new \stdClass(), + 'text', + 'foo', + ], + [ + 'bday', + new \stdClass(), + 'date-and-or-time', + '1985-04-07', + ], + [ + 'bday', + (object) [ + 'x-param' => [1, 2], + ], + 'date', + '1979-12-25', + ], + [ + 'bday', + new \stdClass(), + 'date-time', + '1979-12-25T02:00:00', + ], + [ + 'rev', + new \stdClass(), + 'timestamp', + '1995-10-31T22:27:10Z', + ], + [ + 'lang', + new \stdClass(), + 'language-tag', + 'nl', + ], + [ + 'n', + new \stdClass(), + 'text', + ['Last', 'First', 'Middle', '', ''], + ], + [ + 'tel', + (object) [ + 'group' => 'item1', + ], + 'text', + '+1 555 123456', + ], + [ + 'x-ab-label', + (object) [ + 'group' => 'item1', + ], + 'unknown', + 'Walkie Talkie', + ], + [ + 'adr', + new \stdClass(), + 'text', + [ + '', + '', + ['My Street', 'Left Side', 'Second Shack'], + 'Hometown', + 'PA', + '18252', + 'U.S.A', + ], + ], + + [ + 'x-truncated', + new \stdClass(), + 'date', + '--12-25', + ], + [ + 'x-time-local', + new \stdClass(), + 'time', + '12:30:00', + ], + [ + 'x-time-utc', + new \stdClass(), + 'time', + '12:30:00Z', + ], + [ + 'x-time-offset', + new \stdClass(), + 'time', + '12:30:00-08:00', + ], + [ + 'x-time-reduced', + new \stdClass(), + 'time', + '23', + ], + [ + 'x-time-truncated', + new \stdClass(), + 'time', + '--30', + ], + [ + 'x-karma-points', + new \stdClass(), + 'integer', + 42, + ], + [ + 'x-grade', + new \stdClass(), + 'float', + 1.3, + ], + [ + 'tz', + new \stdClass(), + 'utc-offset', + '-05:00', + ], + ], + ]; + + $parser = new Json(json_encode($input)); + $vobj = $parser->parse(); + + $version = VObject\Version::VERSION; + + $result = $vobj->serialize(); + $expected = <<<VCF +BEGIN:VCARD +VERSION:4.0 +PRODID:-//Sabre//Sabre VObject $version//EN +UID:foo +BDAY:1985-04-07 +BDAY;X-PARAM=1,2;VALUE=DATE:1979-12-25 +BDAY;VALUE=DATE-TIME:1979-12-25T02:00:00 +REV:1995-10-31T22:27:10Z +LANG:nl +N:Last;First;Middle;; +item1.TEL:+1 555 123456 +item1.X-AB-LABEL:Walkie Talkie +ADR:;;My Street,Left Side,Second Shack;Hometown;PA;18252;U.S.A +X-TRUNCATED;VALUE=DATE:--12-25 +X-TIME-LOCAL;VALUE=TIME:123000 +X-TIME-UTC;VALUE=TIME:123000Z +X-TIME-OFFSET;VALUE=TIME:123000-0800 +X-TIME-REDUCED;VALUE=TIME:23 +X-TIME-TRUNCATED;VALUE=TIME:--30 +X-KARMA-POINTS;VALUE=INTEGER:42 +X-GRADE;VALUE=FLOAT:1.3 +TZ;VALUE=UTC-OFFSET:-0500 +END:VCARD + +VCF; + $this->assertEquals($expected, str_replace("\r", '', $result)); + + $this->assertEquals( + $input, + $vobj->jsonSerialize() + ); + } + + public function testRoundTripJCal() + { + $input = [ + 'vcalendar', + [ + [ + 'version', + new \stdClass(), + 'text', + '2.0', + ], + [ + 'prodid', + new \stdClass(), + 'text', + '-//Sabre//Sabre VObject '.VObject\Version::VERSION.'//EN', + ], + [ + 'calscale', + new \stdClass(), + 'text', + 'GREGORIAN', + ], + ], + [ + ['vevent', + [ + [ + 'uid', new \stdClass(), 'text', 'foo', + ], + [ + 'dtstart', new \stdClass(), 'date', '2013-05-26', + ], + [ + 'duration', new \stdClass(), 'duration', 'P1D', + ], + [ + 'categories', new \stdClass(), 'text', 'home', 'testing', + ], + [ + 'created', new \stdClass(), 'date-time', '2013-05-26T18:10:00Z', + ], + [ + 'attach', new \stdClass(), 'binary', base64_encode('attachment'), + ], + [ + 'attendee', new \stdClass(), 'cal-address', 'mailto:armin@example.org', + ], + [ + 'attendee', + (object) [ + 'cn' => 'Dominik', + 'partstat' => 'DECLINED', + ], + 'cal-address', + 'mailto:dominik@example.org', + ], + [ + 'geo', new \stdClass(), 'float', [51.96668, 7.61876], + ], + [ + 'sequence', new \stdClass(), 'integer', 5, + ], + [ + 'freebusy', new \stdClass(), 'period', ['2013-05-26T21:02:13', 'PT1H'], ['2013-06-26T12:00:00', '2013-06-26T13:00:00'], + ], + [ + 'url', new \stdClass(), 'uri', 'http://example.org/', + ], + [ + 'tzoffsetfrom', new \stdClass(), 'utc-offset', '+05:00', + ], + [ + 'rrule', new \stdClass(), 'recur', [ + 'freq' => 'WEEKLY', + 'byday' => ['MO', 'TU'], + ], + ], + [ + 'x-bool', new \stdClass(), 'boolean', true, + ], + [ + 'x-time', new \stdClass(), 'time', '08:00:00', + ], + [ + 'request-status', + new \stdClass(), + 'text', + ['2.0', 'Success'], + ], + [ + 'request-status', + new \stdClass(), + 'text', + ['3.7', 'Invalid Calendar User', 'ATTENDEE:mailto:jsmith@example.org'], + ], + ], + [ + ['valarm', + [ + [ + 'action', new \stdClass(), 'text', 'DISPLAY', + ], + ], + [], + ], + ], + ], + ], + ]; + + $parser = new Json(json_encode($input)); + $vobj = $parser->parse(); + $result = $vobj->serialize(); + + $version = VObject\Version::VERSION; + + $expected = <<<VCF +BEGIN:VCALENDAR +VERSION:2.0 +PRODID:-//Sabre//Sabre VObject $version//EN +CALSCALE:GREGORIAN +BEGIN:VEVENT +UID:foo +DTSTART;VALUE=DATE:20130526 +DURATION:P1D +CATEGORIES:home,testing +CREATED:20130526T181000Z +ATTACH;VALUE=BINARY:YXR0YWNobWVudA== +ATTENDEE:mailto:armin@example.org +ATTENDEE;CN=Dominik;PARTSTAT=DECLINED:mailto:dominik@example.org +GEO:51.96668;7.61876 +SEQUENCE:5 +FREEBUSY:20130526T210213/PT1H,20130626T120000/20130626T130000 +URL;VALUE=URI:http://example.org/ +TZOFFSETFROM:+0500 +RRULE:FREQ=WEEKLY;BYDAY=MO,TU +X-BOOL;VALUE=BOOLEAN:TRUE +X-TIME;VALUE=TIME:080000 +REQUEST-STATUS:2.0;Success +REQUEST-STATUS:3.7;Invalid Calendar User;ATTENDEE:mailto:jsmith@example.org +BEGIN:VALARM +ACTION:DISPLAY +END:VALARM +END:VEVENT +END:VCALENDAR + +VCF; + $this->assertEquals($expected, str_replace("\r", '', $result)); + + $this->assertEquals( + $input, + $vobj->jsonSerialize() + ); + } + + public function testParseStreamArg() + { + $input = [ + 'vcard', + [ + [ + 'FN', new \stdClass(), 'text', 'foo', + ], + ], + ]; + + $stream = fopen('php://memory', 'r+'); + fwrite($stream, json_encode($input)); + rewind($stream); + + $result = VObject\Reader::readJson($stream, 0); + $this->assertEquals('foo', $result->FN->getValue()); + } + + /** + * @expectedException \Sabre\VObject\ParseException + */ + public function testParseInvalidData() + { + $json = new Json(); + $input = [ + 'vlist', + [ + [ + 'FN', new \stdClass(), 'text', 'foo', + ], + ], + ]; + + $json->parse(json_encode($input), 0); + } +} diff --git a/vendor/sabre/vobject/tests/VObject/Parser/MimeDirTest.php b/vendor/sabre/vobject/tests/VObject/Parser/MimeDirTest.php new file mode 100644 index 000000000..309068854 --- /dev/null +++ b/vendor/sabre/vobject/tests/VObject/Parser/MimeDirTest.php @@ -0,0 +1,153 @@ +<?php + +namespace Sabre\VObject\Parser; + +use PHPUnit\Framework\TestCase; + +/** + * Note that most MimeDir related tests can actually be found in the ReaderTest + * class one level up. + */ +class MimeDirTest extends TestCase +{ + /** + * @expectedException \Sabre\VObject\ParseException + */ + public function testParseError() + { + $mimeDir = new MimeDir(); + $mimeDir->parse(fopen(__FILE__, 'a+')); + } + + public function testDecodeLatin1() + { + $vcard = <<<VCF +BEGIN:VCARD +VERSION:3.0 +FN:umlaut u - \xFC +END:VCARD\n +VCF; + + $mimeDir = new MimeDir(); + $mimeDir->setCharset('ISO-8859-1'); + $vcard = $mimeDir->parse($vcard); + $this->assertEquals("umlaut u - \xC3\xBC", $vcard->FN->getValue()); + } + + public function testDecodeInlineLatin1() + { + $vcard = <<<VCF +BEGIN:VCARD +VERSION:2.1 +FN;CHARSET=ISO-8859-1:umlaut u - \xFC +END:VCARD\n +VCF; + + $mimeDir = new MimeDir(); + $vcard = $mimeDir->parse($vcard); + $this->assertEquals("umlaut u - \xC3\xBC", $vcard->FN->getValue()); + } + + public function testIgnoreCharsetVCard30() + { + $vcard = <<<VCF +BEGIN:VCARD +VERSION:3.0 +FN;CHARSET=unknown:foo-bar - \xFC +END:VCARD\n +VCF; + + $mimeDir = new MimeDir(); + $vcard = $mimeDir->parse($vcard); + $this->assertEquals("foo-bar - \xFC", $vcard->FN->getValue()); + } + + public function testDontDecodeLatin1() + { + $vcard = <<<VCF +BEGIN:VCARD +VERSION:4.0 +FN:umlaut u - \xFC +END:VCARD\n +VCF; + + $mimeDir = new MimeDir(); + $vcard = $mimeDir->parse($vcard); + // This basically tests that we don't touch the input string if + // the encoding was set to UTF-8. The result is actually invalid + // and the validator should report this, but it tests effectively + // that we pass through the string byte-by-byte. + $this->assertEquals("umlaut u - \xFC", $vcard->FN->getValue()); + } + + /** + * @expectedException \InvalidArgumentException + */ + public function testDecodeUnsupportedCharset() + { + $mimeDir = new MimeDir(); + $mimeDir->setCharset('foobar'); + } + + /** + * @expectedException \Sabre\VObject\ParseException + */ + public function testDecodeUnsupportedInlineCharset() + { + $vcard = <<<VCF +BEGIN:VCARD +VERSION:2.1 +FN;CHARSET=foobar:nothing +END:VCARD\n +VCF; + + $mimeDir = new MimeDir(); + $mimeDir->parse($vcard); + } + + public function testDecodeWindows1252() + { + $vcard = <<<VCF +BEGIN:VCARD +VERSION:3.0 +FN:Euro \x80 +END:VCARD\n +VCF; + + $mimeDir = new MimeDir(); + $mimeDir->setCharset('Windows-1252'); + $vcard = $mimeDir->parse($vcard); + $this->assertEquals("Euro \xE2\x82\xAC", $vcard->FN->getValue()); + } + + public function testDecodeWindows1252Inline() + { + $vcard = <<<VCF +BEGIN:VCARD +VERSION:2.1 +FN;CHARSET=Windows-1252:Euro \x80 +END:VCARD\n +VCF; + + $mimeDir = new MimeDir(); + $vcard = $mimeDir->parse($vcard); + $this->assertEquals("Euro \xE2\x82\xAC", $vcard->FN->getValue()); + } + + public function testCaseInsensitiveInlineCharset() + { + $vcard = <<<VCF +BEGIN:VCARD +VERSION:2.1 +FN;CHARSET=iSo-8859-1:Euro +N;CHARSET=utf-8:Test2 +END:VCARD\n +VCF; + + $mimeDir = new MimeDir(); + $vcard = $mimeDir->parse($vcard); + // we can do a simple assertion here. As long as we don't get an exception, everything is thing + $this->assertEquals('Euro', $vcard->FN->getValue()); + $this->assertEquals('Test2', $vcard->N->getValue()); + } +} diff --git a/vendor/sabre/vobject/tests/VObject/Parser/QuotedPrintableTest.php b/vendor/sabre/vobject/tests/VObject/Parser/QuotedPrintableTest.php new file mode 100644 index 000000000..7ec16a5a5 --- /dev/null +++ b/vendor/sabre/vobject/tests/VObject/Parser/QuotedPrintableTest.php @@ -0,0 +1,101 @@ +<?php + +namespace Sabre\VObject\Parser; + +use PHPUnit\Framework\TestCase; +use Sabre\VObject\Reader; + +class QuotedPrintableTest extends TestCase +{ + public function testReadQuotedPrintableSimple() + { + $data = "BEGIN:VCARD\r\nLABEL;ENCODING=QUOTED-PRINTABLE:Aach=65n\r\nEND:VCARD"; + + $result = Reader::read($data); + + $this->assertInstanceOf('Sabre\\VObject\\Component', $result); + $this->assertEquals('VCARD', $result->name); + $this->assertEquals(1, count($result->children())); + $this->assertEquals('Aachen', $this->getPropertyValue($result->LABEL)); + } + + public function testReadQuotedPrintableNewlineSoft() + { + $data = "BEGIN:VCARD\r\nLABEL;ENCODING=QUOTED-PRINTABLE:Aa=\r\n ch=\r\n en\r\nEND:VCARD"; + $result = Reader::read($data); + + $this->assertInstanceOf('Sabre\\VObject\\Component', $result); + $this->assertEquals('VCARD', $result->name); + $this->assertEquals(1, count($result->children())); + $this->assertEquals('Aachen', $this->getPropertyValue($result->LABEL)); + } + + public function testReadQuotedPrintableNewlineHard() + { + $data = "BEGIN:VCARD\r\nLABEL;ENCODING=QUOTED-PRINTABLE:Aachen=0D=0A=\r\n Germany\r\nEND:VCARD"; + $result = Reader::read($data); + + $this->assertInstanceOf('Sabre\\VObject\\Component', $result); + $this->assertEquals('VCARD', $result->name); + $this->assertEquals(1, count($result->children())); + $this->assertEquals("Aachen\r\nGermany", $this->getPropertyValue($result->LABEL)); + } + + public function testReadQuotedPrintableCompatibilityMS() + { + $data = "BEGIN:VCARD\r\nLABEL;ENCODING=QUOTED-PRINTABLE:Aachen=0D=0A=\r\nDeutschland:okay\r\nEND:VCARD"; + $result = Reader::read($data, Reader::OPTION_FORGIVING); + + $this->assertInstanceOf('Sabre\\VObject\\Component', $result); + $this->assertEquals('VCARD', $result->name); + $this->assertEquals(1, count($result->children())); + $this->assertEquals("Aachen\r\nDeutschland:okay", $this->getPropertyValue($result->LABEL)); + } + + public function testReadQuotesPrintableCompoundValues() + { + $data = <<<VCF +BEGIN:VCARD +VERSION:2.1 +N:Doe;John;;; +FN:John Doe +ADR;WORK;CHARSET=UTF-8;ENCODING=QUOTED-PRINTABLE:;;M=C3=BCnster = +Str. 1;M=C3=BCnster;;48143;Deutschland +END:VCARD +VCF; + + $result = Reader::read($data, Reader::OPTION_FORGIVING); + $this->assertEquals([ + '', '', 'Münster Str. 1', 'Münster', '', '48143', 'Deutschland', + ], $result->ADR->getParts()); + } + + private function getPropertyValue(\Sabre\VObject\Property $property) + { + return (string) $property; + + /* + $param = $property['encoding']; + if ($param !== null) { + $encoding = strtoupper((string)$param); + if ($encoding === 'QUOTED-PRINTABLE') { + $value = quoted_printable_decode($value); + } else { + throw new Exception(); + } + } + + $param = $property['charset']; + if ($param !== null) { + $charset = strtoupper((string)$param); + if ($charset !== 'UTF-8') { + $value = mb_convert_encoding($value, 'UTF-8', $charset); + } + } else { + $value = StringUtil::convertToUTF8($value); + } + + return $value; + */ + } +} diff --git a/vendor/sabre/vobject/tests/VObject/Parser/XmlTest.php b/vendor/sabre/vobject/tests/VObject/Parser/XmlTest.php new file mode 100644 index 000000000..e520185ba --- /dev/null +++ b/vendor/sabre/vobject/tests/VObject/Parser/XmlTest.php @@ -0,0 +1,2808 @@ +<?php + +namespace Sabre\VObject\Parser; + +use PHPUnit\Framework\TestCase; +use Sabre\VObject; + +class XmlTest extends TestCase +{ + use VObject\PHPUnitAssertions; + + public function testRFC6321Example1() + { + $this->assertXMLEqualsToMimeDir( +<<<XML +<?xml version="1.0" encoding="UTF-8"?> +<icalendar xmlns="urn:ietf:params:xml:ns:icalendar-2.0"> + <vcalendar> + <properties> + <calscale> + <text>GREGORIAN</text> + </calscale> + <prodid> + <text>-//Example Inc.//Example Calendar//EN</text> + </prodid> + <version> + <text>2.0</text> + </version> + </properties> + <components> + <vevent> + <properties> + <dtstamp> + <date-time>2008-02-05T19:12:24Z</date-time> + </dtstamp> + <dtstart> + <date>2008-10-06</date> + </dtstart> + <summary> + <text>Planning meeting</text> + </summary> + <uid> + <text>4088E990AD89CB3DBB484909</text> + </uid> + </properties> + </vevent> + </components> + </vcalendar> +</icalendar> +XML +, + 'BEGIN:VCALENDAR'."\n". + // VERSION comes first because this is required by vCard 4.0. + 'VERSION:2.0'."\n". + 'CALSCALE:GREGORIAN'."\n". + 'PRODID:-//Example Inc.//Example Calendar//EN'."\n". + 'BEGIN:VEVENT'."\n". + 'DTSTAMP:20080205T191224Z'."\n". + 'DTSTART;VALUE=DATE:20081006'."\n". + 'SUMMARY:Planning meeting'."\n". + 'UID:4088E990AD89CB3DBB484909'."\n". + 'END:VEVENT'."\n". + 'END:VCALENDAR'."\n" + ); + } + + public function testRFC6321Example2() + { + $xml = <<<XML +<?xml version="1.0" encoding="UTF-8" ?> +<icalendar xmlns="urn:ietf:params:xml:ns:icalendar-2.0"> + <vcalendar> + <properties> + <prodid> + <text>-//Example Inc.//Example Client//EN</text> + </prodid> + <version> + <text>2.0</text> + </version> + </properties> + <components> + <vtimezone> + <properties> + <last-modified> + <date-time>2004-01-10T03:28:45Z</date-time> + </last-modified> + <tzid><text>US/Eastern</text></tzid> + </properties> + <components> + <daylight> + <properties> + <dtstart> + <date-time>2000-04-04T02:00:00</date-time> + </dtstart> + <rrule> + <recur> + <freq>YEARLY</freq> + <byday>1SU</byday> + <bymonth>4</bymonth> + </recur> + </rrule> + <tzname> + <text>EDT</text> + </tzname> + <tzoffsetfrom> + <utc-offset>-05:00</utc-offset> + </tzoffsetfrom> + <tzoffsetto> + <utc-offset>-04:00</utc-offset> + </tzoffsetto> + </properties> + </daylight> + <standard> + <properties> + <dtstart> + <date-time>2000-10-26T02:00:00</date-time> + </dtstart> + <rrule> + <recur> + <freq>YEARLY</freq> + <byday>-1SU</byday> + <bymonth>10</bymonth> + </recur> + </rrule> + <tzname> + <text>EST</text> + </tzname> + <tzoffsetfrom> + <utc-offset>-04:00</utc-offset> + </tzoffsetfrom> + <tzoffsetto> + <utc-offset>-05:00</utc-offset> + </tzoffsetto> + </properties> + </standard> + </components> + </vtimezone> + <vevent> + <properties> + <dtstamp> + <date-time>2006-02-06T00:11:21Z</date-time> + </dtstamp> + <dtstart> + <parameters> + <tzid><text>US/Eastern</text></tzid> + </parameters> + <date-time>2006-01-02T12:00:00</date-time> + </dtstart> + <duration> + <duration>PT1H</duration> + </duration> + <rrule> + <recur> + <freq>DAILY</freq> + <count>5</count> + </recur> + </rrule> + <rdate> + <parameters> + <tzid><text>US/Eastern</text></tzid> + </parameters> + <period> + <start>2006-01-02T15:00:00</start> + <duration>PT2H</duration> + </period> + </rdate> + <summary> + <text>Event #2</text> + </summary> + <description> + <text>We are having a meeting all this week at 12 +pm for one hour, with an additional meeting on the first day +2 hours long. Please bring your own lunch for the 12 pm +meetings.</text> + </description> + <uid> + <text>00959BC664CA650E933C892C@example.com</text> + </uid> + </properties> + </vevent> + <vevent> + <properties> + <dtstamp> + <date-time>2006-02-06T00:11:21Z</date-time> + </dtstamp> + <dtstart> + <parameters> + <tzid><text>US/Eastern</text></tzid> + </parameters> + <date-time>2006-01-04T14:00:00</date-time> + </dtstart> + <duration> + <duration>PT1H</duration> + </duration> + <recurrence-id> + <parameters> + <tzid><text>US/Eastern</text></tzid> + </parameters> + <date-time>2006-01-04T12:00:00</date-time> + </recurrence-id> + <summary> + <text>Event #2 bis</text> + </summary> + <uid> + <text>00959BC664CA650E933C892C@example.com</text> + </uid> + </properties> + </vevent> + </components> + </vcalendar> +</icalendar> +XML; + + $component = VObject\Reader::readXML($xml); + $this->assertVObjectEqualsVObject( + 'BEGIN:VCALENDAR'."\n". + 'VERSION:2.0'."\n". + 'PRODID:-//Example Inc.//Example Client//EN'."\n". + 'BEGIN:VTIMEZONE'."\n". + 'LAST-MODIFIED:20040110T032845Z'."\n". + 'TZID:US/Eastern'."\n". + 'BEGIN:DAYLIGHT'."\n". + 'DTSTART:20000404T020000'."\n". + 'RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=4'."\n". + 'TZNAME:EDT'."\n". + 'TZOFFSETFROM:-0500'."\n". + 'TZOFFSETTO:-0400'."\n". + 'END:DAYLIGHT'."\n". + 'BEGIN:STANDARD'."\n". + 'DTSTART:20001026T020000'."\n". + 'RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10'."\n". + 'TZNAME:EST'."\n". + 'TZOFFSETFROM:-0400'."\n". + 'TZOFFSETTO:-0500'."\n". + 'END:STANDARD'."\n". + 'END:VTIMEZONE'."\n". + 'BEGIN:VEVENT'."\n". + 'DTSTAMP:20060206T001121Z'."\n". + 'DTSTART;TZID=US/Eastern:20060102T120000'."\n". + 'DURATION:PT1H'."\n". + 'RRULE:FREQ=DAILY;COUNT=5'."\n". + 'RDATE;TZID=US/Eastern;VALUE=PERIOD:20060102T150000/PT2H'."\n". + 'SUMMARY:Event #2'."\n". + 'DESCRIPTION:We are having a meeting all this week at 12\npm for one hour\, '."\n". + ' with an additional meeting on the first day\n2 hours long.\nPlease bring y'."\n". + ' our own lunch for the 12 pm\nmeetings.'."\n". + 'UID:00959BC664CA650E933C892C@example.com'."\n". + 'END:VEVENT'."\n". + 'BEGIN:VEVENT'."\n". + 'DTSTAMP:20060206T001121Z'."\n". + 'DTSTART;TZID=US/Eastern:20060104T140000'."\n". + 'DURATION:PT1H'."\n". + 'RECURRENCE-ID;TZID=US/Eastern:20060104T120000'."\n". + 'SUMMARY:Event #2 bis'."\n". + 'UID:00959BC664CA650E933C892C@example.com'."\n". + 'END:VEVENT'."\n". + 'END:VCALENDAR'."\n", + VObject\Writer::write($component) + ); + } + + /** + * iCalendar Stream. + */ + public function testRFC6321Section3_2() + { + $this->assertXMLReflexivelyEqualsToMimeDir( +<<<XML +<?xml version="1.0" encoding="UTF-8"?> +<icalendar xmlns="urn:ietf:params:xml:ns:icalendar-2.0"> + <vcalendar/> +</icalendar> +XML +, + 'BEGIN:VCALENDAR'."\n". + 'END:VCALENDAR'."\n" + ); + } + + /** + * All components exist. + */ + public function testRFC6321Section3_3() + { + $this->assertXMLReflexivelyEqualsToMimeDir( +<<<XML +<?xml version="1.0" encoding="UTF-8"?> +<icalendar xmlns="urn:ietf:params:xml:ns:icalendar-2.0"> + <vcalendar> + <components> + <vtimezone/> + <vevent/> + <vtodo/> + <vjournal/> + <vfreebusy/> + <standard/> + <daylight/> + <valarm/> + </components> + </vcalendar> +</icalendar> +XML +, + 'BEGIN:VCALENDAR'."\n". + 'BEGIN:VTIMEZONE'."\n". + 'END:VTIMEZONE'."\n". + 'BEGIN:VEVENT'."\n". + 'END:VEVENT'."\n". + 'BEGIN:VTODO'."\n". + 'END:VTODO'."\n". + 'BEGIN:VJOURNAL'."\n". + 'END:VJOURNAL'."\n". + 'BEGIN:VFREEBUSY'."\n". + 'END:VFREEBUSY'."\n". + 'BEGIN:STANDARD'."\n". + 'END:STANDARD'."\n". + 'BEGIN:DAYLIGHT'."\n". + 'END:DAYLIGHT'."\n". + 'BEGIN:VALARM'."\n". + 'END:VALARM'."\n". + 'END:VCALENDAR'."\n" + ); + } + + /** + * Properties, Special Cases, GEO. + */ + public function testRFC6321Section3_4_1_2() + { + $this->assertXMLReflexivelyEqualsToMimeDir( +<<<XML +<?xml version="1.0" encoding="UTF-8"?> +<icalendar xmlns="urn:ietf:params:xml:ns:icalendar-2.0"> + <vcalendar> + <properties> + <geo> + <latitude>37.386013</latitude> + <longitude>-122.082932</longitude> + </geo> + </properties> + </vcalendar> +</icalendar> +XML +, + 'BEGIN:VCALENDAR'."\n". + 'GEO:37.386013;-122.082932'."\n". + 'END:VCALENDAR'."\n" + ); + } + + /** + * Properties, Special Cases, REQUEST-STATUS. + */ + public function testRFC6321Section3_4_1_3() + { + // Example 1 of RFC5545, Section 3.8.8.3. + $this->assertXMLReflexivelyEqualsToMimeDir( +<<<XML +<?xml version="1.0" encoding="UTF-8"?> +<icalendar xmlns="urn:ietf:params:xml:ns:icalendar-2.0"> + <vcalendar> + <properties> + <request-status> + <code>2.0</code> + <description>Success</description> + </request-status> + </properties> + </vcalendar> +</icalendar> +XML +, + 'BEGIN:VCALENDAR'."\n". + 'REQUEST-STATUS:2.0;Success'."\n". + 'END:VCALENDAR'."\n" + ); + + // Example 2 of RFC5545, Section 3.8.8.3. + $this->assertXMLReflexivelyEqualsToMimeDir( +<<<XML +<?xml version="1.0" encoding="UTF-8"?> +<icalendar xmlns="urn:ietf:params:xml:ns:icalendar-2.0"> + <vcalendar> + <properties> + <request-status> + <code>3.1</code> + <description>Invalid property value</description> + <data>DTSTART:96-Apr-01</data> + </request-status> + </properties> + </vcalendar> +</icalendar> +XML +, + 'BEGIN:VCALENDAR'."\n". + 'REQUEST-STATUS:3.1;Invalid property value;DTSTART:96-Apr-01'."\n". + 'END:VCALENDAR'."\n" + ); + + // Example 3 of RFC5545, Section 3.8.8.3. + $this->assertXMLReflexivelyEqualsToMimeDir( +<<<XML +<?xml version="1.0" encoding="UTF-8"?> +<icalendar xmlns="urn:ietf:params:xml:ns:icalendar-2.0"> + <vcalendar> + <properties> + <request-status> + <code>2.8</code> + <description>Success, repeating event ignored. Scheduled as a single event.</description> + <data>RRULE:FREQ=WEEKLY;INTERVAL=2</data> + </request-status> + </properties> + </vcalendar> +</icalendar> +XML +, + 'BEGIN:VCALENDAR'."\n". + 'REQUEST-STATUS:2.8;Success\, repeating event ignored. Scheduled as a single'."\n". + ' event.;RRULE:FREQ=WEEKLY\;INTERVAL=2'."\n". + 'END:VCALENDAR'."\n" + ); + + // Example 4 of RFC5545, Section 3.8.8.3. + $this->assertXMLReflexivelyEqualsToMimeDir( +<<<XML +<?xml version="1.0" encoding="UTF-8"?> +<icalendar xmlns="urn:ietf:params:xml:ns:icalendar-2.0"> + <vcalendar> + <properties> + <request-status> + <code>4.1</code> + <description>Event conflict. Date-time is busy.</description> + </request-status> + </properties> + </vcalendar> +</icalendar> +XML +, + 'BEGIN:VCALENDAR'."\n". + 'REQUEST-STATUS:4.1;Event conflict. Date-time is busy.'."\n". + 'END:VCALENDAR'."\n" + ); + + // Example 5 of RFC5545, Section 3.8.8.3. + $this->assertXMLReflexivelyEqualsToMimeDir( +<<<XML +<?xml version="1.0" encoding="UTF-8"?> +<icalendar xmlns="urn:ietf:params:xml:ns:icalendar-2.0"> + <vcalendar> + <properties> + <request-status> + <code>3.7</code> + <description>Invalid calendar user</description> + <data>ATTENDEE:mailto:jsmith@example.com</data> + </request-status> + </properties> + </vcalendar> +</icalendar> +XML +, + 'BEGIN:VCALENDAR'."\n". + 'REQUEST-STATUS:3.7;Invalid calendar user;ATTENDEE:mailto:jsmith@example.com'."\n". + 'END:VCALENDAR'."\n" + ); + } + + /** + * Values, Binary. + */ + public function testRFC6321Section3_6_1() + { + $this->assertXMLEqualsToMimeDir( +<<<XML +<?xml version="1.0" encoding="UTF-8"?> +<icalendar xmlns="urn:ietf:params:xml:ns:icalendar-2.0"> + <vcalendar> + <properties> + <attach> + <binary>SGVsbG8gV29ybGQh</binary> + </attach> + </properties> + </vcalendar> +</icalendar> +XML +, + 'BEGIN:VCALENDAR'."\n". + 'ATTACH:SGVsbG8gV29ybGQh'."\n". + 'END:VCALENDAR'."\n" + ); + + // In vCard 4, BINARY no longer exists and is replaced by URI. + $this->assertXMLReflexivelyEqualsToMimeDir( +<<<XML +<?xml version="1.0" encoding="UTF-8"?> +<icalendar xmlns="urn:ietf:params:xml:ns:icalendar-2.0"> + <vcalendar> + <properties> + <attach> + <uri>SGVsbG8gV29ybGQh</uri> + </attach> + </properties> + </vcalendar> +</icalendar> +XML +, + 'BEGIN:VCALENDAR'."\n". + 'ATTACH:SGVsbG8gV29ybGQh'."\n". + 'END:VCALENDAR'."\n" + ); + } + + /** + * Values, Boolean. + */ + public function testRFC6321Section3_6_2() + { + $this->assertXMLEqualsToMimeDir( +<<<XML +<?xml version="1.0" encoding="UTF-8"?> +<icalendar xmlns="urn:ietf:params:xml:ns:icalendar-2.0"> + <vcalendar> + <properties> + <attendee> + <parameters> + <rsvp><boolean>true</boolean></rsvp> + </parameters> + <cal-address>mailto:cyrus@example.com</cal-address> + </attendee> + </properties> + </vcalendar> +</icalendar> +XML +, + 'BEGIN:VCALENDAR'."\n". + 'ATTENDEE;RSVP=true:mailto:cyrus@example.com'."\n". + 'END:VCALENDAR'."\n" + ); + } + + /** + * Values, Calendar User Address. + */ + public function testRFC6321Section3_6_3() + { + $this->assertXMLReflexivelyEqualsToMimeDir( +<<<XML +<?xml version="1.0" encoding="UTF-8"?> +<icalendar xmlns="urn:ietf:params:xml:ns:icalendar-2.0"> + <vcalendar> + <properties> + <attendee> + <cal-address>mailto:cyrus@example.com</cal-address> + </attendee> + </properties> + </vcalendar> +</icalendar> +XML +, + 'BEGIN:VCALENDAR'."\n". + 'ATTENDEE:mailto:cyrus@example.com'."\n". + 'END:VCALENDAR'."\n" + ); + } + + /** + * Values, Date. + */ + public function testRFC6321Section3_6_4() + { + $this->assertXMLReflexivelyEqualsToMimeDir( +<<<XML +<?xml version="1.0" encoding="UTF-8"?> +<icalendar xmlns="urn:ietf:params:xml:ns:icalendar-2.0"> + <vcalendar> + <properties> + <dtstart> + <date>2011-05-17</date> + </dtstart> + </properties> + </vcalendar> +</icalendar> +XML +, + 'BEGIN:VCALENDAR'."\n". + 'DTSTART;VALUE=DATE:20110517'."\n". + 'END:VCALENDAR'."\n" + ); + } + + /** + * Values, Date-Time. + */ + public function testRFC6321Section3_6_5() + { + $this->assertXMLReflexivelyEqualsToMimeDir( +<<<XML +<?xml version="1.0" encoding="UTF-8"?> +<icalendar xmlns="urn:ietf:params:xml:ns:icalendar-2.0"> + <vcalendar> + <properties> + <dtstart> + <date-time>2011-05-17T12:00:00</date-time> + </dtstart> + </properties> + </vcalendar> +</icalendar> +XML +, + 'BEGIN:VCALENDAR'."\n". + 'DTSTART:20110517T120000'."\n". + 'END:VCALENDAR'."\n" + ); + } + + /** + * Values, Duration. + */ + public function testRFC6321Section3_6_6() + { + $this->assertXMLReflexivelyEqualsToMimeDir( +<<<XML +<?xml version="1.0" encoding="UTF-8"?> +<icalendar xmlns="urn:ietf:params:xml:ns:icalendar-2.0"> + <vcalendar> + <properties> + <duration> + <duration>P1D</duration> + </duration> + </properties> + </vcalendar> +</icalendar> +XML +, + 'BEGIN:VCALENDAR'."\n". + 'DURATION:P1D'."\n". + 'END:VCALENDAR'."\n" + ); + } + + /** + * Values, Float. + */ + public function testRFC6321Section3_6_7() + { + // GEO uses <float /> with a positive and a non-negative numbers. + $this->testRFC6321Section3_4_1_2(); + } + + /** + * Values, Integer. + */ + public function testRFC6321Section3_6_8() + { + $this->assertXMLEqualsToMimeDir( +<<<XML +<?xml version="1.0" encoding="UTF-8"?> +<icalendar xmlns="urn:ietf:params:xml:ns:icalendar-2.0"> + <vcalendar> + <properties> + <foo> + <integer>42</integer> + </foo> + </properties> + </vcalendar> +</icalendar> +XML +, + 'BEGIN:VCALENDAR'."\n". + 'FOO:42'."\n". + 'END:VCALENDAR'."\n" + ); + + $this->assertXMLEqualsToMimeDir( +<<<XML +<?xml version="1.0" encoding="UTF-8"?> +<icalendar xmlns="urn:ietf:params:xml:ns:icalendar-2.0"> + <vcalendar> + <properties> + <foo> + <integer>-42</integer> + </foo> + </properties> + </vcalendar> +</icalendar> +XML +, + 'BEGIN:VCALENDAR'."\n". + 'FOO:-42'."\n". + 'END:VCALENDAR'."\n" + ); + } + + /** + * Values, Period of Time. + */ + public function testRFC6321Section3_6_9() + { + $this->assertXMLReflexivelyEqualsToMimeDir( +<<<XML +<?xml version="1.0" encoding="UTF-8"?> +<icalendar xmlns="urn:ietf:params:xml:ns:icalendar-2.0"> + <vcalendar> + <properties> + <freebusy> + <period> + <start>2011-05-17T12:00:00</start> + <duration>P1H</duration> + </period> + </freebusy> + </properties> + </vcalendar> +</icalendar> +XML +, + 'BEGIN:VCALENDAR'."\n". + 'FREEBUSY:20110517T120000/P1H'."\n". + 'END:VCALENDAR'."\n" + ); + + $this->assertXMLReflexivelyEqualsToMimeDir( +<<<XML +<?xml version="1.0" encoding="UTF-8"?> +<icalendar xmlns="urn:ietf:params:xml:ns:icalendar-2.0"> + <vcalendar> + <properties> + <freebusy> + <period> + <start>2011-05-17T12:00:00</start> + <end>2012-05-17T12:00:00</end> + </period> + </freebusy> + </properties> + </vcalendar> +</icalendar> +XML +, + 'BEGIN:VCALENDAR'."\n". + 'FREEBUSY:20110517T120000/20120517T120000'."\n". + 'END:VCALENDAR'."\n" + ); + } + + /** + * Values, Recurrence Rule. + */ + public function testRFC6321Section3_6_10() + { + $this->assertXMLReflexivelyEqualsToMimeDir( +<<<XML +<?xml version="1.0" encoding="UTF-8"?> +<icalendar xmlns="urn:ietf:params:xml:ns:icalendar-2.0"> + <vcalendar> + <properties> + <rrule> + <recur> + <freq>YEARLY</freq> + <count>5</count> + <byday>-1SU</byday> + <bymonth>10</bymonth> + </recur> + </rrule> + </properties> + </vcalendar> +</icalendar> +XML +, + 'BEGIN:VCALENDAR'."\n". + 'RRULE:FREQ=YEARLY;COUNT=5;BYDAY=-1SU;BYMONTH=10'."\n". + 'END:VCALENDAR'."\n" + ); + } + + /** + * Values, Text. + */ + public function testRFC6321Section3_6_11() + { + $this->assertXMLReflexivelyEqualsToMimeDir( +<<<XML +<?xml version="1.0" encoding="UTF-8"?> +<icalendar xmlns="urn:ietf:params:xml:ns:icalendar-2.0"> + <vcalendar> + <properties> + <calscale> + <text>GREGORIAN</text> + </calscale> + </properties> + </vcalendar> +</icalendar> +XML +, + 'BEGIN:VCALENDAR'."\n". + 'CALSCALE:GREGORIAN'."\n". + 'END:VCALENDAR'."\n" + ); + } + + /** + * Values, Time. + */ + public function testRFC6321Section3_6_12() + { + $this->assertXMLEqualsToMimeDir( +<<<XML +<?xml version="1.0" encoding="UTF-8"?> +<icalendar xmlns="urn:ietf:params:xml:ns:icalendar-2.0"> + <vcalendar> + <properties> + <foo> + <time>12:00:00</time> + </foo> + </properties> + </vcalendar> +</icalendar> +XML +, + 'BEGIN:VCALENDAR'."\n". + 'FOO:120000'."\n". + 'END:VCALENDAR'."\n" + ); + } + + /** + * Values, URI. + */ + public function testRFC6321Section3_6_13() + { + $this->assertXMLReflexivelyEqualsToMimeDir( +<<<XML +<?xml version="1.0" encoding="UTF-8"?> +<icalendar xmlns="urn:ietf:params:xml:ns:icalendar-2.0"> + <vcalendar> + <properties> + <attach> + <uri>http://calendar.example.com</uri> + </attach> + </properties> + </vcalendar> +</icalendar> +XML +, + 'BEGIN:VCALENDAR'."\n". + 'ATTACH:http://calendar.example.com'."\n". + 'END:VCALENDAR'."\n" + ); + } + + /** + * Values, UTC Offset. + */ + public function testRFC6321Section3_6_14() + { + // Example 1 of RFC5545, Section 3.3.14. + $this->assertXMLReflexivelyEqualsToMimeDir( +<<<XML +<?xml version="1.0" encoding="UTF-8"?> +<icalendar xmlns="urn:ietf:params:xml:ns:icalendar-2.0"> + <vcalendar> + <properties> + <tzoffsetfrom> + <utc-offset>-05:00</utc-offset> + </tzoffsetfrom> + </properties> + </vcalendar> +</icalendar> +XML +, + 'BEGIN:VCALENDAR'."\n". + 'TZOFFSETFROM:-0500'."\n". + 'END:VCALENDAR'."\n" + ); + + // Example 2 of RFC5545, Section 3.3.14. + $this->assertXMLReflexivelyEqualsToMimeDir( +<<<XML +<?xml version="1.0" encoding="UTF-8"?> +<icalendar xmlns="urn:ietf:params:xml:ns:icalendar-2.0"> + <vcalendar> + <properties> + <tzoffsetfrom> + <utc-offset>+01:00</utc-offset> + </tzoffsetfrom> + </properties> + </vcalendar> +</icalendar> +XML +, + 'BEGIN:VCALENDAR'."\n". + 'TZOFFSETFROM:+0100'."\n". + 'END:VCALENDAR'."\n" + ); + } + + /** + * Handling Unrecognized Properties or Parameters. + */ + public function testRFC6321Section5() + { + $this->assertXMLReflexivelyEqualsToMimeDir( +<<<XML +<?xml version="1.0" encoding="UTF-8"?> +<icalendar xmlns="urn:ietf:params:xml:ns:icalendar-2.0"> + <vcalendar> + <properties> + <x-property> + <unknown>20110512T120000Z</unknown> + </x-property> + </properties> + </vcalendar> +</icalendar> +XML +, + 'BEGIN:VCALENDAR'."\n". + 'X-PROPERTY:20110512T120000Z'."\n". + 'END:VCALENDAR'."\n" + ); + + $this->assertXMLReflexivelyEqualsToMimeDir( +<<<XML +<?xml version="1.0" encoding="UTF-8"?> +<icalendar xmlns="urn:ietf:params:xml:ns:icalendar-2.0"> + <vcalendar> + <properties> + <dtstart> + <parameters> + <x-param> + <text>PT30M</text> + </x-param> + </parameters> + <date-time>2011-05-12T13:00:00Z</date-time> + </dtstart> + </properties> + </vcalendar> +</icalendar> +XML +, + 'BEGIN:VCALENDAR'."\n". + 'DTSTART;X-PARAM=PT30M:20110512T130000Z'."\n". + 'END:VCALENDAR'."\n" + ); + } + + public function testRDateWithDateTime() + { + $this->assertXMLReflexivelyEqualsToMimeDir( +<<<XML +<?xml version="1.0" encoding="UTF-8"?> +<icalendar xmlns="urn:ietf:params:xml:ns:icalendar-2.0"> + <vcalendar> + <properties> + <rdate> + <date-time>2008-02-05T19:12:24Z</date-time> + </rdate> + </properties> + </vcalendar> +</icalendar> +XML +, + 'BEGIN:VCALENDAR'."\n". + 'RDATE:20080205T191224Z'."\n". + 'END:VCALENDAR'."\n" + ); + + $this->assertXMLReflexivelyEqualsToMimeDir( +<<<XML +<?xml version="1.0" encoding="UTF-8"?> +<icalendar xmlns="urn:ietf:params:xml:ns:icalendar-2.0"> + <vcalendar> + <properties> + <rdate> + <date-time>2008-02-05T19:12:24Z</date-time> + <date-time>2009-02-05T19:12:24Z</date-time> + </rdate> + </properties> + </vcalendar> +</icalendar> +XML +, + 'BEGIN:VCALENDAR'."\n". + 'RDATE:20080205T191224Z,20090205T191224Z'."\n". + 'END:VCALENDAR'."\n" + ); + } + + public function testRDateWithDate() + { + $this->assertXMLEqualsToMimeDir( +<<<XML +<?xml version="1.0" encoding="UTF-8"?> +<icalendar xmlns="urn:ietf:params:xml:ns:icalendar-2.0"> + <vcalendar> + <properties> + <rdate> + <date>2008-10-06</date> + </rdate> + </properties> + </vcalendar> +</icalendar> +XML +, + 'BEGIN:VCALENDAR'."\n". + 'RDATE:20081006'."\n". + 'END:VCALENDAR'."\n" + ); + + $this->assertXMLEqualsToMimeDir( +<<<XML +<?xml version="1.0" encoding="UTF-8"?> +<icalendar xmlns="urn:ietf:params:xml:ns:icalendar-2.0"> + <vcalendar> + <properties> + <rdate> + <date>2008-10-06</date> + <date>2009-10-06</date> + <date>2010-10-06</date> + </rdate> + </properties> + </vcalendar> +</icalendar> +XML +, + 'BEGIN:VCALENDAR'."\n". + 'RDATE:20081006,20091006,20101006'."\n". + 'END:VCALENDAR'."\n" + ); + } + + public function testRDateWithPeriod() + { + $this->assertXMLReflexivelyEqualsToMimeDir( +<<<XML +<?xml version="1.0" encoding="UTF-8"?> +<icalendar xmlns="urn:ietf:params:xml:ns:icalendar-2.0"> + <vcalendar> + <properties> + <rdate> + <parameters> + <tzid> + <text>US/Eastern</text> + </tzid> + </parameters> + <period> + <start>2006-01-02T15:00:00</start> + <duration>PT2H</duration> + </period> + </rdate> + </properties> + </vcalendar> +</icalendar> +XML +, + 'BEGIN:VCALENDAR'."\n". + 'RDATE;TZID=US/Eastern;VALUE=PERIOD:20060102T150000/PT2H'."\n". + 'END:VCALENDAR'."\n" + ); + + $this->assertXMLEqualsToMimeDir( +<<<XML +<?xml version="1.0" encoding="UTF-8"?> +<icalendar xmlns="urn:ietf:params:xml:ns:icalendar-2.0"> + <vcalendar> + <properties> + <rdate> + <parameters> + <tzid> + <text>US/Eastern</text> + </tzid> + </parameters> + <period> + <start>2006-01-02T15:00:00</start> + <duration>PT2H</duration> + </period> + <period> + <start>2008-01-02T15:00:00</start> + <duration>PT1H</duration> + </period> + </rdate> + </properties> + </vcalendar> +</icalendar> +XML +, + 'BEGIN:VCALENDAR'."\n". + 'RDATE;TZID=US/Eastern;VALUE=PERIOD:20060102T150000/PT2H,20080102T150000/PT1'."\n". + ' H'."\n". + 'END:VCALENDAR'."\n" + ); + } + + /** + * Basic example. + */ + public function testRFC6351Basic() + { + $this->assertXMLReflexivelyEqualsToMimeDir( +<<<XML +<?xml version="1.0" encoding="UTF-8"?> +<vcards xmlns="urn:ietf:params:xml:ns:vcard-4.0"> + <vcard> + <fn> + <text>J. Doe</text> + </fn> + <n> + <surname>Doe</surname> + <given>J.</given> + <additional/> + <prefix/> + <suffix/> + </n> + </vcard> +</vcards> +XML +, + 'BEGIN:VCARD'."\n". + 'VERSION:4.0'."\n". + 'FN:J. Doe'."\n". + 'N:Doe;J.;;;'."\n". + 'END:VCARD'."\n" + ); + } + + /** + * Example 1. + */ + public function testRFC6351Example1() + { + $this->assertXMLReflexivelyEqualsToMimeDir( +<<<XML +<?xml version="1.0" encoding="UTF-8"?> +<vcards xmlns="urn:ietf:params:xml:ns:vcard-4.0"> + <vcard> + <fn> + <text>J. Doe</text> + </fn> + <n> + <surname>Doe</surname> + <given>J.</given> + <additional/> + <prefix/> + <suffix/> + </n> + <x-file> + <parameters> + <mediatype> + <text>image/jpeg</text> + </mediatype> + </parameters> + <unknown>alien.jpg</unknown> + </x-file> + <x1:a href="http://www.example.com" xmlns:x1="http://www.w3.org/1999/xhtml">My web page!</x1:a> + </vcard> +</vcards> +XML +, + 'BEGIN:VCARD'."\n". + 'VERSION:4.0'."\n". + 'FN:J. Doe'."\n". + 'N:Doe;J.;;;'."\n". + 'X-FILE;MEDIATYPE=image/jpeg:alien.jpg'."\n". + 'XML:<a xmlns="http://www.w3.org/1999/xhtml" href="http://www.example.com">M'."\n". + ' y web page!</a>'."\n". + 'END:VCARD'."\n" + ); + } + + /** + * Design Considerations. + */ + public function testRFC6351Section5() + { + $this->assertXMLEqualsToMimeDir( +<<<XML +<?xml version="1.0" encoding="UTF-8"?> +<vcards xmlns="urn:ietf:params:xml:ns:vcard-4.0"> + <vcard> + <tel> + <parameters> + <type> + <text>voice</text> + <text>video</text> + </type> + </parameters> + <uri>tel:+1-555-555-555</uri> + </tel> + </vcard> +</vcards> +XML +, + 'BEGIN:VCARD'."\n". + 'VERSION:4.0'."\n". + 'TEL;TYPE="voice,video":tel:+1-555-555-555'."\n". + 'END:VCARD'."\n" + ); + + $this->assertXMLReflexivelyEqualsToMimeDir( +<<<XML +<?xml version="1.0" encoding="UTF-8"?> +<vcards xmlns="urn:ietf:params:xml:ns:vcard-4.0"> + <vcard> + <tel> + <parameters> + <type> + <text>voice</text> + <text>video</text> + </type> + </parameters> + <text>tel:+1-555-555-555</text> + </tel> + </vcard> +</vcards> +XML +, + 'BEGIN:VCARD'."\n". + 'VERSION:4.0'."\n". + 'TEL;TYPE="voice,video":tel:+1-555-555-555'."\n". + 'END:VCARD'."\n" + ); + } + + /** + * Design Considerations. + */ + public function testRFC6351Section5Group() + { + $this->assertXMLReflexivelyEqualsToMimeDir( +<<<XML +<?xml version="1.0" encoding="UTF-8"?> +<vcards xmlns="urn:ietf:params:xml:ns:vcard-4.0"> + <vcard> + <tel> + <text>tel:+1-555-555-556</text> + </tel> + <group name="contact"> + <tel> + <text>tel:+1-555-555-555</text> + </tel> + <fn> + <text>Gordon</text> + </fn> + </group> + <group name="media"> + <fn> + <text>Gordon</text> + </fn> + </group> + </vcard> +</vcards> +XML +, + 'BEGIN:VCARD'."\n". + 'VERSION:4.0'."\n". + 'TEL:tel:+1-555-555-556'."\n". + 'contact.TEL:tel:+1-555-555-555'."\n". + 'contact.FN:Gordon'."\n". + 'media.FN:Gordon'."\n". + 'END:VCARD'."\n" + ); + } + + /** + * Extensibility. + */ + public function testRFC6351Section5_1_NoNamespace() + { + $this->assertXMLEqualsToMimeDir( +<<<XML +<?xml version="1.0" encoding="UTF-8"?> +<vcards xmlns="urn:ietf:params:xml:ns:vcard-4.0"> + <vcard> + <x-my-prop> + <parameters> + <pref> + <integer>1</integer> + </pref> + </parameters> + <text>value goes here</text> + </x-my-prop> + </vcard> +</vcards> +XML +, + 'BEGIN:VCARD'."\n". + 'VERSION:4.0'."\n". + 'X-MY-PROP;PREF=1:value goes here'."\n". + 'END:VCARD'."\n" + ); + } + + /** + * Section 4.3.1 of Relax NG Schema: value-date. + */ + public function testRFC6351ValueDateWithYearMonthDay() + { + $this->assertXMLReflexivelyEqualsToMimeDir( +<<<XML +<?xml version="1.0" encoding="UTF-8"?> +<vcards xmlns="urn:ietf:params:xml:ns:vcard-4.0"> + <vcard> + <bday> + <date-and-or-time>20150128</date-and-or-time> + </bday> + </vcard> +</vcards> +XML +, + 'BEGIN:VCARD'."\n". + 'VERSION:4.0'."\n". + 'BDAY:20150128'."\n". + 'END:VCARD'."\n" + ); + } + + /** + * Section 4.3.1 of Relax NG Schema: value-date. + */ + public function testRFC6351ValueDateWithYearMonth() + { + $this->assertXMLReflexivelyEqualsToMimeDir( +<<<XML +<?xml version="1.0" encoding="UTF-8"?> +<vcards xmlns="urn:ietf:params:xml:ns:vcard-4.0"> + <vcard> + <bday> + <date-and-or-time>2015-01</date-and-or-time> + </bday> + </vcard> +</vcards> +XML +, + 'BEGIN:VCARD'."\n". + 'VERSION:4.0'."\n". + 'BDAY:2015-01'."\n". + 'END:VCARD'."\n" + ); + } + + /** + * Section 4.3.1 of Relax NG Schema: value-date. + */ + public function testRFC6351ValueDateWithMonth() + { + $this->assertXMLReflexivelyEqualsToMimeDir( +<<<XML +<?xml version="1.0" encoding="UTF-8"?> +<vcards xmlns="urn:ietf:params:xml:ns:vcard-4.0"> + <vcard> + <bday> + <date-and-or-time>--01</date-and-or-time> + </bday> + </vcard> +</vcards> +XML +, + 'BEGIN:VCARD'."\n". + 'VERSION:4.0'."\n". + 'BDAY:--01'."\n". + 'END:VCARD'."\n" + ); + } + + /** + * Section 4.3.1 of Relax NG Schema: value-date. + */ + public function testRFC6351ValueDateWithMonthDay() + { + $this->assertXMLReflexivelyEqualsToMimeDir( +<<<XML +<?xml version="1.0" encoding="UTF-8"?> +<vcards xmlns="urn:ietf:params:xml:ns:vcard-4.0"> + <vcard> + <bday> + <date-and-or-time>--0128</date-and-or-time> + </bday> + </vcard> +</vcards> +XML +, + 'BEGIN:VCARD'."\n". + 'VERSION:4.0'."\n". + 'BDAY:--0128'."\n". + 'END:VCARD'."\n" + ); + } + + /** + * Section 4.3.1 of Relax NG Schema: value-date. + */ + public function testRFC6351ValueDateWithDay() + { + $this->assertXMLReflexivelyEqualsToMimeDir( +<<<XML +<?xml version="1.0" encoding="UTF-8"?> +<vcards xmlns="urn:ietf:params:xml:ns:vcard-4.0"> + <vcard> + <bday> + <date-and-or-time>---28</date-and-or-time> + </bday> + </vcard> +</vcards> +XML +, + 'BEGIN:VCARD'."\n". + 'VERSION:4.0'."\n". + 'BDAY:---28'."\n". + 'END:VCARD'."\n" + ); + } + + /** + * Section 4.3.2 of Relax NG Schema: value-time. + */ + public function testRFC6351ValueTimeWithHour() + { + $this->assertXMLReflexivelyEqualsToMimeDir( +<<<XML +<?xml version="1.0" encoding="UTF-8"?> +<vcards xmlns="urn:ietf:params:xml:ns:vcard-4.0"> + <vcard> + <bday> + <date-and-or-time>13</date-and-or-time> + </bday> + </vcard> +</vcards> +XML +, + 'BEGIN:VCARD'."\n". + 'VERSION:4.0'."\n". + 'BDAY:13'."\n". + 'END:VCARD'."\n" + ); + } + + /** + * Section 4.3.2 of Relax NG Schema: value-time. + */ + public function testRFC6351ValueTimeWithHourMinute() + { + $this->assertXMLReflexivelyEqualsToMimeDir( +<<<XML +<?xml version="1.0" encoding="UTF-8"?> +<vcards xmlns="urn:ietf:params:xml:ns:vcard-4.0"> + <vcard> + <bday> + <date-and-or-time>1353</date-and-or-time> + </bday> + </vcard> +</vcards> +XML +, + 'BEGIN:VCARD'."\n". + 'VERSION:4.0'."\n". + 'BDAY:1353'."\n". + 'END:VCARD'."\n" + ); + } + + /** + * Section 4.3.2 of Relax NG Schema: value-time. + */ + public function testRFC6351ValueTimeWithHourMinuteSecond() + { + $this->assertXMLReflexivelyEqualsToMimeDir( +<<<XML +<?xml version="1.0" encoding="UTF-8"?> +<vcards xmlns="urn:ietf:params:xml:ns:vcard-4.0"> + <vcard> + <bday> + <date-and-or-time>135301</date-and-or-time> + </bday> + </vcard> +</vcards> +XML +, + 'BEGIN:VCARD'."\n". + 'VERSION:4.0'."\n". + 'BDAY:135301'."\n". + 'END:VCARD'."\n" + ); + } + + /** + * Section 4.3.2 of Relax NG Schema: value-time. + */ + public function testRFC6351ValueTimeWithMinute() + { + $this->assertXMLReflexivelyEqualsToMimeDir( +<<<XML +<?xml version="1.0" encoding="UTF-8"?> +<vcards xmlns="urn:ietf:params:xml:ns:vcard-4.0"> + <vcard> + <bday> + <date-and-or-time>-53</date-and-or-time> + </bday> + </vcard> +</vcards> +XML +, + 'BEGIN:VCARD'."\n". + 'VERSION:4.0'."\n". + 'BDAY:-53'."\n". + 'END:VCARD'."\n" + ); + } + + /** + * Section 4.3.2 of Relax NG Schema: value-time. + */ + public function testRFC6351ValueTimeWithMinuteSecond() + { + $this->assertXMLReflexivelyEqualsToMimeDir( +<<<XML +<?xml version="1.0" encoding="UTF-8"?> +<vcards xmlns="urn:ietf:params:xml:ns:vcard-4.0"> + <vcard> + <bday> + <date-and-or-time>-5301</date-and-or-time> + </bday> + </vcard> +</vcards> +XML +, + 'BEGIN:VCARD'."\n". + 'VERSION:4.0'."\n". + 'BDAY:-5301'."\n". + 'END:VCARD'."\n" + ); + } + + /** + * Section 4.3.2 of Relax NG Schema: value-time. + */ + public function testRFC6351ValueTimeWithSecond() + { + $this->assertTrue(true); + + /* + * According to the Relax NG Schema, there is a conflict between + * value-date and value-time. The --01 syntax can only match a + * value-date because of the higher priority set in + * value-date-and-or-time. So we basically skip this test. + * + $this->assertXMLReflexivelyEqualsToMimeDir( +<<<XML +<?xml version="1.0" encoding="UTF-8"?> +<vcards xmlns="urn:ietf:params:xml:ns:vcard-4.0"> + <vcard> + <bday> + <date-and-or-time>--01</date-and-or-time> + </bday> + </vcard> +</vcards> +XML +, + 'BEGIN:VCARD' . "\n" . + 'VERSION:4.0' . "\n" . + 'BDAY:--01' . "\n" . + 'END:VCARD' . "\n" + ); + */ + } + + /** + * Section 4.3.2 of Relax NG Schema: value-time. + */ + public function testRFC6351ValueTimeWithSecondZ() + { + $this->assertXMLReflexivelyEqualsToMimeDir( +<<<XML +<?xml version="1.0" encoding="UTF-8"?> +<vcards xmlns="urn:ietf:params:xml:ns:vcard-4.0"> + <vcard> + <bday> + <date-and-or-time>--01Z</date-and-or-time> + </bday> + </vcard> +</vcards> +XML +, + 'BEGIN:VCARD'."\n". + 'VERSION:4.0'."\n". + 'BDAY:--01Z'."\n". + 'END:VCARD'."\n" + ); + } + + /** + * Section 4.3.2 of Relax NG Schema: value-time. + */ + public function testRFC6351ValueTimeWithSecondTZ() + { + $this->assertXMLReflexivelyEqualsToMimeDir( +<<<XML +<?xml version="1.0" encoding="UTF-8"?> +<vcards xmlns="urn:ietf:params:xml:ns:vcard-4.0"> + <vcard> + <bday> + <date-and-or-time>--01+1234</date-and-or-time> + </bday> + </vcard> +</vcards> +XML +, + 'BEGIN:VCARD'."\n". + 'VERSION:4.0'."\n". + 'BDAY:--01+1234'."\n". + 'END:VCARD'."\n" + ); + } + + /** + * Section 4.3.3 of Relax NG Schema: value-date-time. + */ + public function testRFC6351ValueDateTimeWithYearMonthDayHour() + { + $this->assertXMLReflexivelyEqualsToMimeDir( +<<<XML +<?xml version="1.0" encoding="UTF-8"?> +<vcards xmlns="urn:ietf:params:xml:ns:vcard-4.0"> + <vcard> + <bday> + <date-and-or-time>20150128T13</date-and-or-time> + </bday> + </vcard> +</vcards> +XML +, + 'BEGIN:VCARD'."\n". + 'VERSION:4.0'."\n". + 'BDAY:20150128T13'."\n". + 'END:VCARD'."\n" + ); + } + + /** + * Section 4.3.3 of Relax NG Schema: value-date-time. + */ + public function testRFC6351ValueDateTimeWithMonthDayHour() + { + $this->assertXMLReflexivelyEqualsToMimeDir( +<<<XML +<?xml version="1.0" encoding="UTF-8"?> +<vcards xmlns="urn:ietf:params:xml:ns:vcard-4.0"> + <vcard> + <bday> + <date-and-or-time>--0128T13</date-and-or-time> + </bday> + </vcard> +</vcards> +XML +, + 'BEGIN:VCARD'."\n". + 'VERSION:4.0'."\n". + 'BDAY:--0128T13'."\n". + 'END:VCARD'."\n" + ); + } + + /** + * Section 4.3.3 of Relax NG Schema: value-date-time. + */ + public function testRFC6351ValueDateTimeWithDayHour() + { + $this->assertXMLReflexivelyEqualsToMimeDir( +<<<XML +<?xml version="1.0" encoding="UTF-8"?> +<vcards xmlns="urn:ietf:params:xml:ns:vcard-4.0"> + <vcard> + <bday> + <date-and-or-time>---28T13</date-and-or-time> + </bday> + </vcard> +</vcards> +XML +, + 'BEGIN:VCARD'."\n". + 'VERSION:4.0'."\n". + 'BDAY:---28T13'."\n". + 'END:VCARD'."\n" + ); + } + + /** + * Section 4.3.3 of Relax NG Schema: value-date-time. + */ + public function testRFC6351ValueDateTimeWithDayHourMinute() + { + $this->assertXMLReflexivelyEqualsToMimeDir( +<<<XML +<?xml version="1.0" encoding="UTF-8"?> +<vcards xmlns="urn:ietf:params:xml:ns:vcard-4.0"> + <vcard> + <bday> + <date-and-or-time>---28T1353</date-and-or-time> + </bday> + </vcard> +</vcards> +XML +, + 'BEGIN:VCARD'."\n". + 'VERSION:4.0'."\n". + 'BDAY:---28T1353'."\n". + 'END:VCARD'."\n" + ); + } + + /** + * Section 4.3.3 of Relax NG Schema: value-date-time. + */ + public function testRFC6351ValueDateTimeWithDayHourMinuteSecond() + { + $this->assertXMLReflexivelyEqualsToMimeDir( +<<<XML +<?xml version="1.0" encoding="UTF-8"?> +<vcards xmlns="urn:ietf:params:xml:ns:vcard-4.0"> + <vcard> + <bday> + <date-and-or-time>---28T135301</date-and-or-time> + </bday> + </vcard> +</vcards> +XML +, + 'BEGIN:VCARD'."\n". + 'VERSION:4.0'."\n". + 'BDAY:---28T135301'."\n". + 'END:VCARD'."\n" + ); + } + + /** + * Section 4.3.3 of Relax NG Schema: value-date-time. + */ + public function testRFC6351ValueDateTimeWithDayHourZ() + { + $this->assertXMLReflexivelyEqualsToMimeDir( +<<<XML +<?xml version="1.0" encoding="UTF-8"?> +<vcards xmlns="urn:ietf:params:xml:ns:vcard-4.0"> + <vcard> + <bday> + <date-and-or-time>---28T13Z</date-and-or-time> + </bday> + </vcard> +</vcards> +XML +, + 'BEGIN:VCARD'."\n". + 'VERSION:4.0'."\n". + 'BDAY:---28T13Z'."\n". + 'END:VCARD'."\n" + ); + } + + /** + * Section 4.3.3 of Relax NG Schema: value-date-time. + */ + public function testRFC6351ValueDateTimeWithDayHourTZ() + { + $this->assertXMLReflexivelyEqualsToMimeDir( +<<<XML +<?xml version="1.0" encoding="UTF-8"?> +<vcards xmlns="urn:ietf:params:xml:ns:vcard-4.0"> + <vcard> + <bday> + <date-and-or-time>---28T13+1234</date-and-or-time> + </bday> + </vcard> +</vcards> +XML +, + 'BEGIN:VCARD'."\n". + 'VERSION:4.0'."\n". + 'BDAY:---28T13+1234'."\n". + 'END:VCARD'."\n" + ); + } + + /** + * Property: SOURCE. + */ + public function testRFC6350Section6_1_3() + { + $this->assertXMLReflexivelyEqualsToMimeDir( +<<<XML +<?xml version="1.0" encoding="UTF-8"?> +<vcards xmlns="urn:ietf:params:xml:ns:vcard-4.0"> + <vcard> + <source> + <uri>ldap://ldap.example.com/cn=Babs%20Jensen,%20o=Babsco,%20c=US</uri> + </source> + </vcard> +</vcards> +XML +, + 'BEGIN:VCARD'."\n". + 'VERSION:4.0'."\n". + 'SOURCE:ldap://ldap.example.com/cn=Babs%20Jensen\,%20o=Babsco\,%20c=US'."\n". + 'END:VCARD'."\n" + ); + } + + /** + * Property: KIND. + */ + public function testRFC6350Section6_1_4() + { + $this->assertXMLReflexivelyEqualsToMimeDir( +<<<XML +<?xml version="1.0" encoding="UTF-8"?> +<vcards xmlns="urn:ietf:params:xml:ns:vcard-4.0"> + <vcard> + <kind> + <text>individual</text> + </kind> + </vcard> +</vcards> +XML +, + 'BEGIN:VCARD'."\n". + 'VERSION:4.0'."\n". + 'KIND:individual'."\n". + 'END:VCARD'."\n" + ); + } + + /** + * Property: FN. + */ + public function testRFC6350Section6_2_1() + { + $this->assertXMLReflexivelyEqualsToMimeDir( +<<<XML +<?xml version="1.0" encoding="UTF-8"?> +<vcards xmlns="urn:ietf:params:xml:ns:vcard-4.0"> + <vcard> + <fn> + <text>Mr. John Q. Public, Esq.</text> + </fn> + </vcard> +</vcards> +XML +, + 'BEGIN:VCARD'."\n". + 'VERSION:4.0'."\n". + 'FN:Mr. John Q. Public\, Esq.'."\n". + 'END:VCARD'."\n" + ); + } + + /** + * Property: N. + */ + public function testRFC6350Section6_2_2() + { + $this->assertXMLReflexivelyEqualsToMimeDir( +<<<XML +<?xml version="1.0" encoding="UTF-8"?> +<vcards xmlns="urn:ietf:params:xml:ns:vcard-4.0"> + <vcard> + <n> + <surname>Stevenson</surname> + <given>John</given> + <additional>Philip,Paul</additional> + <prefix>Dr.</prefix> + <suffix>Jr.,M.D.,A.C.P.</suffix> + </n> + </vcard> +</vcards> +XML +, + 'BEGIN:VCARD'."\n". + 'VERSION:4.0'."\n". + 'N:Stevenson;John;Philip\,Paul;Dr.;Jr.\,M.D.\,A.C.P.'."\n". + 'END:VCARD'."\n" + ); + } + + /** + * Property: NICKNAME. + */ + public function testRFC6350Section6_2_3() + { + $this->assertXMLReflexivelyEqualsToMimeDir( +<<<XML +<?xml version="1.0" encoding="UTF-8"?> +<vcards xmlns="urn:ietf:params:xml:ns:vcard-4.0"> + <vcard> + <nickname> + <text>Jim</text> + <text>Jimmie</text> + </nickname> + </vcard> +</vcards> +XML +, + 'BEGIN:VCARD'."\n". + 'VERSION:4.0'."\n". + 'NICKNAME:Jim,Jimmie'."\n". + 'END:VCARD'."\n" + ); + } + + /** + * Property: PHOTO. + */ + public function testRFC6350Section6_2_4() + { + $this->assertXMLReflexivelyEqualsToMimeDir( +<<<XML +<?xml version="1.0" encoding="UTF-8"?> +<vcards xmlns="urn:ietf:params:xml:ns:vcard-4.0"> + <vcard> + <photo> + <uri>http://www.example.com/pub/photos/jqpublic.gif</uri> + </photo> + </vcard> +</vcards> +XML +, + 'BEGIN:VCARD'."\n". + 'VERSION:4.0'."\n". + 'PHOTO:http://www.example.com/pub/photos/jqpublic.gif'."\n". + 'END:VCARD'."\n" + ); + } + + public function testRFC6350Section6_2_5() + { + $this->assertXMLReflexivelyEqualsToMimeDir( +<<<XML +<?xml version="1.0" encoding="UTF-8"?> +<vcards xmlns="urn:ietf:params:xml:ns:vcard-4.0"> + <vcard> + <bday> + <date-and-or-time>19531015T231000Z</date-and-or-time> + </bday> + </vcard> +</vcards> +XML +, + 'BEGIN:VCARD'."\n". + 'VERSION:4.0'."\n". + 'BDAY:19531015T231000Z'."\n". + 'END:VCARD'."\n" + ); + } + + public function testRFC6350Section6_2_6() + { + $this->assertXMLReflexivelyEqualsToMimeDir( +<<<XML +<?xml version="1.0" encoding="UTF-8"?> +<vcards xmlns="urn:ietf:params:xml:ns:vcard-4.0"> + <vcard> + <anniversary> + <date-and-or-time>19960415</date-and-or-time> + </anniversary> + </vcard> +</vcards> +XML +, + 'BEGIN:VCARD'."\n". + 'VERSION:4.0'."\n". + 'ANNIVERSARY:19960415'."\n". + 'END:VCARD'."\n" + ); + } + + /** + * Property: GENDER. + */ + public function testRFC6350Section6_2_7() + { + $this->assertXMLReflexivelyEqualsToMimeDir( +<<<XML +<?xml version="1.0" encoding="UTF-8"?> +<vcards xmlns="urn:ietf:params:xml:ns:vcard-4.0"> + <vcard> + <gender> + <sex>Jim</sex> + <text>Jimmie</text> + </gender> + </vcard> +</vcards> +XML +, + 'BEGIN:VCARD'."\n". + 'VERSION:4.0'."\n". + 'GENDER:Jim;Jimmie'."\n". + 'END:VCARD'."\n" + ); + } + + /** + * Property: ADR. + */ + public function testRFC6350Section6_3_1() + { + $this->assertXMLReflexivelyEqualsToMimeDir( +<<<XML +<?xml version="1.0" encoding="UTF-8"?> +<vcards xmlns="urn:ietf:params:xml:ns:vcard-4.0"> + <vcard> + <adr> + <pobox/> + <ext/> + <street>123 Main Street</street> + <locality>Any Town</locality> + <region>CA</region> + <code>91921-1234</code> + <country>U.S.A.</country> + </adr> + </vcard> +</vcards> +XML +, + 'BEGIN:VCARD'."\n". + 'VERSION:4.0'."\n". + 'ADR:;;123 Main Street;Any Town;CA;91921-1234;U.S.A.'."\n". + 'END:VCARD'."\n" + ); + } + + /** + * Property: TEL. + */ + public function testRFC6350Section6_4_1() + { + /* + * Quoting RFC: + * > Value type: By default, it is a single free-form text value (for + * > backward compatibility with vCard 3), but it SHOULD be reset to a + * > URI value. It is expected that the URI scheme will be "tel", as + * > specified in [RFC3966], but other schemes MAY be used. + * + * So first, we test xCard/URI to vCard/URI. + * Then, we test xCard/TEXT to vCard/TEXT to xCard/TEXT. + */ + $this->assertXMLEqualsToMimeDir( +<<<XML +<?xml version="1.0" encoding="UTF-8"?> +<vcards xmlns="urn:ietf:params:xml:ns:vcard-4.0"> + <vcard> + <tel> + <parameters> + <type> + <text>home</text> + </type> + </parameters> + <uri>tel:+33-01-23-45-67</uri> + </tel> + </vcard> +</vcards> +XML +, + 'BEGIN:VCARD'."\n". + 'VERSION:4.0'."\n". + 'TEL;TYPE=home:tel:+33-01-23-45-67'."\n". + 'END:VCARD'."\n" + ); + + $this->assertXMLReflexivelyEqualsToMimeDir( +<<<XML +<?xml version="1.0" encoding="UTF-8"?> +<vcards xmlns="urn:ietf:params:xml:ns:vcard-4.0"> + <vcard> + <tel> + <parameters> + <type> + <text>home</text> + </type> + </parameters> + <text>tel:+33-01-23-45-67</text> + </tel> + </vcard> +</vcards> +XML +, + 'BEGIN:VCARD'."\n". + 'VERSION:4.0'."\n". + 'TEL;TYPE=home:tel:+33-01-23-45-67'."\n". + 'END:VCARD'."\n" + ); + } + + /** + * Property: EMAIL. + */ + public function testRFC6350Section6_4_2() + { + $this->assertXMLReflexivelyEqualsToMimeDir( +<<<XML +<?xml version="1.0" encoding="UTF-8"?> +<vcards xmlns="urn:ietf:params:xml:ns:vcard-4.0"> + <vcard> + <email> + <parameters> + <type> + <text>work</text> + </type> + </parameters> + <text>jqpublic@xyz.example.com</text> + </email> + </vcard> +</vcards> +XML +, + 'BEGIN:VCARD'."\n". + 'VERSION:4.0'."\n". + 'EMAIL;TYPE=work:jqpublic@xyz.example.com'."\n". + 'END:VCARD'."\n" + ); + } + + /** + * Property: IMPP. + */ + public function testRFC6350Section6_4_3() + { + $this->assertXMLReflexivelyEqualsToMimeDir( +<<<XML +<?xml version="1.0" encoding="UTF-8"?> +<vcards xmlns="urn:ietf:params:xml:ns:vcard-4.0"> + <vcard> + <impp> + <parameters> + <pref> + <text>1</text> + </pref> + </parameters> + <uri>xmpp:alice@example.com</uri> + </impp> + </vcard> +</vcards> +XML +, + 'BEGIN:VCARD'."\n". + 'VERSION:4.0'."\n". + 'IMPP;PREF=1:xmpp:alice@example.com'."\n". + 'END:VCARD'."\n" + ); + } + + /** + * Property: LANG. + */ + public function testRFC6350Section6_4_4() + { + $this->assertXMLReflexivelyEqualsToMimeDir( +<<<XML +<?xml version="1.0" encoding="UTF-8"?> +<vcards xmlns="urn:ietf:params:xml:ns:vcard-4.0"> + <vcard> + <lang> + <parameters> + <type> + <text>work</text> + </type> + <pref> + <text>2</text> + </pref> + </parameters> + <language-tag>en</language-tag> + </lang> + </vcard> +</vcards> +XML +, + 'BEGIN:VCARD'."\n". + 'VERSION:4.0'."\n". + 'LANG;TYPE=work;PREF=2:en'."\n". + 'END:VCARD'."\n" + ); + } + + /** + * Property: TZ. + */ + public function testRFC6350Section6_5_1() + { + $this->assertXMLReflexivelyEqualsToMimeDir( +<<<XML +<?xml version="1.0" encoding="UTF-8"?> +<vcards xmlns="urn:ietf:params:xml:ns:vcard-4.0"> + <vcard> + <tz> + <text>Raleigh/North America</text> + </tz> + </vcard> +</vcards> +XML +, + 'BEGIN:VCARD'."\n". + 'VERSION:4.0'."\n". + 'TZ:Raleigh/North America'."\n". + 'END:VCARD'."\n" + ); + } + + /** + * Property: GEO. + */ + public function testRFC6350Section6_5_2() + { + $this->assertXMLEqualsToMimeDir( +<<<XML +<?xml version="1.0" encoding="UTF-8"?> +<vcards xmlns="urn:ietf:params:xml:ns:vcard-4.0"> + <vcard> + <geo> + <uri>geo:37.386013,-122.082932</uri> + </geo> + </vcard> +</vcards> +XML +, + 'BEGIN:VCARD'."\n". + 'VERSION:4.0'."\n". + 'GEO:geo:37.386013\,-122.082932'."\n". + 'END:VCARD'."\n" + ); + + $this->assertXMLReflexivelyEqualsToMimeDir( +<<<XML +<?xml version="1.0" encoding="UTF-8"?> +<vcards xmlns="urn:ietf:params:xml:ns:vcard-4.0"> + <vcard> + <geo> + <text>geo:37.386013,-122.082932</text> + </geo> + </vcard> +</vcards> +XML +, + 'BEGIN:VCARD'."\n". + 'VERSION:4.0'."\n". + 'GEO:geo:37.386013\,-122.082932'."\n". + 'END:VCARD'."\n" + ); + } + + /** + * Property: TITLE. + */ + public function testRFC6350Section6_6_1() + { + $this->assertXMLReflexivelyEqualsToMimeDir( +<<<XML +<?xml version="1.0" encoding="UTF-8"?> +<vcards xmlns="urn:ietf:params:xml:ns:vcard-4.0"> + <vcard> + <title> + <text>Research Scientist</text> + + + +XML +, + 'BEGIN:VCARD'."\n". + 'VERSION:4.0'."\n". + 'TITLE:Research Scientist'."\n". + 'END:VCARD'."\n" + ); + } + + /** + * Property: ROLE. + */ + public function testRFC6350Section6_6_2() + { + $this->assertXMLReflexivelyEqualsToMimeDir( +<< + + + + Project Leader + + + +XML +, + 'BEGIN:VCARD'."\n". + 'VERSION:4.0'."\n". + 'ROLE:Project Leader'."\n". + 'END:VCARD'."\n" + ); + } + + /** + * Property: LOGO. + */ + public function testRFC6350Section6_6_3() + { + $this->assertXMLReflexivelyEqualsToMimeDir( +<< + + + + http://www.example.com/pub/logos/abccorp.jpg + + + +XML +, + 'BEGIN:VCARD'."\n". + 'VERSION:4.0'."\n". + 'LOGO:http://www.example.com/pub/logos/abccorp.jpg'."\n". + 'END:VCARD'."\n" + ); + } + + /** + * Property: ORG. + */ + public function testRFC6350Section6_6_4() + { + $this->assertXMLReflexivelyEqualsToMimeDir( +<< + + + + ABC, Inc. + North American Division + Marketing + + + +XML +, + 'BEGIN:VCARD'."\n". + 'VERSION:4.0'."\n". + 'ORG:ABC\, Inc.;North American Division;Marketing'."\n". + 'END:VCARD'."\n" + ); + } + + /** + * Property: MEMBER. + */ + public function testRFC6350Section6_6_5() + { + $this->assertXMLReflexivelyEqualsToMimeDir( +<< + + + + urn:uuid:03a0e51f-d1aa-4385-8a53-e29025acd8af + + + +XML +, + 'BEGIN:VCARD'."\n". + 'VERSION:4.0'."\n". + 'MEMBER:urn:uuid:03a0e51f-d1aa-4385-8a53-e29025acd8af'."\n". + 'END:VCARD'."\n" + ); + + $this->assertXMLReflexivelyEqualsToMimeDir( +<< + + + + mailto:subscriber1@example.com + + + xmpp:subscriber2@example.com + + + sip:subscriber3@example.com + + + tel:+1-418-555-5555 + + + +XML +, + 'BEGIN:VCARD'."\n". + 'VERSION:4.0'."\n". + 'MEMBER:mailto:subscriber1@example.com'."\n". + 'MEMBER:xmpp:subscriber2@example.com'."\n". + 'MEMBER:sip:subscriber3@example.com'."\n". + 'MEMBER:tel:+1-418-555-5555'."\n". + 'END:VCARD'."\n" + ); + } + + /** + * Property: RELATED. + */ + public function testRFC6350Section6_6_6() + { + $this->assertXMLReflexivelyEqualsToMimeDir( +<< + + + + + + friend + + + urn:uuid:f81d4fae-7dec-11d0-a765-00a0c91e6bf6 + + + +XML +, + 'BEGIN:VCARD'."\n". + 'VERSION:4.0'."\n". + 'RELATED;TYPE=friend:urn:uuid:f81d4fae-7dec-11d0-a765-00a0c91e6bf6'."\n". + 'END:VCARD'."\n" + ); + } + + /** + * Property: CATEGORIES. + */ + public function testRFC6350Section6_7_1() + { + $this->assertXMLReflexivelyEqualsToMimeDir( +<< + + + + INTERNET + IETF + INDUSTRY + INFORMATION TECHNOLOGY + + + +XML +, + 'BEGIN:VCARD'."\n". + 'VERSION:4.0'."\n". + 'CATEGORIES:INTERNET,IETF,INDUSTRY,INFORMATION TECHNOLOGY'."\n". + 'END:VCARD'."\n" + ); + } + + /** + * Property: NOTE. + */ + public function testRFC6350Section6_7_2() + { + $this->assertXMLReflexivelyEqualsToMimeDir( +<< + + + + Foo, bar + + + +XML +, + 'BEGIN:VCARD'."\n". + 'VERSION:4.0'."\n". + 'NOTE:Foo\, bar'."\n". + 'END:VCARD'."\n" + ); + } + + /** + * Property: PRODID. + */ + public function testRFC6350Section6_7_3() + { + $this->assertXMLReflexivelyEqualsToMimeDir( +<< + + + + -//ONLINE DIRECTORY//NONSGML Version 1//EN + + + +XML +, + 'BEGIN:VCARD'."\n". + 'VERSION:4.0'."\n". + 'PRODID:-//ONLINE DIRECTORY//NONSGML Version 1//EN'."\n". + 'END:VCARD'."\n" + ); + } + + public function testRFC6350Section6_7_4() + { + $this->assertXMLReflexivelyEqualsToMimeDir( +<< + + + + 19951031T222710Z + + + +XML +, + 'BEGIN:VCARD'."\n". + 'VERSION:4.0'."\n". + 'REV:19951031T222710Z'."\n". + 'END:VCARD'."\n" + ); + } + + /** + * Property: SOUND. + */ + public function testRFC6350Section6_7_5() + { + $this->assertXMLEqualsToMimeDir( +<< + + + + CID:JOHNQPUBLIC.part8.19960229T080000.xyzMail@example.com + + + +XML +, + 'BEGIN:VCARD'."\n". + 'VERSION:4.0'."\n". + 'SOUND:CID:JOHNQPUBLIC.part8.19960229T080000.xyzMail@example.com'."\n". + 'END:VCARD'."\n" + ); + + $this->assertXMLReflexivelyEqualsToMimeDir( +<< + + + + CID:JOHNQPUBLIC.part8.19960229T080000.xyzMail@example.com + + + +XML +, + 'BEGIN:VCARD'."\n". + 'VERSION:4.0'."\n". + 'SOUND:CID:JOHNQPUBLIC.part8.19960229T080000.xyzMail@example.com'."\n". + 'END:VCARD'."\n" + ); + } + + /** + * Property: UID. + */ + public function testRFC6350Section6_7_6() + { + $this->assertXMLReflexivelyEqualsToMimeDir( +<< + + + + urn:uuid:f81d4fae-7dec-11d0-a765-00a0c91e6bf6 + + + +XML +, + 'BEGIN:VCARD'."\n". + 'VERSION:4.0'."\n". + 'UID:urn:uuid:f81d4fae-7dec-11d0-a765-00a0c91e6bf6'."\n". + 'END:VCARD'."\n" + ); + } + + /** + * Property: CLIENTPIDMAP. + */ + public function testRFC6350Section6_7_7() + { + $this->assertXMLReflexivelyEqualsToMimeDir( +<< + + + + 1 + urn:uuid:3df403f4-5924-4bb7-b077-3c711d9eb34b + + + +XML +, + 'BEGIN:VCARD'."\n". + 'VERSION:4.0'."\n". + 'CLIENTPIDMAP:1;urn:uuid:3df403f4-5924-4bb7-b077-3c711d9eb34b'."\n". + 'END:VCARD'."\n" + ); + } + + /** + * Property: URL. + */ + public function testRFC6350Section6_7_8() + { + $this->assertXMLReflexivelyEqualsToMimeDir( +<< + + + + http://example.org/restaurant.french/~chezchic.html + + + +XML +, + 'BEGIN:VCARD'."\n". + 'VERSION:4.0'."\n". + 'URL:http://example.org/restaurant.french/~chezchic.html'."\n". + 'END:VCARD'."\n" + ); + } + + /** + * Property: VERSION. + */ + public function testRFC6350Section6_7_9() + { + $this->assertXMLReflexivelyEqualsToMimeDir( +<< + + + +XML +, + 'BEGIN:VCARD'."\n". + 'VERSION:4.0'."\n". + 'END:VCARD'."\n" + ); + } + + /** + * Property: KEY. + */ + public function testRFC6350Section6_8_1() + { + $this->assertXMLReflexivelyEqualsToMimeDir( +<< + + + + + + application/pgp-keys + + + ftp://example.com/keys/jdoe + + + +XML +, + 'BEGIN:VCARD'."\n". + 'VERSION:4.0'."\n". + 'KEY;MEDIATYPE=application/pgp-keys:ftp://example.com/keys/jdoe'."\n". + 'END:VCARD'."\n" + ); + } + + /** + * Property: FBURL. + */ + public function testRFC6350Section6_9_1() + { + $this->assertXMLReflexivelyEqualsToMimeDir( +<< + + + + + + 1 + + + http://www.example.com/busy/janedoe + + + +XML +, + 'BEGIN:VCARD'."\n". + 'VERSION:4.0'."\n". + 'FBURL;PREF=1:http://www.example.com/busy/janedoe'."\n". + 'END:VCARD'."\n" + ); + } + + /** + * Property: CALADRURI. + */ + public function testRFC6350Section6_9_2() + { + $this->assertXMLReflexivelyEqualsToMimeDir( +<< + + + + http://example.com/calendar/jdoe + + + +XML +, + 'BEGIN:VCARD'."\n". + 'VERSION:4.0'."\n". + 'CALADRURI:http://example.com/calendar/jdoe'."\n". + 'END:VCARD'."\n" + ); + } + + /** + * Property: CALURI. + */ + public function testRFC6350Section6_9_3() + { + $this->assertXMLReflexivelyEqualsToMimeDir( +<< + + + + + + 1 + + + http://cal.example.com/calA + + + +XML +, + 'BEGIN:VCARD'."\n". + 'VERSION:4.0'."\n". + 'CALURI;PREF=1:http://cal.example.com/calA'."\n". + 'END:VCARD'."\n" + ); + } + + /** + * Property: CAPURI. + */ + public function testRFC6350SectionA_3() + { + $this->assertXMLReflexivelyEqualsToMimeDir( +<< + + + + http://cap.example.com/capA + + + +XML +, + 'BEGIN:VCARD'."\n". + 'VERSION:4.0'."\n". + 'CAPURI:http://cap.example.com/capA'."\n". + 'END:VCARD'."\n" + ); + } + + /** + * Check this equality: + * XML -> object model -> MIME Dir. + */ + protected function assertXMLEqualsToMimeDir($xml, $mimedir) + { + $component = VObject\Reader::readXML($xml); + $this->assertVObjectEqualsVObject($mimedir, $component); + } + + /** + * Check this (reflexive) equality: + * XML -> object model -> MIME Dir -> object model -> XML. + */ + protected function assertXMLReflexivelyEqualsToMimeDir($xml, $mimedir) + { + $this->assertXMLEqualsToMimeDir($xml, $mimedir); + + $component = VObject\Reader::read($mimedir); + $this->assertXmlStringEqualsXmlString($xml, VObject\Writer::writeXML($component)); + } +} diff --git a/vendor/sabre/vobject/tests/VObject/Property/BinaryTest.php b/vendor/sabre/vobject/tests/VObject/Property/BinaryTest.php new file mode 100644 index 000000000..a6ea701ba --- /dev/null +++ b/vendor/sabre/vobject/tests/VObject/Property/BinaryTest.php @@ -0,0 +1,18 @@ + '3.0']); + $vcard->add('PHOTO', ['a', 'b']); + } +} diff --git a/vendor/sabre/vobject/tests/VObject/Property/BooleanTest.php b/vendor/sabre/vobject/tests/VObject/Property/BooleanTest.php new file mode 100644 index 000000000..ad2ccbcd7 --- /dev/null +++ b/vendor/sabre/vobject/tests/VObject/Property/BooleanTest.php @@ -0,0 +1,21 @@ +assertTrue($vcard->{'X-AWESOME'}->getValue()); + $this->assertFalse($vcard->{'X-SUCKS'}->getValue()); + + $this->assertEquals('BOOLEAN', $vcard->{'X-AWESOME'}->getValueType()); + $this->assertEquals($input, $vcard->serialize()); + } +} diff --git a/vendor/sabre/vobject/tests/VObject/Property/CompoundTest.php b/vendor/sabre/vobject/tests/VObject/Property/CompoundTest.php new file mode 100644 index 000000000..bfa1ed64b --- /dev/null +++ b/vendor/sabre/vobject/tests/VObject/Property/CompoundTest.php @@ -0,0 +1,48 @@ +createProperty('ORG'); + $elem->setParts($arr); + + $this->assertEquals('ABC\, Inc.;North American Division;Marketing\;Sales', $elem->getValue()); + $this->assertEquals(3, count($elem->getParts())); + $parts = $elem->getParts(); + $this->assertEquals('Marketing;Sales', $parts[2]); + } + + public function testGetParts() + { + $str = 'ABC\, Inc.;North American Division;Marketing\;Sales'; + + $vcard = new VCard(); + $elem = $vcard->createProperty('ORG'); + $elem->setRawMimeDirValue($str); + + $this->assertEquals(3, count($elem->getParts())); + $parts = $elem->getParts(); + $this->assertEquals('Marketing;Sales', $parts[2]); + } + + public function testGetPartsNull() + { + $vcard = new VCard(); + $elem = $vcard->createProperty('ORG', null); + + $this->assertEquals(0, count($elem->getParts())); + } +} diff --git a/vendor/sabre/vobject/tests/VObject/Property/FloatTest.php b/vendor/sabre/vobject/tests/VObject/Property/FloatTest.php new file mode 100644 index 000000000..c5237c47b --- /dev/null +++ b/vendor/sabre/vobject/tests/VObject/Property/FloatTest.php @@ -0,0 +1,29 @@ +parse($input); + + $this->assertInstanceOf('Sabre\VObject\Property\FloatValue', $result->{'X-FLOAT'}); + + $this->assertEquals([ + 0.234, + 1.245, + ], $result->{'X-FLOAT'}->getParts()); + + $this->assertEquals( + $input, + $result->serialize() + ); + } +} diff --git a/vendor/sabre/vobject/tests/VObject/Property/ICalendar/CalAddressTest.php b/vendor/sabre/vobject/tests/VObject/Property/ICalendar/CalAddressTest.php new file mode 100644 index 000000000..a907daf5c --- /dev/null +++ b/vendor/sabre/vobject/tests/VObject/Property/ICalendar/CalAddressTest.php @@ -0,0 +1,31 @@ +add('ATTENDEE', $input); + + $this->assertEquals( + $expected, + $property->getNormalizedValue() + ); + } + + public function values() + { + return [ + ['mailto:a@b.com', 'mailto:a@b.com'], + ['mailto:a@b.com', 'MAILTO:a@b.com'], + ['/foo/bar', '/foo/bar'], + ]; + } +} diff --git a/vendor/sabre/vobject/tests/VObject/Property/ICalendar/DateTimeTest.php b/vendor/sabre/vobject/tests/VObject/Property/ICalendar/DateTimeTest.php new file mode 100644 index 000000000..33525ff33 --- /dev/null +++ b/vendor/sabre/vobject/tests/VObject/Property/ICalendar/DateTimeTest.php @@ -0,0 +1,348 @@ +vcal = new VCalendar(); + } + + public function testSetDateTime() + { + $tz = new \DateTimeZone('Europe/Amsterdam'); + $dt = new \DateTime('1985-07-04 01:30:00', $tz); + $dt->setTimeZone($tz); + + $elem = $this->vcal->createProperty('DTSTART'); + $elem->setDateTime($dt); + + $this->assertEquals('19850704T013000', (string) $elem); + $this->assertEquals('Europe/Amsterdam', (string) $elem['TZID']); + $this->assertNull($elem['VALUE']); + + $this->assertTrue($elem->hasTime()); + } + + public function testSetDateTimeLOCAL() + { + $tz = new \DateTimeZone('Europe/Amsterdam'); + $dt = new \DateTime('1985-07-04 01:30:00', $tz); + $dt->setTimeZone($tz); + + $elem = $this->vcal->createProperty('DTSTART'); + $elem->setDateTime($dt, $isFloating = true); + + $this->assertEquals('19850704T013000', (string) $elem); + $this->assertNull($elem['TZID']); + + $this->assertTrue($elem->hasTime()); + } + + public function testSetDateTimeUTC() + { + $tz = new \DateTimeZone('GMT'); + $dt = new \DateTime('1985-07-04 01:30:00', $tz); + $dt->setTimeZone($tz); + + $elem = $this->vcal->createProperty('DTSTART'); + $elem->setDateTime($dt); + + $this->assertEquals('19850704T013000Z', (string) $elem); + $this->assertNull($elem['TZID']); + + $this->assertTrue($elem->hasTime()); + } + + public function testSetDateTimeFromUnixTimestamp() + { + // When initialized from a Unix timestamp, the timezone is set to "+00:00". + $dt = new \DateTime('@489288600'); + + $elem = $this->vcal->createProperty('DTSTART'); + $elem->setDateTime($dt); + + $this->assertEquals('19850704T013000Z', (string) $elem); + $this->assertNull($elem['TZID']); + + $this->assertTrue($elem->hasTime()); + } + + public function testSetDateTimeLOCALTZ() + { + $tz = new \DateTimeZone('Europe/Amsterdam'); + $dt = new \DateTime('1985-07-04 01:30:00', $tz); + $dt->setTimeZone($tz); + + $elem = $this->vcal->createProperty('DTSTART'); + $elem->setDateTime($dt); + + $this->assertEquals('19850704T013000', (string) $elem); + $this->assertEquals('Europe/Amsterdam', (string) $elem['TZID']); + + $this->assertTrue($elem->hasTime()); + } + + public function testSetDateTimeDATE() + { + $tz = new \DateTimeZone('Europe/Amsterdam'); + $dt = new \DateTime('1985-07-04 01:30:00', $tz); + $dt->setTimeZone($tz); + + $elem = $this->vcal->createProperty('DTSTART'); + $elem['VALUE'] = 'DATE'; + $elem->setDateTime($dt); + + $this->assertEquals('19850704', (string) $elem); + $this->assertNull($elem['TZID']); + $this->assertEquals('DATE', (string) $elem['VALUE']); + + $this->assertFalse($elem->hasTime()); + } + + public function testSetValue() + { + $tz = new \DateTimeZone('Europe/Amsterdam'); + $dt = new \DateTime('1985-07-04 01:30:00', $tz); + $dt->setTimeZone($tz); + + $elem = $this->vcal->createProperty('DTSTART'); + $elem->setValue($dt); + + $this->assertEquals('19850704T013000', (string) $elem); + $this->assertEquals('Europe/Amsterdam', (string) $elem['TZID']); + $this->assertNull($elem['VALUE']); + + $this->assertTrue($elem->hasTime()); + } + + public function testSetValueArray() + { + $tz = new \DateTimeZone('Europe/Amsterdam'); + $dt1 = new \DateTime('1985-07-04 01:30:00', $tz); + $dt2 = new \DateTime('1985-07-04 02:30:00', $tz); + $dt1->setTimeZone($tz); + $dt2->setTimeZone($tz); + + $elem = $this->vcal->createProperty('DTSTART'); + $elem->setValue([$dt1, $dt2]); + + $this->assertEquals('19850704T013000,19850704T023000', (string) $elem); + $this->assertEquals('Europe/Amsterdam', (string) $elem['TZID']); + $this->assertNull($elem['VALUE']); + + $this->assertTrue($elem->hasTime()); + } + + public function testSetParts() + { + $tz = new \DateTimeZone('Europe/Amsterdam'); + $dt1 = new \DateTime('1985-07-04 01:30:00', $tz); + $dt2 = new \DateTime('1985-07-04 02:30:00', $tz); + $dt1->setTimeZone($tz); + $dt2->setTimeZone($tz); + + $elem = $this->vcal->createProperty('DTSTART'); + $elem->setParts([$dt1, $dt2]); + + $this->assertEquals('19850704T013000,19850704T023000', (string) $elem); + $this->assertEquals('Europe/Amsterdam', (string) $elem['TZID']); + $this->assertNull($elem['VALUE']); + + $this->assertTrue($elem->hasTime()); + } + + public function testSetPartsStrings() + { + $dt1 = '19850704T013000Z'; + $dt2 = '19850704T023000Z'; + + $elem = $this->vcal->createProperty('DTSTART'); + $elem->setParts([$dt1, $dt2]); + + $this->assertEquals('19850704T013000Z,19850704T023000Z', (string) $elem); + $this->assertNull($elem['VALUE']); + + $this->assertTrue($elem->hasTime()); + } + + public function testGetDateTimeCached() + { + $tz = new \DateTimeZone('Europe/Amsterdam'); + $dt = new \DateTimeImmutable('1985-07-04 01:30:00', $tz); + $dt->setTimeZone($tz); + + $elem = $this->vcal->createProperty('DTSTART'); + $elem->setDateTime($dt); + + $this->assertEquals($elem->getDateTime(), $dt); + } + + public function testGetDateTimeDateNULL() + { + $elem = $this->vcal->createProperty('DTSTART'); + $dt = $elem->getDateTime(); + + $this->assertNull($dt); + } + + public function testGetDateTimeDateDATE() + { + $elem = $this->vcal->createProperty('DTSTART', '19850704'); + $dt = $elem->getDateTime(); + + $this->assertInstanceOf('DateTimeImmutable', $dt); + $this->assertEquals('1985-07-04 00:00:00', $dt->format('Y-m-d H:i:s')); + } + + public function testGetDateTimeDateDATEReferenceTimeZone() + { + $elem = $this->vcal->createProperty('DTSTART', '19850704'); + + $tz = new \DateTimeZone('America/Toronto'); + $dt = $elem->getDateTime($tz); + $dt = $dt->setTimeZone(new \DateTimeZone('UTC')); + + $this->assertInstanceOf('DateTimeImmutable', $dt); + $this->assertEquals('1985-07-04 04:00:00', $dt->format('Y-m-d H:i:s')); + } + + public function testGetDateTimeDateFloating() + { + $elem = $this->vcal->createProperty('DTSTART', '19850704T013000'); + $dt = $elem->getDateTime(); + + $this->assertInstanceOf('DateTimeImmutable', $dt); + $this->assertEquals('1985-07-04 01:30:00', $dt->format('Y-m-d H:i:s')); + } + + public function testGetDateTimeDateFloatingReferenceTimeZone() + { + $elem = $this->vcal->createProperty('DTSTART', '19850704T013000'); + + $tz = new \DateTimeZone('America/Toronto'); + $dt = $elem->getDateTime($tz); + $dt = $dt->setTimeZone(new \DateTimeZone('UTC')); + + $this->assertInstanceOf('DateTimeInterface', $dt); + $this->assertEquals('1985-07-04 05:30:00', $dt->format('Y-m-d H:i:s')); + } + + public function testGetDateTimeDateUTC() + { + $elem = $this->vcal->createProperty('DTSTART', '19850704T013000Z'); + $dt = $elem->getDateTime(); + + $this->assertInstanceOf('DateTimeImmutable', $dt); + $this->assertEquals('1985-07-04 01:30:00', $dt->format('Y-m-d H:i:s')); + $this->assertEquals('UTC', $dt->getTimeZone()->getName()); + } + + public function testGetDateTimeDateLOCALTZ() + { + $elem = $this->vcal->createProperty('DTSTART', '19850704T013000'); + $elem['TZID'] = 'Europe/Amsterdam'; + + $dt = $elem->getDateTime(); + + $this->assertInstanceOf('DateTimeImmutable', $dt); + $this->assertEquals('1985-07-04 01:30:00', $dt->format('Y-m-d H:i:s')); + $this->assertEquals('Europe/Amsterdam', $dt->getTimeZone()->getName()); + } + + /** + * @expectedException \Sabre\VObject\InvalidDataException + */ + public function testGetDateTimeDateInvalid() + { + $elem = $this->vcal->createProperty('DTSTART', 'bla'); + $dt = $elem->getDateTime(); + } + + public function testGetDateTimeWeirdTZ() + { + $elem = $this->vcal->createProperty('DTSTART', '19850704T013000'); + $elem['TZID'] = '/freeassociation.sourceforge.net/Tzfile/Europe/Amsterdam'; + + $event = $this->vcal->createComponent('VEVENT'); + $event->add($elem); + + $timezone = $this->vcal->createComponent('VTIMEZONE'); + $timezone->TZID = '/freeassociation.sourceforge.net/Tzfile/Europe/Amsterdam'; + $timezone->{'X-LIC-LOCATION'} = 'Europe/Amsterdam'; + + $this->vcal->add($event); + $this->vcal->add($timezone); + + $dt = $elem->getDateTime(); + + $this->assertInstanceOf('DateTimeImmutable', $dt); + $this->assertEquals('1985-07-04 01:30:00', $dt->format('Y-m-d H:i:s')); + $this->assertEquals('Europe/Amsterdam', $dt->getTimeZone()->getName()); + } + + public function testGetDateTimeBadTimeZone() + { + $default = date_default_timezone_get(); + date_default_timezone_set('Canada/Eastern'); + + $elem = $this->vcal->createProperty('DTSTART', '19850704T013000'); + $elem['TZID'] = 'Moon'; + + $event = $this->vcal->createComponent('VEVENT'); + $event->add($elem); + + $timezone = $this->vcal->createComponent('VTIMEZONE'); + $timezone->TZID = 'Moon'; + $timezone->{'X-LIC-LOCATION'} = 'Moon'; + + $this->vcal->add($event); + $this->vcal->add($timezone); + + $dt = $elem->getDateTime(); + + $this->assertInstanceOf('DateTimeImmutable', $dt); + $this->assertEquals('1985-07-04 01:30:00', $dt->format('Y-m-d H:i:s')); + $this->assertEquals('Canada/Eastern', $dt->getTimeZone()->getName()); + date_default_timezone_set($default); + } + + public function testUpdateValueParameter() + { + $dtStart = $this->vcal->createProperty('DTSTART', new \DateTime('2013-06-07 15:05:00')); + $dtStart['VALUE'] = 'DATE'; + + $this->assertEquals("DTSTART;VALUE=DATE:20130607\r\n", $dtStart->serialize()); + } + + public function testValidate() + { + $exDate = $this->vcal->createProperty('EXDATE', '-00011130T143000Z'); + $messages = $exDate->validate(); + $this->assertEquals(1, count($messages)); + $this->assertEquals(3, $messages[0]['level']); + } + + /** + * This issue was discovered on the sabredav mailing list. + */ + public function testCreateDatePropertyThroughAdd() + { + $vcal = new VCalendar(); + $vevent = $vcal->add('VEVENT'); + + $dtstart = $vevent->add( + 'DTSTART', + new \DateTime('2014-03-07'), + ['VALUE' => 'DATE'] + ); + + $this->assertEquals("DTSTART;VALUE=DATE:20140307\r\n", $dtstart->serialize()); + } +} diff --git a/vendor/sabre/vobject/tests/VObject/Property/ICalendar/DurationTest.php b/vendor/sabre/vobject/tests/VObject/Property/ICalendar/DurationTest.php new file mode 100644 index 000000000..2003ad6d2 --- /dev/null +++ b/vendor/sabre/vobject/tests/VObject/Property/ICalendar/DurationTest.php @@ -0,0 +1,20 @@ +add('VEVENT', ['DURATION' => ['PT1H']]); + + $this->assertEquals( + new \DateInterval('PT1H'), + $event->{'DURATION'}->getDateInterval() + ); + } +} diff --git a/vendor/sabre/vobject/tests/VObject/Property/ICalendar/RecurTest.php b/vendor/sabre/vobject/tests/VObject/Property/ICalendar/RecurTest.php new file mode 100644 index 000000000..818840605 --- /dev/null +++ b/vendor/sabre/vobject/tests/VObject/Property/ICalendar/RecurTest.php @@ -0,0 +1,432 @@ +add('RRULE', 'FREQ=Daily'); + + $this->assertInstanceOf('Sabre\VObject\Property\ICalendar\Recur', $recur); + + $this->assertEquals(['FREQ' => 'DAILY'], $recur->getParts()); + $recur->setParts(['freq' => 'MONTHLY']); + + $this->assertEquals(['FREQ' => 'MONTHLY'], $recur->getParts()); + } + + /** + * @expectedException \InvalidArgumentException + */ + public function testSetValueBadVal() + { + $vcal = new VCalendar(); + $recur = $vcal->add('RRULE', 'FREQ=Daily'); + $recur->setValue(new \Exception()); + } + + public function testSetValueWithCount() + { + $vcal = new VCalendar(); + $recur = $vcal->add('RRULE', 'FREQ=Daily'); + $recur->setValue(['COUNT' => 3]); + $this->assertEquals($recur->getParts()['COUNT'], 3); + } + + public function testGetJSONWithCount() + { + $input = 'BEGIN:VCALENDAR +BEGIN:VEVENT +UID:908d53c0-e1a3-4883-b69f-530954d6bd62 +TRANSP:OPAQUE +DTSTART;TZID=Europe/Berlin:20160301T150000 +DTEND;TZID=Europe/Berlin:20160301T170000 +SUMMARY:test +RRULE:FREQ=DAILY;COUNT=3 +ORGANIZER;CN=robert pipo:mailto:robert@example.org +END:VEVENT +END:VCALENDAR +'; + + $vcal = Reader::read($input); + $rrule = $vcal->VEVENT->RRULE; + $count = $rrule->getJsonValue()[0]['count']; + $this->assertTrue(is_int($count)); + $this->assertEquals(3, $count); + } + + public function testSetSubParts() + { + $vcal = new VCalendar(); + $recur = $vcal->add('RRULE', ['FREQ' => 'DAILY', 'BYDAY' => 'mo,tu', 'BYMONTH' => [0, 1]]); + + $this->assertEquals([ + 'FREQ' => 'DAILY', + 'BYDAY' => ['MO', 'TU'], + 'BYMONTH' => [0, 1], + ], $recur->getParts()); + } + + public function testGetJSONWithUntil() + { + $input = 'BEGIN:VCALENDAR +BEGIN:VEVENT +UID:908d53c0-e1a3-4883-b69f-530954d6bd62 +TRANSP:OPAQUE +DTSTART;TZID=Europe/Berlin:20160301T150000 +DTEND;TZID=Europe/Berlin:20160301T170000 +SUMMARY:test +RRULE:FREQ=DAILY;UNTIL=20160305T230000Z +ORGANIZER;CN=robert pipo:mailto:robert@example.org +END:VEVENT +END:VCALENDAR +'; + + $vcal = Reader::read($input); + $rrule = $vcal->VEVENT->RRULE; + $untilJsonString = $rrule->getJsonValue()[0]['until']; + $this->assertEquals('2016-03-05T23:00:00Z', $untilJsonString); + } + + public function testValidateStripEmpties() + { + $input = 'BEGIN:VCALENDAR +VERSION:2.0 +PRODID:foobar +BEGIN:VEVENT +UID:908d53c0-e1a3-4883-b69f-530954d6bd62 +TRANSP:OPAQUE +DTSTART;TZID=Europe/Berlin:20160301T150000 +DTEND;TZID=Europe/Berlin:20160301T170000 +SUMMARY:test +RRULE:FREQ=DAILY;BYMONTH=;UNTIL=20160305T230000Z +ORGANIZER;CN=robert pipo:mailto:robert@example.org +DTSTAMP:20160312T183800Z +END:VEVENT +END:VCALENDAR +'; + + $vcal = Reader::read($input); + $this->assertEquals( + 1, + count($vcal->validate()) + ); + $this->assertEquals( + 1, + count($vcal->validate($vcal::REPAIR)) + ); + + $expected = 'BEGIN:VCALENDAR +VERSION:2.0 +PRODID:foobar +BEGIN:VEVENT +UID:908d53c0-e1a3-4883-b69f-530954d6bd62 +TRANSP:OPAQUE +DTSTART;TZID=Europe/Berlin:20160301T150000 +DTEND;TZID=Europe/Berlin:20160301T170000 +SUMMARY:test +RRULE:FREQ=DAILY;UNTIL=20160305T230000Z +ORGANIZER;CN=robert pipo:mailto:robert@example.org +DTSTAMP:20160312T183800Z +END:VEVENT +END:VCALENDAR +'; + + $this->assertVObjectEqualsVObject( + $expected, + $vcal + ); + } + + public function testValidateStripNoFreq() + { + $input = 'BEGIN:VCALENDAR +VERSION:2.0 +PRODID:foobar +BEGIN:VEVENT +UID:908d53c0-e1a3-4883-b69f-530954d6bd62 +TRANSP:OPAQUE +DTSTART;TZID=Europe/Berlin:20160301T150000 +DTEND;TZID=Europe/Berlin:20160301T170000 +SUMMARY:test +RRULE:UNTIL=20160305T230000Z +ORGANIZER;CN=robert pipo:mailto:robert@example.org +DTSTAMP:20160312T183800Z +END:VEVENT +END:VCALENDAR +'; + + $vcal = Reader::read($input); + $this->assertEquals( + 1, + count($vcal->validate()) + ); + $this->assertEquals( + 1, + count($vcal->validate($vcal::REPAIR)) + ); + + $expected = 'BEGIN:VCALENDAR +VERSION:2.0 +PRODID:foobar +BEGIN:VEVENT +UID:908d53c0-e1a3-4883-b69f-530954d6bd62 +TRANSP:OPAQUE +DTSTART;TZID=Europe/Berlin:20160301T150000 +DTEND;TZID=Europe/Berlin:20160301T170000 +SUMMARY:test +ORGANIZER;CN=robert pipo:mailto:robert@example.org +DTSTAMP:20160312T183800Z +END:VEVENT +END:VCALENDAR +'; + + $this->assertVObjectEqualsVObject( + $expected, + $vcal + ); + } + + public function testValidateInvalidByMonthRruleWithRepair() + { + $calendar = new VCalendar(); + $property = $calendar->createProperty('RRULE', 'FREQ=YEARLY;COUNT=6;BYMONTHDAY=24;BYMONTH=0'); + $result = $property->validate(Node::REPAIR); + + $this->assertCount(1, $result); + $this->assertEquals('BYMONTH in RRULE must have value(s) between 1 and 12!', $result[0]['message']); + $this->assertEquals(1, $result[0]['level']); + $this->assertEquals('FREQ=YEARLY;COUNT=6;BYMONTHDAY=24', $property->getValue()); + } + + public function testValidateInvalidByMonthRruleWithoutRepair() + { + $calendar = new VCalendar(); + $property = $calendar->createProperty('RRULE', 'FREQ=YEARLY;COUNT=6;BYMONTHDAY=24;BYMONTH=0'); + $result = $property->validate(); + + $this->assertCount(1, $result); + $this->assertEquals('BYMONTH in RRULE must have value(s) between 1 and 12!', $result[0]['message']); + $this->assertEquals(3, $result[0]['level']); + $this->assertEquals('FREQ=YEARLY;COUNT=6;BYMONTHDAY=24;BYMONTH=0', $property->getValue()); + } + + public function testValidateInvalidByMonthRruleWithRepair2() + { + $calendar = new VCalendar(); + $property = $calendar->createProperty('RRULE', 'FREQ=YEARLY;COUNT=6;BYMONTHDAY=24;BYMONTH=bla'); + $result = $property->validate(Node::REPAIR); + + $this->assertCount(1, $result); + $this->assertEquals('BYMONTH in RRULE must have value(s) between 1 and 12!', $result[0]['message']); + $this->assertEquals(1, $result[0]['level']); + $this->assertEquals('FREQ=YEARLY;COUNT=6;BYMONTHDAY=24', $property->getValue()); + } + + public function testValidateInvalidByMonthRruleWithoutRepair2() + { + $calendar = new VCalendar(); + $property = $calendar->createProperty('RRULE', 'FREQ=YEARLY;COUNT=6;BYMONTHDAY=24;BYMONTH=bla'); + $result = $property->validate(); + + $this->assertCount(1, $result); + $this->assertEquals('BYMONTH in RRULE must have value(s) between 1 and 12!', $result[0]['message']); + $this->assertEquals(3, $result[0]['level']); + // Without repair the invalid BYMONTH is still there, but the value is changed to uppercase + $this->assertEquals('FREQ=YEARLY;COUNT=6;BYMONTHDAY=24;BYMONTH=BLA', $property->getValue()); + } + + public function testValidateInvalidByMonthRruleValue14WithRepair() + { + $calendar = new VCalendar(); + $property = $calendar->createProperty('RRULE', 'FREQ=YEARLY;COUNT=6;BYMONTHDAY=24;BYMONTH=14'); + $result = $property->validate(Node::REPAIR); + + $this->assertCount(1, $result); + $this->assertEquals('BYMONTH in RRULE must have value(s) between 1 and 12!', $result[0]['message']); + $this->assertEquals(1, $result[0]['level']); + $this->assertEquals('FREQ=YEARLY;COUNT=6;BYMONTHDAY=24', $property->getValue()); + } + + public function testValidateInvalidByMonthRruleMultipleWithRepair() + { + $calendar = new VCalendar(); + $property = $calendar->createProperty('RRULE', 'FREQ=YEARLY;COUNT=6;BYMONTHDAY=24;BYMONTH=0,1,2,3,4,14'); + $result = $property->validate(Node::REPAIR); + + $this->assertCount(2, $result); + $this->assertEquals('BYMONTH in RRULE must have value(s) between 1 and 12!', $result[0]['message']); + $this->assertEquals(1, $result[0]['level']); + $this->assertEquals('BYMONTH in RRULE must have value(s) between 1 and 12!', $result[1]['message']); + $this->assertEquals(1, $result[1]['level']); + $this->assertEquals('FREQ=YEARLY;COUNT=6;BYMONTHDAY=24;BYMONTH=1,2,3,4', $property->getValue()); + } + + public function testValidateOneOfManyInvalidByMonthRruleWithRepair() + { + $calendar = new VCalendar(); + $property = $calendar->createProperty('RRULE', 'FREQ=YEARLY;COUNT=6;BYMONTHDAY=24;BYMONTH=bla,3,foo'); + $result = $property->validate(Node::REPAIR); + + $this->assertCount(2, $result); + $this->assertEquals('BYMONTH in RRULE must have value(s) between 1 and 12!', $result[0]['message']); + $this->assertEquals(1, $result[0]['level']); + $this->assertEquals('BYMONTH in RRULE must have value(s) between 1 and 12!', $result[1]['message']); + $this->assertEquals(1, $result[1]['level']); + $this->assertEquals('FREQ=YEARLY;COUNT=6;BYMONTHDAY=24;BYMONTH=3', $property->getValue()); + } + + public function testValidateValidByMonthRrule() + { + $calendar = new VCalendar(); + $property = $calendar->createProperty('RRULE', 'FREQ=YEARLY;COUNT=6;BYMONTHDAY=24;BYMONTH=2,3'); + $this->assertEquals('FREQ=YEARLY;COUNT=6;BYMONTHDAY=24;BYMONTH=2,3', $property->getValue()); + } + + /** + * test for issue #336. + */ + public function testValidateRruleBySecondZero() + { + $calendar = new VCalendar(); + $property = $calendar->createProperty('RRULE', 'FREQ=DAILY;BYHOUR=10;BYMINUTE=30;BYSECOND=0;UNTIL=20150616T153000Z'); + $result = $property->validate(Node::REPAIR); + + // There should be 0 warnings and the value should be unchanged + $this->assertEmpty($result); + $this->assertEquals('FREQ=DAILY;BYHOUR=10;BYMINUTE=30;BYSECOND=0;UNTIL=20150616T153000Z', $property->getValue()); + } + + public function testValidateValidByWeekNoWithRepair() + { + $calendar = new VCalendar(); + $property = $calendar->createProperty('RRULE', 'FREQ=YEARLY;COUNT=6;BYWEEKNO=11'); + $result = $property->validate(Node::REPAIR); + + $this->assertCount(0, $result); + $this->assertEquals('FREQ=YEARLY;COUNT=6;BYWEEKNO=11', $property->getValue()); + } + + public function testValidateInvalidByWeekNoWithRepair() + { + $calendar = new VCalendar(); + $property = $calendar->createProperty('RRULE', 'FREQ=YEARLY;COUNT=6;BYWEEKNO=55;BYDAY=WE'); + $result = $property->validate(Node::REPAIR); + + $this->assertCount(1, $result); + $this->assertEquals('BYWEEKNO in RRULE must have value(s) from -53 to -1, or 1 to 53!', $result[0]['message']); + $this->assertEquals(1, $result[0]['level']); + $this->assertEquals('FREQ=YEARLY;COUNT=6;BYDAY=WE', $property->getValue()); + } + + public function testValidateMultipleInvalidByWeekNoWithRepair() + { + $calendar = new VCalendar(); + $property = $calendar->createProperty('RRULE', 'FREQ=YEARLY;COUNT=6;BYWEEKNO=55,2,-80;BYDAY=WE'); + $result = $property->validate(Node::REPAIR); + + $this->assertCount(2, $result); + $this->assertEquals('BYWEEKNO in RRULE must have value(s) from -53 to -1, or 1 to 53!', $result[0]['message']); + $this->assertEquals(1, $result[0]['level']); + $this->assertEquals('BYWEEKNO in RRULE must have value(s) from -53 to -1, or 1 to 53!', $result[1]['message']); + $this->assertEquals(1, $result[1]['level']); + $this->assertEquals('FREQ=YEARLY;COUNT=6;BYWEEKNO=2;BYDAY=WE', $property->getValue()); + } + + public function testValidateAllInvalidByWeekNoWithRepair() + { + $calendar = new VCalendar(); + $property = $calendar->createProperty('RRULE', 'FREQ=YEARLY;COUNT=6;BYWEEKNO=55,-80;BYDAY=WE'); + $result = $property->validate(Node::REPAIR); + + $this->assertCount(2, $result); + $this->assertEquals('BYWEEKNO in RRULE must have value(s) from -53 to -1, or 1 to 53!', $result[0]['message']); + $this->assertEquals(1, $result[0]['level']); + $this->assertEquals('BYWEEKNO in RRULE must have value(s) from -53 to -1, or 1 to 53!', $result[1]['message']); + $this->assertEquals(1, $result[1]['level']); + $this->assertEquals('FREQ=YEARLY;COUNT=6;BYDAY=WE', $property->getValue()); + } + + public function testValidateInvalidByWeekNoWithoutRepair() + { + $calendar = new VCalendar(); + $property = $calendar->createProperty('RRULE', 'FREQ=YEARLY;COUNT=6;BYWEEKNO=55;BYDAY=WE'); + $result = $property->validate(); + + $this->assertCount(1, $result); + $this->assertEquals('BYWEEKNO in RRULE must have value(s) from -53 to -1, or 1 to 53!', $result[0]['message']); + $this->assertEquals(3, $result[0]['level']); + $this->assertEquals('FREQ=YEARLY;COUNT=6;BYWEEKNO=55;BYDAY=WE', $property->getValue()); + } + + public function testValidateValidByYearDayWithRepair() + { + $calendar = new VCalendar(); + $property = $calendar->createProperty('RRULE', 'FREQ=YEARLY;COUNT=6;BYYEARDAY=119'); + $result = $property->validate(Node::REPAIR); + + $this->assertCount(0, $result); + $this->assertEquals('FREQ=YEARLY;COUNT=6;BYYEARDAY=119', $property->getValue()); + } + + public function testValidateInvalidByYearDayWithRepair() + { + $calendar = new VCalendar(); + $property = $calendar->createProperty('RRULE', 'FREQ=YEARLY;COUNT=6;BYYEARDAY=367;BYDAY=WE'); + $result = $property->validate(Node::REPAIR); + + $this->assertCount(1, $result); + $this->assertEquals('BYYEARDAY in RRULE must have value(s) from -366 to -1, or 1 to 366!', $result[0]['message']); + $this->assertEquals(1, $result[0]['level']); + $this->assertEquals('FREQ=YEARLY;COUNT=6;BYDAY=WE', $property->getValue()); + } + + public function testValidateMultipleInvalidByYearDayWithRepair() + { + $calendar = new VCalendar(); + $property = $calendar->createProperty('RRULE', 'FREQ=YEARLY;COUNT=6;BYYEARDAY=380,2,-390;BYDAY=WE'); + $result = $property->validate(Node::REPAIR); + + $this->assertCount(2, $result); + $this->assertEquals('BYYEARDAY in RRULE must have value(s) from -366 to -1, or 1 to 366!', $result[0]['message']); + $this->assertEquals(1, $result[0]['level']); + $this->assertEquals('BYYEARDAY in RRULE must have value(s) from -366 to -1, or 1 to 366!', $result[1]['message']); + $this->assertEquals(1, $result[1]['level']); + $this->assertEquals('FREQ=YEARLY;COUNT=6;BYYEARDAY=2;BYDAY=WE', $property->getValue()); + } + + public function testValidateAllInvalidByYearDayWithRepair() + { + $calendar = new VCalendar(); + $property = $calendar->createProperty('RRULE', 'FREQ=YEARLY;COUNT=6;BYYEARDAY=455,-480;BYDAY=WE'); + $result = $property->validate(Node::REPAIR); + + $this->assertCount(2, $result); + $this->assertEquals('BYYEARDAY in RRULE must have value(s) from -366 to -1, or 1 to 366!', $result[0]['message']); + $this->assertEquals(1, $result[0]['level']); + $this->assertEquals('BYYEARDAY in RRULE must have value(s) from -366 to -1, or 1 to 366!', $result[1]['message']); + $this->assertEquals(1, $result[1]['level']); + $this->assertEquals('FREQ=YEARLY;COUNT=6;BYDAY=WE', $property->getValue()); + } + + public function testValidateInvalidByYearDayWithoutRepair() + { + $calendar = new VCalendar(); + $property = $calendar->createProperty('RRULE', 'FREQ=YEARLY;COUNT=6;BYYEARDAY=380;BYDAY=WE'); + $result = $property->validate(); + + $this->assertCount(1, $result); + $this->assertEquals('BYYEARDAY in RRULE must have value(s) from -366 to -1, or 1 to 366!', $result[0]['message']); + $this->assertEquals(3, $result[0]['level']); + $this->assertEquals('FREQ=YEARLY;COUNT=6;BYYEARDAY=380;BYDAY=WE', $property->getValue()); + } +} diff --git a/vendor/sabre/vobject/tests/VObject/Property/TextTest.php b/vendor/sabre/vobject/tests/VObject/Property/TextTest.php new file mode 100644 index 000000000..eea21b1ad --- /dev/null +++ b/vendor/sabre/vobject/tests/VObject/Property/TextTest.php @@ -0,0 +1,87 @@ + '2.1', + 'PROP' => $propValue, + ], false); + + // Adding quoted-printable, because we're testing if it gets removed + // automatically. + $doc->PROP['ENCODING'] = 'QUOTED-PRINTABLE'; + $doc->PROP['P1'] = 'V1'; + + $output = $doc->serialize(); + + $this->assertEquals("BEGIN:VCARD\r\nVERSION:2.1\r\n$expected\r\nEND:VCARD\r\n", $output); + } + + public function testSerializeVCard21() + { + $this->assertVCard21Serialization( + 'f;oo', + 'PROP;P1=V1:f;oo' + ); + } + + public function testSerializeVCard21Array() + { + $this->assertVCard21Serialization( + ['f;oo', 'bar'], + 'PROP;P1=V1:f\;oo;bar' + ); + } + + public function testSerializeVCard21Fold() + { + $this->assertVCard21Serialization( + str_repeat('x', 80), + 'PROP;P1=V1:'.str_repeat('x', 64)."\r\n ".str_repeat('x', 16) + ); + } + + public function testSerializeQuotedPrintable() + { + $this->assertVCard21Serialization( + "foo\r\nbar", + 'PROP;P1=V1;ENCODING=QUOTED-PRINTABLE:foo=0D=0Abar' + ); + } + + public function testSerializeQuotedPrintableFold() + { + $this->assertVCard21Serialization( + "foo\r\nbarxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", + "PROP;P1=V1;ENCODING=QUOTED-PRINTABLE:foo=0D=0Abarxxxxxxxxxxxxxxxxxxxxxxxxxx=\r\n xxx" + ); + } + + public function testValidateMinimumPropValue() + { + $vcard = <<assertEquals(1, count($vcard->validate())); + + $this->assertEquals(1, count($vcard->N->getParts())); + + $vcard->validate(\Sabre\VObject\Node::REPAIR); + + $this->assertEquals(5, count($vcard->N->getParts())); + } +} diff --git a/vendor/sabre/vobject/tests/VObject/Property/UriTest.php b/vendor/sabre/vobject/tests/VObject/Property/UriTest.php new file mode 100644 index 000000000..4ab32a736 --- /dev/null +++ b/vendor/sabre/vobject/tests/VObject/Property/UriTest.php @@ -0,0 +1,26 @@ +serialize(); + $this->assertContains('URL;VALUE=URI:http://example.org/', $output); + } +} diff --git a/vendor/sabre/vobject/tests/VObject/Property/VCard/DateAndOrTimeTest.php b/vendor/sabre/vobject/tests/VObject/Property/VCard/DateAndOrTimeTest.php new file mode 100644 index 000000000..a59411e01 --- /dev/null +++ b/vendor/sabre/vobject/tests/VObject/Property/VCard/DateAndOrTimeTest.php @@ -0,0 +1,255 @@ +createProperty('BDAY', $input); + + $this->assertEquals([$output], $prop->getJsonValue()); + } + + public function dates() + { + return [ + [ + '19961022T140000', + '1996-10-22T14:00:00', + ], + [ + '--1022T1400', + '--10-22T14:00', + ], + [ + '---22T14', + '---22T14', + ], + [ + '19850412', + '1985-04-12', + ], + [ + '1985-04', + '1985-04', + ], + [ + '1985', + '1985', + ], + [ + '--0412', + '--04-12', + ], + [ + 'T102200', + 'T10:22:00', + ], + [ + 'T1022', + 'T10:22', + ], + [ + 'T10', + 'T10', + ], + [ + 'T-2200', + 'T-22:00', + ], + [ + 'T102200Z', + 'T10:22:00Z', + ], + [ + 'T102200-0800', + 'T10:22:00-0800', + ], + [ + 'T--00', + 'T--00', + ], + ]; + } + + public function testSetParts() + { + $vcard = new VObject\Component\VCard(); + + $prop = $vcard->createProperty('BDAY'); + $prop->setParts([ + new \DateTime('2014-04-02 18:37:00'), + ]); + + $this->assertEquals('20140402T183700Z', $prop->getValue()); + } + + public function testSetPartsDateTimeImmutable() + { + $vcard = new VObject\Component\VCard(); + + $prop = $vcard->createProperty('BDAY'); + $prop->setParts([ + new \DateTimeImmutable('2014-04-02 18:37:00'), + ]); + + $this->assertEquals('20140402T183700Z', $prop->getValue()); + } + + /** + * @expectedException \InvalidArgumentException + */ + public function testSetPartsTooMany() + { + $vcard = new VObject\Component\VCard(); + + $prop = $vcard->createProperty('BDAY'); + $prop->setParts([ + 1, + 2, + ]); + } + + public function testSetPartsString() + { + $vcard = new VObject\Component\VCard(); + + $prop = $vcard->createProperty('BDAY'); + $prop->setParts([ + '20140402T183700Z', + ]); + + $this->assertEquals('20140402T183700Z', $prop->getValue()); + } + + public function testSetValueDateTime() + { + $vcard = new VObject\Component\VCard(); + + $prop = $vcard->createProperty('BDAY'); + $prop->setValue( + new \DateTime('2014-04-02 18:37:00') + ); + + $this->assertEquals('20140402T183700Z', $prop->getValue()); + } + + public function testSetValueDateTimeImmutable() + { + $vcard = new VObject\Component\VCard(); + + $prop = $vcard->createProperty('BDAY'); + $prop->setValue( + new \DateTimeImmutable('2014-04-02 18:37:00') + ); + + $this->assertEquals('20140402T183700Z', $prop->getValue()); + } + + public function testSetDateTimeOffset() + { + $vcard = new VObject\Component\VCard(); + + $prop = $vcard->createProperty('BDAY'); + $prop->setValue( + new \DateTime('2014-04-02 18:37:00', new \DateTimeZone('America/Toronto')) + ); + + $this->assertEquals('20140402T183700-0400', $prop->getValue()); + } + + public function testGetDateTime() + { + $datetime = new \DateTime('2014-04-02 18:37:00', new \DateTimeZone('America/Toronto')); + + $vcard = new VObject\Component\VCard(); + $prop = $vcard->createProperty('BDAY', $datetime); + + $dt = $prop->getDateTime(); + $this->assertEquals('2014-04-02T18:37:00-04:00', $dt->format('c'), 'For some reason this one failed. Current default timezone is: '.date_default_timezone_get()); + } + + public function testGetDate() + { + $datetime = new \DateTime('2014-04-02'); + + $vcard = new VObject\Component\VCard(); + $prop = $vcard->createProperty('BDAY', $datetime, null, 'DATE'); + + $this->assertEquals('DATE', $prop->getValueType()); + $this->assertEquals('BDAY:20140402', rtrim($prop->serialize())); + } + + public function testGetDateIncomplete() + { + $datetime = '--0407'; + + $vcard = new VObject\Component\VCard(); + $prop = $vcard->add('BDAY', $datetime); + + $dt = $prop->getDateTime(); + // Note: if the year changes between the last line and the next line of + // code, this test may fail. + // + // If that happens, head outside and have a drink. + $current = new \DateTime('now'); + $year = $current->format('Y'); + + $this->assertEquals($year.'0407', $dt->format('Ymd')); + } + + public function testGetDateIncompleteFromVCard() + { + $vcard = <<BDAY; + + $dt = $prop->getDateTime(); + // Note: if the year changes between the last line and the next line of + // code, this test may fail. + // + // If that happens, head outside and have a drink. + $current = new \DateTime('now'); + $year = $current->format('Y'); + + $this->assertEquals($year.'0407', $dt->format('Ymd')); + } + + public function testValidate() + { + $datetime = '--0407'; + + $vcard = new VObject\Component\VCard(); + $prop = $vcard->add('BDAY', $datetime); + + $this->assertEquals([], $prop->validate()); + } + + public function testValidateBroken() + { + $datetime = '123'; + + $vcard = new VObject\Component\VCard(); + $prop = $vcard->add('BDAY', $datetime); + + $this->assertEquals([[ + 'level' => 3, + 'message' => 'The supplied value (123) is not a correct DATE-AND-OR-TIME property', + 'node' => $prop, + ]], $prop->validate()); + } +} diff --git a/vendor/sabre/vobject/tests/VObject/Property/VCard/LanguageTagTest.php b/vendor/sabre/vobject/tests/VObject/Property/VCard/LanguageTagTest.php new file mode 100644 index 000000000..ffb65f434 --- /dev/null +++ b/vendor/sabre/vobject/tests/VObject/Property/VCard/LanguageTagTest.php @@ -0,0 +1,47 @@ +parse($input); + + $this->assertInstanceOf('Sabre\VObject\Property\VCard\LanguageTag', $result->LANG); + + $this->assertEquals('nl', $result->LANG->getValue()); + + $this->assertEquals( + $input, + $result->serialize() + ); + } + + public function testChangeAndSerialize() + { + $input = "BEGIN:VCARD\r\nVERSION:4.0\r\nLANG:nl\r\nEND:VCARD\r\n"; + $mimeDir = new VObject\Parser\MimeDir($input); + + $result = $mimeDir->parse($input); + + $this->assertInstanceOf('Sabre\VObject\Property\VCard\LanguageTag', $result->LANG); + // This replicates what the vcard converter does and triggered a bug in + // the past. + $result->LANG->setValue(['de']); + + $this->assertEquals('de', $result->LANG->getValue()); + + $expected = "BEGIN:VCARD\r\nVERSION:4.0\r\nLANG:de\r\nEND:VCARD\r\n"; + $this->assertEquals( + $expected, + $result->serialize() + ); + } +} diff --git a/vendor/sabre/vobject/tests/VObject/Property/VCard/PhoneNumberTest.php b/vendor/sabre/vobject/tests/VObject/Property/VCard/PhoneNumberTest.php new file mode 100644 index 000000000..4a54d3333 --- /dev/null +++ b/vendor/sabre/vobject/tests/VObject/Property/VCard/PhoneNumberTest.php @@ -0,0 +1,19 @@ +assertInstanceOf('Sabre\VObject\Property\VCard\PhoneNumber', $vCard->TEL); + $this->assertEquals('PHONE-NUMBER', $vCard->TEL->getValueType()); + $this->assertEquals($input, $vCard->serialize()); + } +} diff --git a/vendor/sabre/vobject/tests/VObject/PropertyTest.php b/vendor/sabre/vobject/tests/VObject/PropertyTest.php new file mode 100644 index 000000000..1c2dc0830 --- /dev/null +++ b/vendor/sabre/vobject/tests/VObject/PropertyTest.php @@ -0,0 +1,390 @@ +createProperty('propname', 'propvalue'); + $this->assertEquals('PROPNAME', $property->name); + $this->assertEquals('propvalue', $property->__toString()); + $this->assertEquals('propvalue', (string) $property); + $this->assertEquals('propvalue', $property->getValue()); + } + + public function testCreate() + { + $cal = new VCalendar(); + + $params = [ + 'param1' => 'value1', + 'param2' => 'value2', + ]; + + $property = $cal->createProperty('propname', 'propvalue', $params); + + $this->assertEquals('value1', $property['param1']->getValue()); + $this->assertEquals('value2', $property['param2']->getValue()); + } + + public function testSetValue() + { + $cal = new VCalendar(); + + $property = $cal->createProperty('propname', 'propvalue'); + $property->setValue('value2'); + + $this->assertEquals('PROPNAME', $property->name); + $this->assertEquals('value2', $property->__toString()); + } + + public function testParameterExists() + { + $cal = new VCalendar(); + $property = $cal->createProperty('propname', 'propvalue'); + $property['paramname'] = 'paramvalue'; + + $this->assertTrue(isset($property['PARAMNAME'])); + $this->assertTrue(isset($property['paramname'])); + $this->assertFalse(isset($property['foo'])); + } + + public function testParameterGet() + { + $cal = new VCalendar(); + $property = $cal->createProperty('propname', 'propvalue'); + $property['paramname'] = 'paramvalue'; + + $this->assertInstanceOf('Sabre\\VObject\\Parameter', $property['paramname']); + } + + public function testParameterNotExists() + { + $cal = new VCalendar(); + $property = $cal->createProperty('propname', 'propvalue'); + $property['paramname'] = 'paramvalue'; + + $this->assertInternalType('null', $property['foo']); + } + + public function testParameterMultiple() + { + $cal = new VCalendar(); + $property = $cal->createProperty('propname', 'propvalue'); + $property['paramname'] = 'paramvalue'; + $property->add('paramname', 'paramvalue'); + + $this->assertInstanceOf('Sabre\\VObject\\Parameter', $property['paramname']); + $this->assertEquals(2, count($property['paramname']->getParts())); + } + + public function testSetParameterAsString() + { + $cal = new VCalendar(); + $property = $cal->createProperty('propname', 'propvalue'); + $property['paramname'] = 'paramvalue'; + + $this->assertEquals(1, count($property->parameters())); + $this->assertInstanceOf('Sabre\\VObject\\Parameter', $property->parameters['PARAMNAME']); + $this->assertEquals('PARAMNAME', $property->parameters['PARAMNAME']->name); + $this->assertEquals('paramvalue', $property->parameters['PARAMNAME']->getValue()); + } + + public function testUnsetParameter() + { + $cal = new VCalendar(); + $property = $cal->createProperty('propname', 'propvalue'); + $property['paramname'] = 'paramvalue'; + + unset($property['PARAMNAME']); + $this->assertEquals(0, count($property->parameters())); + } + + public function testSerialize() + { + $cal = new VCalendar(); + $property = $cal->createProperty('propname', 'propvalue'); + + $this->assertEquals("PROPNAME:propvalue\r\n", $property->serialize()); + } + + public function testSerializeParam() + { + $cal = new VCalendar(); + $property = $cal->createProperty('propname', 'propvalue', [ + 'paramname' => 'paramvalue', + 'paramname2' => 'paramvalue2', + ]); + + $this->assertEquals("PROPNAME;PARAMNAME=paramvalue;PARAMNAME2=paramvalue2:propvalue\r\n", $property->serialize()); + } + + public function testSerializeNewLine() + { + $cal = new VCalendar(); + $property = $cal->createProperty('SUMMARY', "line1\nline2"); + + $this->assertEquals("SUMMARY:line1\\nline2\r\n", $property->serialize()); + } + + public function testSerializeLongLine() + { + $cal = new VCalendar(); + $value = str_repeat('!', 200); + $property = $cal->createProperty('propname', $value); + + $expected = 'PROPNAME:'.str_repeat('!', 66)."\r\n ".str_repeat('!', 74)."\r\n ".str_repeat('!', 60)."\r\n"; + + $this->assertEquals($expected, $property->serialize()); + } + + public function testSerializeUTF8LineFold() + { + $cal = new VCalendar(); + $value = str_repeat('!', 65)."\xc3\xa4bla".str_repeat('!', 142)."\xc3\xa4foo"; // inserted umlaut-a + $property = $cal->createProperty('propname', $value); + + // PROPNAME:!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ("PROPNAME:" + 65x"!" = 74 bytes) + // äbla!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! (" äbla" + 69x"!" = 75 bytes) + // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! (" " + 73x"!" = 74 bytes) + // äfoo + $expected = 'PROPNAME:'.str_repeat('!', 65)."\r\n \xc3\xa4bla".str_repeat('!', 69)."\r\n ".str_repeat('!', 73)."\r\n \xc3\xa4foo\r\n"; + $this->assertEquals($expected, $property->serialize()); + } + + public function testGetIterator() + { + $cal = new VCalendar(); + $it = new ElementList([]); + $property = $cal->createProperty('propname', 'propvalue'); + $property->setIterator($it); + $this->assertEquals($it, $property->getIterator()); + } + + public function testGetIteratorDefault() + { + $cal = new VCalendar(); + $property = $cal->createProperty('propname', 'propvalue'); + $it = $property->getIterator(); + $this->assertTrue($it instanceof ElementList); + $this->assertEquals(1, count($it)); + } + + public function testAddScalar() + { + $cal = new VCalendar(); + $property = $cal->createProperty('EMAIL'); + + $property->add('myparam', 'value'); + + $this->assertEquals(1, count($property->parameters())); + + $this->assertTrue($property->parameters['MYPARAM'] instanceof Parameter); + $this->assertEquals('MYPARAM', $property->parameters['MYPARAM']->name); + $this->assertEquals('value', $property->parameters['MYPARAM']->getValue()); + } + + public function testAddParameter() + { + $cal = new VCalendar(); + $prop = $cal->createProperty('EMAIL'); + + $prop->add('MYPARAM', 'value'); + + $this->assertEquals(1, count($prop->parameters())); + $this->assertEquals('MYPARAM', $prop['myparam']->name); + } + + public function testAddParameterTwice() + { + $cal = new VCalendar(); + $prop = $cal->createProperty('EMAIL'); + + $prop->add('MYPARAM', 'value1'); + $prop->add('MYPARAM', 'value2'); + + $this->assertEquals(1, count($prop->parameters)); + $this->assertEquals(2, count($prop->parameters['MYPARAM']->getParts())); + + $this->assertEquals('MYPARAM', $prop['MYPARAM']->name); + } + + public function testClone() + { + $cal = new VCalendar(); + $property = $cal->createProperty('EMAIL', 'value'); + $property['FOO'] = 'BAR'; + + $property2 = clone $property; + + $property['FOO'] = 'BAZ'; + $this->assertEquals('BAR', (string) $property2['FOO']); + } + + public function testCreateParams() + { + $cal = new VCalendar(); + $property = $cal->createProperty('X-PROP', 'value', [ + 'param1' => 'value1', + 'param2' => ['value2', 'value3'], + ]); + + $this->assertEquals(1, count($property['PARAM1']->getParts())); + $this->assertEquals(2, count($property['PARAM2']->getParts())); + } + + public function testValidateNonUTF8() + { + $calendar = new VCalendar(); + $property = $calendar->createProperty('X-PROP', "Bla\x00"); + $result = $property->validate(Property::REPAIR); + + $this->assertEquals('Property contained a control character (0x00)', $result[0]['message']); + $this->assertEquals('Bla', $property->getValue()); + } + + public function testValidateControlChars() + { + $s = 'chars['; + foreach ([ + 0x7F, 0x5E, 0x5C, 0x3B, 0x3A, 0x2C, 0x22, 0x20, + 0x1F, 0x1E, 0x1D, 0x1C, 0x1B, 0x1A, 0x19, 0x18, + 0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11, 0x10, + 0x0F, 0x0E, 0x0D, 0x0C, 0x0B, 0x0A, 0x09, 0x08, + 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, + ] as $c) { + $s .= sprintf('%02X(%c)', $c, $c); + } + $s .= ']end'; + + $calendar = new VCalendar(); + $property = $calendar->createProperty('X-PROP', $s); + $result = $property->validate(Property::REPAIR); + + $this->assertEquals('Property contained a control character (0x7f)', $result[0]['message']); + $this->assertEquals("chars[7F()5E(^)5C(\\\\)3B(\\;)3A(:)2C(\\,)22(\")20( )1F()1E()1D()1C()1B()1A()19()18()17()16()15()14()13()12()11()10()0F()0E()0D()0C()0B()0A(\\n)09(\t)08()07()06()05()04()03()02()01()00()]end", $property->getRawMimeDirValue()); + } + + public function testValidateBadPropertyName() + { + $calendar = new VCalendar(); + $property = $calendar->createProperty('X_*&PROP*', 'Bla'); + $result = $property->validate(Property::REPAIR); + + $this->assertEquals($result[0]['message'], 'The propertyname: X_*&PROP* contains invalid characters. Only A-Z, 0-9 and - are allowed'); + $this->assertEquals('X-PROP', $property->name); + } + + public function testGetValue() + { + $calendar = new VCalendar(); + $property = $calendar->createProperty('SUMMARY', null); + $this->assertEquals([], $property->getParts()); + $this->assertNull($property->getValue()); + + $property->setValue([]); + $this->assertEquals([], $property->getParts()); + $this->assertNull($property->getValue()); + + $property->setValue([1]); + $this->assertEquals([1], $property->getParts()); + $this->assertEquals(1, $property->getValue()); + + $property->setValue([1, 2]); + $this->assertEquals([1, 2], $property->getParts()); + $this->assertEquals('1,2', $property->getValue()); + + $property->setValue('str'); + $this->assertEquals(['str'], $property->getParts()); + $this->assertEquals('str', $property->getValue()); + } + + /** + * ElementList should reject this. + * + * @expectedException \LogicException + */ + public function testArrayAccessSetInt() + { + $calendar = new VCalendar(); + $property = $calendar->createProperty('X-PROP', null); + + $calendar->add($property); + $calendar->{'X-PROP'}[0] = 'Something!'; + } + + /** + * ElementList should reject this. + * + * @expectedException \LogicException + */ + public function testArrayAccessUnsetInt() + { + $calendar = new VCalendar(); + $property = $calendar->createProperty('X-PROP', null); + + $calendar->add($property); + unset($calendar->{'X-PROP'}[0]); + } + + public function testValidateBadEncoding() + { + $document = new VCalendar(); + $property = $document->add('X-FOO', 'value'); + $property['ENCODING'] = 'invalid'; + + $result = $property->validate(); + + $this->assertEquals('ENCODING=INVALID is not valid for this document type.', $result[0]['message']); + $this->assertEquals(3, $result[0]['level']); + } + + public function testValidateBadEncodingVCard4() + { + $document = new VCard(['VERSION' => '4.0']); + $property = $document->add('X-FOO', 'value'); + $property['ENCODING'] = 'BASE64'; + + $result = $property->validate(); + + $this->assertEquals('ENCODING parameter is not valid in vCard 4.', $result[0]['message']); + $this->assertEquals(3, $result[0]['level']); + } + + public function testValidateBadEncodingVCard3() + { + $document = new VCard(['VERSION' => '3.0']); + $property = $document->add('X-FOO', 'value'); + $property['ENCODING'] = 'BASE64'; + + $result = $property->validate(); + + $this->assertEquals('ENCODING=BASE64 is not valid for this document type.', $result[0]['message']); + $this->assertEquals(3, $result[0]['level']); + + //Validate the reparation of BASE64 formatted vCard v3 + $result = $property->validate(Property::REPAIR); + + $this->assertEquals('ENCODING=BASE64 has been transformed to ENCODING=B.', $result[0]['message']); + $this->assertEquals(1, $result[0]['level']); + } + + public function testValidateBadEncodingVCard21() + { + $document = new VCard(['VERSION' => '2.1']); + $property = $document->add('X-FOO', 'value'); + $property['ENCODING'] = 'B'; + + $result = $property->validate(); + + $this->assertEquals('ENCODING=B is not valid for this document type.', $result[0]['message']); + $this->assertEquals(3, $result[0]['level']); + } +} diff --git a/vendor/sabre/vobject/tests/VObject/ReaderTest.php b/vendor/sabre/vobject/tests/VObject/ReaderTest.php new file mode 100644 index 000000000..06310e80a --- /dev/null +++ b/vendor/sabre/vobject/tests/VObject/ReaderTest.php @@ -0,0 +1,462 @@ +assertInstanceOf('Sabre\\VObject\\Component', $result); + $this->assertEquals('VCALENDAR', $result->name); + $this->assertEquals(0, count($result->children())); + } + + public function testReadStream() + { + $data = "BEGIN:VCALENDAR\r\nEND:VCALENDAR"; + + $stream = fopen('php://memory', 'r+'); + fwrite($stream, $data); + rewind($stream); + + $result = Reader::read($stream); + + $this->assertInstanceOf('Sabre\\VObject\\Component', $result); + $this->assertEquals('VCALENDAR', $result->name); + $this->assertEquals(0, count($result->children())); + } + + public function testReadComponentUnixNewLine() + { + $data = "BEGIN:VCALENDAR\nEND:VCALENDAR"; + + $result = Reader::read($data); + + $this->assertInstanceOf('Sabre\\VObject\\Component', $result); + $this->assertEquals('VCALENDAR', $result->name); + $this->assertEquals(0, count($result->children())); + } + + public function testReadComponentLineFold() + { + $data = "BEGIN:\r\n\tVCALENDAR\r\nE\r\n ND:VCALENDAR"; + + $result = Reader::read($data); + + $this->assertInstanceOf('Sabre\\VObject\\Component', $result); + $this->assertEquals('VCALENDAR', $result->name); + $this->assertEquals(0, count($result->children())); + } + + /** + * @expectedException \Sabre\VObject\ParseException + */ + public function testReadCorruptComponent() + { + $data = "BEGIN:VCALENDAR\r\nEND:FOO"; + + $result = Reader::read($data); + } + + /** + * @expectedException \Sabre\VObject\ParseException + */ + public function testReadCorruptSubComponent() + { + $data = "BEGIN:VCALENDAR\r\nBEGIN:VEVENT\r\nEND:FOO\r\nEND:VCALENDAR"; + + $result = Reader::read($data); + } + + public function testReadProperty() + { + $data = "BEGIN:VCALENDAR\r\nSUMMARY:propValue\r\nEND:VCALENDAR"; + $result = Reader::read($data); + + $result = $result->SUMMARY; + $this->assertInstanceOf('Sabre\\VObject\\Property', $result); + $this->assertEquals('SUMMARY', $result->name); + $this->assertEquals('propValue', $result->getValue()); + } + + public function testReadPropertyWithNewLine() + { + $data = "BEGIN:VCALENDAR\r\nSUMMARY:Line1\\nLine2\\NLine3\\\\Not the 4th line!\r\nEND:VCALENDAR"; + $result = Reader::read($data); + + $result = $result->SUMMARY; + $this->assertInstanceOf('Sabre\\VObject\\Property', $result); + $this->assertEquals('SUMMARY', $result->name); + $this->assertEquals("Line1\nLine2\nLine3\\Not the 4th line!", $result->getValue()); + } + + public function testReadMappedProperty() + { + $data = "BEGIN:VCALENDAR\r\nDTSTART:20110529\r\nEND:VCALENDAR"; + $result = Reader::read($data); + + $result = $result->DTSTART; + $this->assertInstanceOf('Sabre\\VObject\\Property\\ICalendar\\DateTime', $result); + $this->assertEquals('DTSTART', $result->name); + $this->assertEquals('20110529', $result->getValue()); + } + + public function testReadMappedPropertyGrouped() + { + $data = "BEGIN:VCALENDAR\r\nfoo.DTSTART:20110529\r\nEND:VCALENDAR"; + $result = Reader::read($data); + + $result = $result->DTSTART; + $this->assertInstanceOf('Sabre\\VObject\\Property\\ICalendar\\DateTime', $result); + $this->assertEquals('DTSTART', $result->name); + $this->assertEquals('20110529', $result->getValue()); + } + + /** + * @expectedException \Sabre\VObject\ParseException + */ + public function testReadBrokenLine() + { + $data = "BEGIN:VCALENDAR\r\nPROPNAME;propValue"; + $result = Reader::read($data); + } + + public function testReadPropertyInComponent() + { + $data = [ + 'BEGIN:VCALENDAR', + 'PROPNAME:propValue', + 'END:VCALENDAR', + ]; + + $result = Reader::read(implode("\r\n", $data)); + + $this->assertInstanceOf('Sabre\\VObject\\Component', $result); + $this->assertEquals('VCALENDAR', $result->name); + $this->assertEquals(1, count($result->children())); + $this->assertInstanceOf('Sabre\\VObject\\Property', $result->children()[0]); + $this->assertEquals('PROPNAME', $result->children()[0]->name); + $this->assertEquals('propValue', $result->children()[0]->getValue()); + } + + public function testReadNestedComponent() + { + $data = [ + 'BEGIN:VCALENDAR', + 'BEGIN:VTIMEZONE', + 'BEGIN:DAYLIGHT', + 'END:DAYLIGHT', + 'END:VTIMEZONE', + 'END:VCALENDAR', + ]; + + $result = Reader::read(implode("\r\n", $data)); + + $this->assertInstanceOf('Sabre\\VObject\\Component', $result); + $this->assertEquals('VCALENDAR', $result->name); + $this->assertEquals(1, count($result->children())); + $this->assertInstanceOf('Sabre\\VObject\\Component', $result->children()[0]); + $this->assertEquals('VTIMEZONE', $result->children()[0]->name); + $this->assertEquals(1, count($result->children()[0]->children())); + $this->assertInstanceOf('Sabre\\VObject\\Component', $result->children()[0]->children()[0]); + $this->assertEquals('DAYLIGHT', $result->children()[0]->children()[0]->name); + } + + public function testReadPropertyParameter() + { + $data = "BEGIN:VCALENDAR\r\nPROPNAME;PARAMNAME=paramvalue:propValue\r\nEND:VCALENDAR"; + $result = Reader::read($data); + + $result = $result->PROPNAME; + + $this->assertInstanceOf('Sabre\\VObject\\Property', $result); + $this->assertEquals('PROPNAME', $result->name); + $this->assertEquals('propValue', $result->getValue()); + $this->assertEquals(1, count($result->parameters())); + $this->assertEquals('PARAMNAME', $result->parameters['PARAMNAME']->name); + $this->assertEquals('paramvalue', $result->parameters['PARAMNAME']->getValue()); + } + + public function testReadPropertyRepeatingParameter() + { + $data = "BEGIN:VCALENDAR\r\nPROPNAME;N=1;N=2;N=3,4;N=\"5\",6;N=\"7,8\";N=9,10;N=^'11^':propValue\r\nEND:VCALENDAR"; + $result = Reader::read($data); + + $result = $result->PROPNAME; + + $this->assertInstanceOf('Sabre\\VObject\\Property', $result); + $this->assertEquals('PROPNAME', $result->name); + $this->assertEquals('propValue', $result->getValue()); + $this->assertEquals(1, count($result->parameters())); + $this->assertEquals('N', $result->parameters['N']->name); + $this->assertEquals('1,2,3,4,5,6,7,8,9,10,"11"', $result->parameters['N']->getValue()); + $this->assertEquals([1, 2, 3, 4, 5, 6, '7,8', 9, 10, '"11"'], $result->parameters['N']->getParts()); + } + + public function testReadPropertyRepeatingNamelessGuessedParameter() + { + $data = "BEGIN:VCALENDAR\r\nPROPNAME;WORK;VOICE;PREF:propValue\r\nEND:VCALENDAR"; + $result = Reader::read($data); + + $result = $result->PROPNAME; + + $this->assertInstanceOf('Sabre\\VObject\\Property', $result); + $this->assertEquals('PROPNAME', $result->name); + $this->assertEquals('propValue', $result->getValue()); + $this->assertEquals(1, count($result->parameters())); + $this->assertEquals('TYPE', $result->parameters['TYPE']->name); + $this->assertEquals('WORK,VOICE,PREF', $result->parameters['TYPE']->getValue()); + $this->assertEquals(['WORK', 'VOICE', 'PREF'], $result->parameters['TYPE']->getParts()); + } + + public function testReadPropertyNoName() + { + $data = "BEGIN:VCALENDAR\r\nPROPNAME;PRODIGY:propValue\r\nEND:VCALENDAR"; + $result = Reader::read($data); + + $result = $result->PROPNAME; + + $this->assertInstanceOf('Sabre\\VObject\\Property', $result); + $this->assertEquals('PROPNAME', $result->name); + $this->assertEquals('propValue', $result->getValue()); + $this->assertEquals(1, count($result->parameters())); + $this->assertEquals('TYPE', $result->parameters['TYPE']->name); + $this->assertTrue($result->parameters['TYPE']->noName); + $this->assertEquals('PRODIGY', $result->parameters['TYPE']); + } + + public function testReadPropertyParameterExtraColon() + { + $data = "BEGIN:VCALENDAR\r\nPROPNAME;PARAMNAME=paramvalue:propValue:anotherrandomstring\r\nEND:VCALENDAR"; + $result = Reader::read($data); + + $result = $result->PROPNAME; + + $this->assertInstanceOf('Sabre\\VObject\\Property', $result); + $this->assertEquals('PROPNAME', $result->name); + $this->assertEquals('propValue:anotherrandomstring', $result->getValue()); + $this->assertEquals(1, count($result->parameters())); + $this->assertEquals('PARAMNAME', $result->parameters['PARAMNAME']->name); + $this->assertEquals('paramvalue', $result->parameters['PARAMNAME']->getValue()); + } + + public function testReadProperty2Parameters() + { + $data = "BEGIN:VCALENDAR\r\nPROPNAME;PARAMNAME=paramvalue;PARAMNAME2=paramvalue2:propValue\r\nEND:VCALENDAR"; + $result = Reader::read($data); + + $result = $result->PROPNAME; + + $this->assertInstanceOf('Sabre\\VObject\\Property', $result); + $this->assertEquals('PROPNAME', $result->name); + $this->assertEquals('propValue', $result->getValue()); + $this->assertEquals(2, count($result->parameters())); + $this->assertEquals('PARAMNAME', $result->parameters['PARAMNAME']->name); + $this->assertEquals('paramvalue', $result->parameters['PARAMNAME']->getValue()); + $this->assertEquals('PARAMNAME2', $result->parameters['PARAMNAME2']->name); + $this->assertEquals('paramvalue2', $result->parameters['PARAMNAME2']->getValue()); + } + + public function testReadPropertyParameterQuoted() + { + $data = "BEGIN:VCALENDAR\r\nPROPNAME;PARAMNAME=\"paramvalue\":propValue\r\nEND:VCALENDAR"; + $result = Reader::read($data); + + $result = $result->PROPNAME; + + $this->assertInstanceOf('Sabre\\VObject\\Property', $result); + $this->assertEquals('PROPNAME', $result->name); + $this->assertEquals('propValue', $result->getValue()); + $this->assertEquals(1, count($result->parameters())); + $this->assertEquals('PARAMNAME', $result->parameters['PARAMNAME']->name); + $this->assertEquals('paramvalue', $result->parameters['PARAMNAME']->getValue()); + } + + public function testReadPropertyParameterNewLines() + { + $data = "BEGIN:VCALENDAR\r\nPROPNAME;PARAMNAME=paramvalue1^nvalue2^^nvalue3:propValue\r\nEND:VCALENDAR"; + $result = Reader::read($data); + + $result = $result->PROPNAME; + + $this->assertInstanceOf('Sabre\\VObject\\Property', $result); + $this->assertEquals('PROPNAME', $result->name); + $this->assertEquals('propValue', $result->getValue()); + + $this->assertEquals(1, count($result->parameters())); + $this->assertEquals('PARAMNAME', $result->parameters['PARAMNAME']->name); + $this->assertEquals("paramvalue1\nvalue2^nvalue3", $result->parameters['PARAMNAME']->getValue()); + } + + public function testReadPropertyParameterQuotedColon() + { + $data = "BEGIN:VCALENDAR\r\nPROPNAME;PARAMNAME=\"param:value\":propValue\r\nEND:VCALENDAR"; + $result = Reader::read($data); + $result = $result->PROPNAME; + + $this->assertInstanceOf('Sabre\\VObject\\Property', $result); + $this->assertEquals('PROPNAME', $result->name); + $this->assertEquals('propValue', $result->getValue()); + $this->assertEquals(1, count($result->parameters())); + $this->assertEquals('PARAMNAME', $result->parameters['PARAMNAME']->name); + $this->assertEquals('param:value', $result->parameters['PARAMNAME']->getValue()); + } + + public function testReadForgiving() + { + $data = [ + 'BEGIN:VCALENDAR', + 'X_PROP:propValue', + 'END:VCALENDAR', + ]; + + $caught = false; + try { + $result = Reader::read(implode("\r\n", $data)); + } catch (ParseException $e) { + $caught = true; + } + + $this->assertEquals(true, $caught); + + $result = Reader::read(implode("\r\n", $data), Reader::OPTION_FORGIVING); + + $expected = implode("\r\n", [ + 'BEGIN:VCALENDAR', + 'X_PROP:propValue', + 'END:VCALENDAR', + '', + ]); + + $this->assertEquals($expected, $result->serialize()); + } + + public function testReadWithInvalidLine() + { + $data = [ + 'BEGIN:VCALENDAR', + 'DESCRIPTION:propValue', + "Yes, we've actually seen a file with non-idented property values on multiple lines", + 'END:VCALENDAR', + ]; + + $caught = false; + try { + $result = Reader::read(implode("\r\n", $data)); + } catch (ParseException $e) { + $caught = true; + } + + $this->assertEquals(true, $caught); + + $result = Reader::read(implode("\r\n", $data), Reader::OPTION_IGNORE_INVALID_LINES); + + $expected = implode("\r\n", [ + 'BEGIN:VCALENDAR', + 'DESCRIPTION:propValue', + 'END:VCALENDAR', + '', + ]); + + $this->assertEquals($expected, $result->serialize()); + } + + /** + * Reported as Issue 32. + * + * @expectedException \Sabre\VObject\ParseException + */ + public function testReadIncompleteFile() + { + $input = <<assertInstanceOf('Sabre\\VObject\\Component', $result); + $this->assertEquals('VCALENDAR', $result->name); + $this->assertEquals(0, count($result->children())); + } + + public function testReadXMLComponent() + { + $data = << + + + + +XML; + + $result = Reader::readXML($data); + + $this->assertInstanceOf('Sabre\\VObject\\Component', $result); + $this->assertEquals('VCALENDAR', $result->name); + $this->assertEquals(0, count($result->children())); + } + + public function testReadXMLStream() + { + $data = << + + + + +XML; + + $stream = fopen('php://memory', 'r+'); + fwrite($stream, $data); + rewind($stream); + + $result = Reader::readXML($stream); + + $this->assertInstanceOf('Sabre\\VObject\\Component', $result); + $this->assertEquals('VCALENDAR', $result->name); + $this->assertEquals(0, count($result->children())); + } +} diff --git a/vendor/sabre/vobject/tests/VObject/Recur/EventIterator/ByMonthInDailyTest.php b/vendor/sabre/vobject/tests/VObject/Recur/EventIterator/ByMonthInDailyTest.php new file mode 100644 index 000000000..71858c36f --- /dev/null +++ b/vendor/sabre/vobject/tests/VObject/Recur/EventIterator/ByMonthInDailyTest.php @@ -0,0 +1,58 @@ +assertInstanceOf('Sabre\\VObject\\Component\\VCalendar', $vcal); + + $vcal = $vcal->expand(new DateTime('2013-09-28'), new DateTime('2014-09-11')); + + foreach ($vcal->VEVENT as $event) { + $dates[] = $event->DTSTART->getValue(); + } + + $expectedDates = [ + '20130929T160000Z', + '20131006T160000Z', + '20131013T160000Z', + '20131020T160000Z', + '20131027T160000Z', + '20140907T160000Z', + ]; + + $this->assertEquals($expectedDates, $dates, 'Recursed dates are restricted by month'); + } +} diff --git a/vendor/sabre/vobject/tests/VObject/Recur/EventIterator/BySetPosHangTest.php b/vendor/sabre/vobject/tests/VObject/Recur/EventIterator/BySetPosHangTest.php new file mode 100644 index 000000000..bd00cb52a --- /dev/null +++ b/vendor/sabre/vobject/tests/VObject/Recur/EventIterator/BySetPosHangTest.php @@ -0,0 +1,60 @@ +assertInstanceOf('Sabre\\VObject\\Component\\VCalendar', $vcal); + + $vcal = $vcal->expand(new DateTime('2015-01-01'), new DateTime('2016-01-01')); + + foreach ($vcal->VEVENT as $event) { + $dates[] = $event->DTSTART->getValue(); + } + + $expectedDates = [ + '20150101T160000Z', + '20150122T160000Z', + '20150219T160000Z', + '20150319T160000Z', + '20150423T150000Z', + '20150521T150000Z', + '20150618T150000Z', + '20150723T150000Z', + '20150820T150000Z', + '20150917T150000Z', + '20151022T150000Z', + '20151119T160000Z', + '20151224T160000Z', + ]; + + $this->assertEquals($expectedDates, $dates); + } +} diff --git a/vendor/sabre/vobject/tests/VObject/Recur/EventIterator/ExpandFloatingTimesTest.php b/vendor/sabre/vobject/tests/VObject/Recur/EventIterator/ExpandFloatingTimesTest.php new file mode 100644 index 000000000..635b0a8c5 --- /dev/null +++ b/vendor/sabre/vobject/tests/VObject/Recur/EventIterator/ExpandFloatingTimesTest.php @@ -0,0 +1,120 @@ +assertInstanceOf('Sabre\\VObject\\Component\\VCalendar', $vcal); + + $vcal = $vcal->expand(new DateTime('2015-01-01'), new DateTime('2015-01-31')); + $output = <<assertVObjectEqualsVObject($output, $vcal); + } + + public function testExpandWithReferenceTimezone() + { + $input = <<assertInstanceOf('Sabre\\VObject\\Component\\VCalendar', $vcal); + + $vcal = $vcal->expand( + new DateTime('2015-01-01'), + new DateTime('2015-01-31'), + new DateTimeZone('Europe/Berlin') + ); + + $output = <<assertVObjectEqualsVObject($output, $vcal); + } +} diff --git a/vendor/sabre/vobject/tests/VObject/Recur/EventIterator/FifthTuesdayProblemTest.php b/vendor/sabre/vobject/tests/VObject/Recur/EventIterator/FifthTuesdayProblemTest.php new file mode 100644 index 000000000..3db97ede2 --- /dev/null +++ b/vendor/sabre/vobject/tests/VObject/Recur/EventIterator/FifthTuesdayProblemTest.php @@ -0,0 +1,53 @@ +VEVENT->UID); + + while ($it->valid()) { + $it->next(); + } + + // If we got here, it means we were successful. The bug that was in the + // system before would fail on the 5th tuesday of the month, if the 5th + // tuesday did not exist. + $this->assertTrue(true); + } +} diff --git a/vendor/sabre/vobject/tests/VObject/Recur/EventIterator/HandleRDateExpandTest.php b/vendor/sabre/vobject/tests/VObject/Recur/EventIterator/HandleRDateExpandTest.php new file mode 100644 index 000000000..698c5fe59 --- /dev/null +++ b/vendor/sabre/vobject/tests/VObject/Recur/EventIterator/HandleRDateExpandTest.php @@ -0,0 +1,59 @@ +assertInstanceOf('Sabre\\VObject\\Component\\VCalendar', $vcal); + + $vcal = $vcal->expand(new DateTime('2015-01-01'), new DateTime('2015-12-01')); + + $result = iterator_to_array($vcal->VEVENT); + + $this->assertEquals(5, count($result)); + + $utc = new DateTimeZone('UTC'); + $expected = [ + new DateTimeImmutable('2015-10-12', $utc), + new DateTimeImmutable('2015-10-15', $utc), + new DateTimeImmutable('2015-10-17', $utc), + new DateTimeImmutable('2015-10-18', $utc), + new DateTimeImmutable('2015-10-20', $utc), + ]; + + $result = array_map(function ($ev) {return $ev->DTSTART->getDateTime(); }, $result); + $this->assertEquals($expected, $result); + } +} diff --git a/vendor/sabre/vobject/tests/VObject/Recur/EventIterator/IncorrectExpandTest.php b/vendor/sabre/vobject/tests/VObject/Recur/EventIterator/IncorrectExpandTest.php new file mode 100644 index 000000000..afc509972 --- /dev/null +++ b/vendor/sabre/vobject/tests/VObject/Recur/EventIterator/IncorrectExpandTest.php @@ -0,0 +1,61 @@ +assertInstanceOf('Sabre\\VObject\\Component\\VCalendar', $vcal); + + $vcal = $vcal->expand(new DateTime('2011-01-01'), new DateTime('2014-01-01')); + + $output = <<assertVObjectEqualsVObject($output, $vcal); + } +} diff --git a/vendor/sabre/vobject/tests/VObject/Recur/EventIterator/InfiniteLoopProblemTest.php b/vendor/sabre/vobject/tests/VObject/Recur/EventIterator/InfiniteLoopProblemTest.php new file mode 100644 index 000000000..ace78de2c --- /dev/null +++ b/vendor/sabre/vobject/tests/VObject/Recur/EventIterator/InfiniteLoopProblemTest.php @@ -0,0 +1,95 @@ +vcal = new VCalendar(); + } + + /** + * This bug came from a Fruux customer. This would result in a never-ending + * request. + */ + public function testFastForwardTooFar() + { + $ev = $this->vcal->createComponent('VEVENT'); + $ev->UID = 'foobar'; + $ev->DTSTART = '20090420T180000Z'; + $ev->RRULE = 'FREQ=WEEKLY;BYDAY=MO;UNTIL=20090704T205959Z;INTERVAL=1'; + + $this->assertFalse($ev->isInTimeRange(new DateTimeImmutable('2012-01-01 12:00:00'), new DateTimeImmutable('3000-01-01 00:00:00'))); + } + + /** + * Different bug, also likely an infinite loop. + */ + public function testYearlyByMonthLoop() + { + $ev = $this->vcal->createComponent('VEVENT'); + $ev->UID = 'uuid'; + $ev->DTSTART = '20120101T154500'; + $ev->DTSTART['TZID'] = 'Europe/Berlin'; + $ev->RRULE = 'FREQ=YEARLY;INTERVAL=1;UNTIL=20120203T225959Z;BYMONTH=2;BYSETPOS=1;BYDAY=SU,MO,TU,WE,TH,FR,SA'; + $ev->DTEND = '20120101T164500'; + $ev->DTEND['TZID'] = 'Europe/Berlin'; + + // This recurrence rule by itself is a yearly rule that should happen + // every february. + // + // The BYDAY part expands this to every day of the month, but the + // BYSETPOS limits this to only the 1st day of the month. Very crazy + // way to specify this, and could have certainly been a lot easier. + $this->vcal->add($ev); + + $it = new Recur\EventIterator($this->vcal, 'uuid'); + $it->fastForward(new DateTimeImmutable('2012-01-29 23:00:00', new DateTimeZone('UTC'))); + + $collect = []; + + while ($it->valid()) { + $collect[] = $it->getDtStart(); + if ($it->getDtStart() > new DateTimeImmutable('2013-02-05 22:59:59', new DateTimeZone('UTC'))) { + break; + } + $it->next(); + } + + $this->assertEquals( + [new DateTimeImmutable('2012-02-01 15:45:00', new DateTimeZone('Europe/Berlin'))], + $collect + ); + } + + /** + * Something, somewhere produced an ics with an interval set to 0. Because + * this means we increase the current day (or week, month) by 0, this also + * results in an infinite loop. + * + * @expectedException \Sabre\VObject\InvalidDataException + */ + public function testZeroInterval() + { + $ev = $this->vcal->createComponent('VEVENT'); + $ev->UID = 'uuid'; + $ev->DTSTART = '20120824T145700Z'; + $ev->RRULE = 'FREQ=YEARLY;INTERVAL=0'; + $this->vcal->add($ev); + + $it = new Recur\EventIterator($this->vcal, 'uuid'); + $it->fastForward(new DateTimeImmutable('2013-01-01 23:00:00', new DateTimeZone('UTC'))); + + // if we got this far.. it means we are no longer infinitely looping + } +} diff --git a/vendor/sabre/vobject/tests/VObject/Recur/EventIterator/Issue26Test.php b/vendor/sabre/vobject/tests/VObject/Recur/EventIterator/Issue26Test.php new file mode 100644 index 000000000..bb4df64df --- /dev/null +++ b/vendor/sabre/vobject/tests/VObject/Recur/EventIterator/Issue26Test.php @@ -0,0 +1,33 @@ +assertInstanceOf('Sabre\\VObject\\Component\\VCalendar', $vcal); + + $it = new EventIterator($vcal, 'bae5d57a98'); + } +} diff --git a/vendor/sabre/vobject/tests/VObject/Recur/EventIterator/Issue48Test.php b/vendor/sabre/vobject/tests/VObject/Recur/EventIterator/Issue48Test.php new file mode 100644 index 000000000..f08f0ccce --- /dev/null +++ b/vendor/sabre/vobject/tests/VObject/Recur/EventIterator/Issue48Test.php @@ -0,0 +1,49 @@ +assertInstanceOf('Sabre\\VObject\\Component\\VCalendar', $vcal); + + $it = new EventIterator($vcal, 'foo'); + + $result = iterator_to_array($it); + + $tz = new DateTimeZone('Europe/Moscow'); + + $expected = [ + new DateTimeImmutable('2013-07-10 11:00:00', $tz), + new DateTimeImmutable('2013-07-12 11:00:00', $tz), + new DateTimeImmutable('2013-07-13 11:00:00', $tz), + ]; + + $this->assertEquals($expected, $result); + } +} diff --git a/vendor/sabre/vobject/tests/VObject/Recur/EventIterator/Issue50Test.php b/vendor/sabre/vobject/tests/VObject/Recur/EventIterator/Issue50Test.php new file mode 100644 index 000000000..faa04e829 --- /dev/null +++ b/vendor/sabre/vobject/tests/VObject/Recur/EventIterator/Issue50Test.php @@ -0,0 +1,126 @@ +assertInstanceOf('Sabre\\VObject\\Component\\VCalendar', $vcal); + + $it = new EventIterator($vcal, '1aef0b27-3d92-4581-829a-11999dd36724'); + + $result = []; + foreach ($it as $instance) { + $result[] = $instance; + } + + $tz = new DateTimeZone('Europe/Brussels'); + + $this->assertEquals([ + new DateTimeImmutable('2013-07-15 09:00:00', $tz), + new DateTimeImmutable('2013-07-16 07:00:00', $tz), + new DateTimeImmutable('2013-07-17 07:00:00', $tz), + new DateTimeImmutable('2013-07-18 09:00:00', $tz), + new DateTimeImmutable('2013-07-19 07:00:00', $tz), + ], $result); + } +} diff --git a/vendor/sabre/vobject/tests/VObject/Recur/EventIterator/MainTest.php b/vendor/sabre/vobject/tests/VObject/Recur/EventIterator/MainTest.php new file mode 100644 index 000000000..10782a53a --- /dev/null +++ b/vendor/sabre/vobject/tests/VObject/Recur/EventIterator/MainTest.php @@ -0,0 +1,1414 @@ +createComponent('VEVENT'); + $ev->UID = 'bla'; + $ev->RRULE = 'FREQ=DAILY;BYHOUR=10;BYMINUTE=5;BYSECOND=16;BYWEEKNO=32;BYYEARDAY=100,200'; + $dtStart = $vcal->createProperty('DTSTART'); + $dtStart->setDateTime(new DateTimeImmutable('2011-10-07')); + + $ev->add($dtStart); + + $vcal->add($ev); + + $it = new EventIterator($vcal, (string) $ev->UID); + + $this->assertTrue($it->isInfinite()); + } + + /** + * @expectedException \Sabre\VObject\InvalidDataException + * @depends testValues + */ + public function testInvalidFreq() + { + $vcal = new VCalendar(); + $ev = $vcal->createComponent('VEVENT'); + $ev->RRULE = 'FREQ=SMONTHLY;INTERVAL=3;UNTIL=20111025T000000Z'; + $ev->UID = 'foo'; + $dtStart = $vcal->createProperty('DTSTART'); + $dtStart->setDateTime(new DateTimeImmutable('2011-10-07', new DateTimeZone('UTC'))); + + $ev->add($dtStart); + $vcal->add($ev); + + $it = new EventIterator($vcal, (string) $ev->UID); + } + + /** + * @expectedException \InvalidArgumentException + */ + public function testVCalendarNoUID() + { + $vcal = new VCalendar(); + $it = new EventIterator($vcal); + } + + /** + * @expectedException \InvalidArgumentException + */ + public function testVCalendarInvalidUID() + { + $vcal = new VCalendar(); + $it = new EventIterator($vcal, 'foo'); + } + + /** + * @depends testValues + */ + public function testHourly() + { + $vcal = new VCalendar(); + $ev = $vcal->createComponent('VEVENT'); + + $ev->UID = 'bla'; + $ev->RRULE = 'FREQ=HOURLY;INTERVAL=3;UNTIL=20111025T000000Z'; + $dtStart = $vcal->createProperty('DTSTART'); + $dtStart->setDateTime(new DateTimeImmutable('2011-10-07 12:00:00', new DateTimeZone('UTC'))); + + $ev->add($dtStart); + $vcal->add($ev); + + $it = new EventIterator($vcal, $ev->UID); + + // Max is to prevent overflow + $max = 12; + $result = []; + foreach ($it as $item) { + $result[] = $item; + --$max; + + if (!$max) { + break; + } + } + + $tz = new DateTimeZone('UTC'); + + $this->assertEquals( + [ + new DateTimeImmutable('2011-10-07 12:00:00', $tz), + new DateTimeImmutable('2011-10-07 15:00:00', $tz), + new DateTimeImmutable('2011-10-07 18:00:00', $tz), + new DateTimeImmutable('2011-10-07 21:00:00', $tz), + new DateTimeImmutable('2011-10-08 00:00:00', $tz), + new DateTimeImmutable('2011-10-08 03:00:00', $tz), + new DateTimeImmutable('2011-10-08 06:00:00', $tz), + new DateTimeImmutable('2011-10-08 09:00:00', $tz), + new DateTimeImmutable('2011-10-08 12:00:00', $tz), + new DateTimeImmutable('2011-10-08 15:00:00', $tz), + new DateTimeImmutable('2011-10-08 18:00:00', $tz), + new DateTimeImmutable('2011-10-08 21:00:00', $tz), + ], + $result + ); + } + + /** + * @depends testValues + */ + public function testDaily() + { + $vcal = new VCalendar(); + $ev = $vcal->createComponent('VEVENT'); + + $ev->UID = 'bla'; + $ev->RRULE = 'FREQ=DAILY;INTERVAL=3;UNTIL=20111025T000000Z'; + $dtStart = $vcal->createProperty('DTSTART'); + $dtStart->setDateTime(new DateTimeImmutable('2011-10-07', new DateTimeZone('UTC'))); + + $ev->add($dtStart); + + $vcal->add($ev); + + $it = new EventIterator($vcal, $ev->UID); + + // Max is to prevent overflow + $max = 12; + $result = []; + foreach ($it as $item) { + $result[] = $item; + --$max; + + if (!$max) { + break; + } + } + + $tz = new DateTimeZone('UTC'); + + $this->assertEquals( + [ + new DateTimeImmutable('2011-10-07', $tz), + new DateTimeImmutable('2011-10-10', $tz), + new DateTimeImmutable('2011-10-13', $tz), + new DateTimeImmutable('2011-10-16', $tz), + new DateTimeImmutable('2011-10-19', $tz), + new DateTimeImmutable('2011-10-22', $tz), + new DateTimeImmutable('2011-10-25', $tz), + ], + $result + ); + } + + /** + * @depends testValues + */ + public function testNoRRULE() + { + $vcal = new VCalendar(); + $ev = $vcal->createComponent('VEVENT'); + + $ev->UID = 'bla'; + $dtStart = $vcal->createProperty('DTSTART'); + $dtStart->setDateTime(new DateTimeImmutable('2011-10-07', new DateTimeZone('UTC'))); + + $ev->add($dtStart); + + $vcal->add($ev); + + $it = new EventIterator($vcal, $ev->UID); + + // Max is to prevent overflow + $max = 12; + $result = []; + foreach ($it as $item) { + $result[] = $item; + --$max; + + if (!$max) { + break; + } + } + + $tz = new DateTimeZone('UTC'); + + $this->assertEquals( + [ + new DateTimeImmutable('2011-10-07', $tz), + ], + $result + ); + } + + /** + * @depends testValues + */ + public function testDailyByDayByHour() + { + $vcal = new VCalendar(); + $ev = $vcal->createComponent('VEVENT'); + + $ev->UID = 'bla'; + $ev->RRULE = 'FREQ=DAILY;BYDAY=SA,SU;BYHOUR=6,7'; + $dtStart = $vcal->createProperty('DTSTART'); + $dtStart->setDateTime(new DateTimeImmutable('2011-10-08 06:00:00', new DateTimeZone('UTC'))); + + $ev->add($dtStart); + + $vcal->add($ev); + + $it = new EventIterator($vcal, (string) $ev->UID); + + // Grabbing the next 12 items + $max = 12; + $result = []; + foreach ($it as $item) { + $result[] = $item; + --$max; + + if (!$max) { + break; + } + } + + $tz = new DateTimeZone('UTC'); + + $this->assertEquals( + [ + new DateTimeImmutable('2011-10-08 06:00:00', $tz), + new DateTimeImmutable('2011-10-08 07:00:00', $tz), + new DateTimeImmutable('2011-10-09 06:00:00', $tz), + new DateTimeImmutable('2011-10-09 07:00:00', $tz), + new DateTimeImmutable('2011-10-15 06:00:00', $tz), + new DateTimeImmutable('2011-10-15 07:00:00', $tz), + new DateTimeImmutable('2011-10-16 06:00:00', $tz), + new DateTimeImmutable('2011-10-16 07:00:00', $tz), + new DateTimeImmutable('2011-10-22 06:00:00', $tz), + new DateTimeImmutable('2011-10-22 07:00:00', $tz), + new DateTimeImmutable('2011-10-23 06:00:00', $tz), + new DateTimeImmutable('2011-10-23 07:00:00', $tz), + ], + $result + ); + } + + /** + * @depends testValues + */ + public function testDailyByHour() + { + $vcal = new VCalendar(); + $ev = $vcal->createComponent('VEVENT'); + + $ev->UID = 'bla'; + $ev->RRULE = 'FREQ=DAILY;INTERVAL=2;BYHOUR=10,11,12,13,14,15'; + $dtStart = $vcal->createProperty('DTSTART'); + $dtStart->setDateTime(new DateTimeImmutable('2012-10-11 12:00:00', new DateTimeZone('UTC'))); + + $ev->add($dtStart); + + $vcal->add($ev); + + $it = new EventIterator($vcal, (string) $ev->UID); + + // Grabbing the next 12 items + $max = 12; + $result = []; + foreach ($it as $item) { + $result[] = $item; + --$max; + + if (!$max) { + break; + } + } + + $tz = new DateTimeZone('UTC'); + + $this->assertEquals( + [ + new DateTimeImmutable('2012-10-11 12:00:00', $tz), + new DateTimeImmutable('2012-10-11 13:00:00', $tz), + new DateTimeImmutable('2012-10-11 14:00:00', $tz), + new DateTimeImmutable('2012-10-11 15:00:00', $tz), + new DateTimeImmutable('2012-10-13 10:00:00', $tz), + new DateTimeImmutable('2012-10-13 11:00:00', $tz), + new DateTimeImmutable('2012-10-13 12:00:00', $tz), + new DateTimeImmutable('2012-10-13 13:00:00', $tz), + new DateTimeImmutable('2012-10-13 14:00:00', $tz), + new DateTimeImmutable('2012-10-13 15:00:00', $tz), + new DateTimeImmutable('2012-10-15 10:00:00', $tz), + new DateTimeImmutable('2012-10-15 11:00:00', $tz), + ], + $result + ); + } + + /** + * @depends testValues + */ + public function testDailyByDay() + { + $vcal = new VCalendar(); + $ev = $vcal->createComponent('VEVENT'); + + $ev->UID = 'bla'; + $ev->RRULE = 'FREQ=DAILY;INTERVAL=2;BYDAY=TU,WE,FR'; + $dtStart = $vcal->createProperty('DTSTART'); + $dtStart->setDateTime(new DateTimeImmutable('2011-10-07', new DateTimeZone('UTC'))); + + $ev->add($dtStart); + + $vcal->add($ev); + + $it = new EventIterator($vcal, (string) $ev->UID); + + // Grabbing the next 12 items + $max = 12; + $result = []; + foreach ($it as $item) { + $result[] = $item; + --$max; + + if (!$max) { + break; + } + } + + $tz = new DateTimeZone('UTC'); + + $this->assertEquals( + [ + new DateTimeImmutable('2011-10-07', $tz), + new DateTimeImmutable('2011-10-11', $tz), + new DateTimeImmutable('2011-10-19', $tz), + new DateTimeImmutable('2011-10-21', $tz), + new DateTimeImmutable('2011-10-25', $tz), + new DateTimeImmutable('2011-11-02', $tz), + new DateTimeImmutable('2011-11-04', $tz), + new DateTimeImmutable('2011-11-08', $tz), + new DateTimeImmutable('2011-11-16', $tz), + new DateTimeImmutable('2011-11-18', $tz), + new DateTimeImmutable('2011-11-22', $tz), + new DateTimeImmutable('2011-11-30', $tz), + ], + $result + ); + } + + /** + * @depends testValues + */ + public function testWeekly() + { + $vcal = new VCalendar(); + $ev = $vcal->createComponent('VEVENT'); + + $ev->UID = 'bla'; + $ev->RRULE = 'FREQ=WEEKLY;INTERVAL=2;COUNT=10'; + $dtStart = $vcal->createProperty('DTSTART'); + $dtStart->setDateTime(new DateTimeImmutable('2011-10-07', new DateTimeZone('UTC'))); + + $ev->add($dtStart); + + $vcal->add($ev); + + $it = new EventIterator($vcal, (string) $ev->UID); + + // Max is to prevent overflow + $max = 12; + $result = []; + foreach ($it as $item) { + $result[] = $item; + --$max; + + if (!$max) { + break; + } + } + + $tz = new DateTimeZone('UTC'); + + $this->assertEquals( + [ + new DateTimeImmutable('2011-10-07', $tz), + new DateTimeImmutable('2011-10-21', $tz), + new DateTimeImmutable('2011-11-04', $tz), + new DateTimeImmutable('2011-11-18', $tz), + new DateTimeImmutable('2011-12-02', $tz), + new DateTimeImmutable('2011-12-16', $tz), + new DateTimeImmutable('2011-12-30', $tz), + new DateTimeImmutable('2012-01-13', $tz), + new DateTimeImmutable('2012-01-27', $tz), + new DateTimeImmutable('2012-02-10', $tz), + ], + $result + ); + } + + /** + * @depends testValues + */ + public function testWeeklyByDayByHour() + { + $vcal = new VCalendar(); + $ev = $vcal->createComponent('VEVENT'); + + $ev->UID = 'bla'; + $ev->RRULE = 'FREQ=WEEKLY;INTERVAL=2;BYDAY=TU,WE,FR;WKST=MO;BYHOUR=8,9,10'; + $dtStart = $vcal->createProperty('DTSTART'); + $dtStart->setDateTime(new DateTimeImmutable('2011-10-07 08:00:00', new DateTimeZone('UTC'))); + + $ev->add($dtStart); + + $vcal->add($ev); + + $it = new EventIterator($vcal, (string) $ev->UID); + + // Grabbing the next 12 items + $max = 15; + $result = []; + foreach ($it as $item) { + $result[] = $item; + --$max; + + if (!$max) { + break; + } + } + + $tz = new DateTimeZone('UTC'); + + $this->assertEquals( + [ + new DateTimeImmutable('2011-10-07 08:00:00', $tz), + new DateTimeImmutable('2011-10-07 09:00:00', $tz), + new DateTimeImmutable('2011-10-07 10:00:00', $tz), + new DateTimeImmutable('2011-10-18 08:00:00', $tz), + new DateTimeImmutable('2011-10-18 09:00:00', $tz), + new DateTimeImmutable('2011-10-18 10:00:00', $tz), + new DateTimeImmutable('2011-10-19 08:00:00', $tz), + new DateTimeImmutable('2011-10-19 09:00:00', $tz), + new DateTimeImmutable('2011-10-19 10:00:00', $tz), + new DateTimeImmutable('2011-10-21 08:00:00', $tz), + new DateTimeImmutable('2011-10-21 09:00:00', $tz), + new DateTimeImmutable('2011-10-21 10:00:00', $tz), + new DateTimeImmutable('2011-11-01 08:00:00', $tz), + new DateTimeImmutable('2011-11-01 09:00:00', $tz), + new DateTimeImmutable('2011-11-01 10:00:00', $tz), + ], + $result + ); + } + + /** + * @depends testValues + */ + public function testWeeklyByDaySpecificHour() + { + $vcal = new VCalendar(); + $ev = $vcal->createComponent('VEVENT'); + + $ev->UID = 'bla'; + $ev->RRULE = 'FREQ=WEEKLY;INTERVAL=2;BYDAY=TU,WE,FR;WKST=SU'; + $dtStart = $vcal->createProperty('DTSTART'); + $dtStart->setDateTime(new DateTimeImmutable('2011-10-07 18:00:00', new DateTimeZone('UTC'))); + + $ev->add($dtStart); + + $vcal->add($ev); + + $it = new EventIterator($vcal, (string) $ev->UID); + + // Grabbing the next 12 items + $max = 12; + $result = []; + foreach ($it as $item) { + $result[] = $item; + --$max; + + if (!$max) { + break; + } + } + + $tz = new DateTimeZone('UTC'); + + $this->assertEquals( + [ + new DateTimeImmutable('2011-10-07 18:00:00', $tz), + new DateTimeImmutable('2011-10-18 18:00:00', $tz), + new DateTimeImmutable('2011-10-19 18:00:00', $tz), + new DateTimeImmutable('2011-10-21 18:00:00', $tz), + new DateTimeImmutable('2011-11-01 18:00:00', $tz), + new DateTimeImmutable('2011-11-02 18:00:00', $tz), + new DateTimeImmutable('2011-11-04 18:00:00', $tz), + new DateTimeImmutable('2011-11-15 18:00:00', $tz), + new DateTimeImmutable('2011-11-16 18:00:00', $tz), + new DateTimeImmutable('2011-11-18 18:00:00', $tz), + new DateTimeImmutable('2011-11-29 18:00:00', $tz), + new DateTimeImmutable('2011-11-30 18:00:00', $tz), + ], + $result + ); + } + + /** + * @depends testValues + */ + public function testWeeklyByDay() + { + $vcal = new VCalendar(); + $ev = $vcal->createComponent('VEVENT'); + + $ev->UID = 'bla'; + $ev->RRULE = 'FREQ=WEEKLY;INTERVAL=2;BYDAY=TU,WE,FR;WKST=SU'; + $dtStart = $vcal->createProperty('DTSTART'); + $dtStart->setDateTime(new DateTimeImmutable('2011-10-07', new DateTimeZone('UTC'))); + + $ev->add($dtStart); + + $vcal->add($ev); + + $it = new EventIterator($vcal, (string) $ev->UID); + + // Grabbing the next 12 items + $max = 12; + $result = []; + foreach ($it as $item) { + $result[] = $item; + --$max; + + if (!$max) { + break; + } + } + + $tz = new DateTimeZone('UTC'); + + $this->assertEquals( + [ + new DateTimeImmutable('2011-10-07', $tz), + new DateTimeImmutable('2011-10-18', $tz), + new DateTimeImmutable('2011-10-19', $tz), + new DateTimeImmutable('2011-10-21', $tz), + new DateTimeImmutable('2011-11-01', $tz), + new DateTimeImmutable('2011-11-02', $tz), + new DateTimeImmutable('2011-11-04', $tz), + new DateTimeImmutable('2011-11-15', $tz), + new DateTimeImmutable('2011-11-16', $tz), + new DateTimeImmutable('2011-11-18', $tz), + new DateTimeImmutable('2011-11-29', $tz), + new DateTimeImmutable('2011-11-30', $tz), + ], + $result + ); + } + + /** + * @depends testValues + */ + public function testMonthly() + { + $vcal = new VCalendar(); + $ev = $vcal->createComponent('VEVENT'); + + $ev->UID = 'bla'; + $ev->RRULE = 'FREQ=MONTHLY;INTERVAL=3;COUNT=5'; + $dtStart = $vcal->createProperty('DTSTART'); + $dtStart->setDateTime(new DateTimeImmutable('2011-12-05', new DateTimeZone('UTC'))); + + $ev->add($dtStart); + + $vcal->add($ev); + + $it = new EventIterator($vcal, (string) $ev->UID); + + $max = 14; + $result = []; + foreach ($it as $item) { + $result[] = $item; + --$max; + + if (!$max) { + break; + } + } + + $tz = new DateTimeZone('UTC'); + + $this->assertEquals( + [ + new DateTimeImmutable('2011-12-05', $tz), + new DateTimeImmutable('2012-03-05', $tz), + new DateTimeImmutable('2012-06-05', $tz), + new DateTimeImmutable('2012-09-05', $tz), + new DateTimeImmutable('2012-12-05', $tz), + ], + $result + ); + } + + /** + * @depends testValues + */ + public function testMonthlyEndOfMonth() + { + $vcal = new VCalendar(); + $ev = $vcal->createComponent('VEVENT'); + + $ev->UID = 'bla'; + $ev->RRULE = 'FREQ=MONTHLY;INTERVAL=2;COUNT=12'; + $dtStart = $vcal->createProperty('DTSTART'); + $dtStart->setDateTime(new DateTimeImmutable('2011-12-31', new DateTimeZone('UTC'))); + + $ev->add($dtStart); + + $vcal->add($ev); + + $it = new EventIterator($vcal, (string) $ev->UID); + + $max = 14; + $result = []; + foreach ($it as $item) { + $result[] = $item; + --$max; + + if (!$max) { + break; + } + } + + $tz = new DateTimeZone('UTC'); + + $this->assertEquals( + [ + new DateTimeImmutable('2011-12-31', $tz), + new DateTimeImmutable('2012-08-31', $tz), + new DateTimeImmutable('2012-10-31', $tz), + new DateTimeImmutable('2012-12-31', $tz), + new DateTimeImmutable('2013-08-31', $tz), + new DateTimeImmutable('2013-10-31', $tz), + new DateTimeImmutable('2013-12-31', $tz), + new DateTimeImmutable('2014-08-31', $tz), + new DateTimeImmutable('2014-10-31', $tz), + new DateTimeImmutable('2014-12-31', $tz), + new DateTimeImmutable('2015-08-31', $tz), + new DateTimeImmutable('2015-10-31', $tz), + ], + $result + ); + } + + /** + * @depends testValues + */ + public function testMonthlyByMonthDay() + { + $vcal = new VCalendar(); + $ev = $vcal->createComponent('VEVENT'); + + $ev->UID = 'bla'; + $ev->RRULE = 'FREQ=MONTHLY;INTERVAL=5;COUNT=9;BYMONTHDAY=1,31,-7'; + $dtStart = $vcal->createProperty('DTSTART'); + $dtStart->setDateTime(new DateTimeImmutable('2011-01-01', new DateTimeZone('UTC'))); + + $ev->add($dtStart); + + $vcal->add($ev); + + $it = new EventIterator($vcal, (string) $ev->UID); + + $max = 14; + $result = []; + foreach ($it as $item) { + $result[] = $item; + --$max; + + if (!$max) { + break; + } + } + + $tz = new DateTimeZone('UTC'); + + $this->assertEquals( + [ + new DateTimeImmutable('2011-01-01', $tz), + new DateTimeImmutable('2011-01-25', $tz), + new DateTimeImmutable('2011-01-31', $tz), + new DateTimeImmutable('2011-06-01', $tz), + new DateTimeImmutable('2011-06-24', $tz), + new DateTimeImmutable('2011-11-01', $tz), + new DateTimeImmutable('2011-11-24', $tz), + new DateTimeImmutable('2012-04-01', $tz), + new DateTimeImmutable('2012-04-24', $tz), + ], + $result + ); + } + + /** + * A pretty slow test. Had to be marked as 'medium' for phpunit to not die + * after 1 second. Would be good to optimize later. + * + * @depends testValues + * @medium + */ + public function testMonthlyByDay() + { + $vcal = new VCalendar(); + $ev = $vcal->createComponent('VEVENT'); + + $ev->UID = 'bla'; + $ev->RRULE = 'FREQ=MONTHLY;INTERVAL=2;COUNT=16;BYDAY=MO,-2TU,+1WE,3TH'; + $dtStart = $vcal->createProperty('DTSTART'); + $dtStart->setDateTime(new DateTimeImmutable('2011-01-03', new DateTimeZone('UTC'))); + + $ev->add($dtStart); + + $vcal->add($ev); + + $it = new EventIterator($vcal, (string) $ev->UID); + + $max = 20; + $result = []; + foreach ($it as $item) { + $result[] = $item; + --$max; + + if (!$max) { + break; + } + } + + $tz = new DateTimeZone('UTC'); + + $this->assertEquals( + [ + new DateTimeImmutable('2011-01-03', $tz), + new DateTimeImmutable('2011-01-05', $tz), + new DateTimeImmutable('2011-01-10', $tz), + new DateTimeImmutable('2011-01-17', $tz), + new DateTimeImmutable('2011-01-18', $tz), + new DateTimeImmutable('2011-01-20', $tz), + new DateTimeImmutable('2011-01-24', $tz), + new DateTimeImmutable('2011-01-31', $tz), + new DateTimeImmutable('2011-03-02', $tz), + new DateTimeImmutable('2011-03-07', $tz), + new DateTimeImmutable('2011-03-14', $tz), + new DateTimeImmutable('2011-03-17', $tz), + new DateTimeImmutable('2011-03-21', $tz), + new DateTimeImmutable('2011-03-22', $tz), + new DateTimeImmutable('2011-03-28', $tz), + new DateTimeImmutable('2011-05-02', $tz), + ], + $result + ); + } + + /** + * @depends testValues + */ + public function testMonthlyByDayByMonthDay() + { + $vcal = new VCalendar(); + $ev = $vcal->createComponent('VEVENT'); + + $ev->UID = 'bla'; + $ev->RRULE = 'FREQ=MONTHLY;COUNT=10;BYDAY=MO;BYMONTHDAY=1'; + $dtStart = $vcal->createProperty('DTSTART'); + $dtStart->setDateTime(new DateTimeImmutable('2011-08-01', new DateTimeZone('UTC'))); + + $ev->add($dtStart); + + $vcal->add($ev); + + $it = new EventIterator($vcal, (string) $ev->UID); + + $max = 20; + $result = []; + foreach ($it as $item) { + $result[] = $item; + --$max; + + if (!$max) { + break; + } + } + + $tz = new DateTimeZone('UTC'); + + $this->assertEquals( + [ + new DateTimeImmutable('2011-08-01', $tz), + new DateTimeImmutable('2012-10-01', $tz), + new DateTimeImmutable('2013-04-01', $tz), + new DateTimeImmutable('2013-07-01', $tz), + new DateTimeImmutable('2014-09-01', $tz), + new DateTimeImmutable('2014-12-01', $tz), + new DateTimeImmutable('2015-06-01', $tz), + new DateTimeImmutable('2016-02-01', $tz), + new DateTimeImmutable('2016-08-01', $tz), + new DateTimeImmutable('2017-05-01', $tz), + ], + $result + ); + } + + /** + * @depends testValues + */ + public function testMonthlyByDayBySetPos() + { + $vcal = new VCalendar(); + $ev = $vcal->createComponent('VEVENT'); + + $ev->UID = 'bla'; + $ev->RRULE = 'FREQ=MONTHLY;COUNT=10;BYDAY=MO,TU,WE,TH,FR;BYSETPOS=1,-1'; + $dtStart = $vcal->createProperty('DTSTART'); + $dtStart->setDateTime(new DateTimeImmutable('2011-01-03', new DateTimeZone('UTC'))); + + $ev->add($dtStart); + + $vcal->add($ev); + + $it = new EventIterator($vcal, (string) $ev->UID); + + $max = 20; + $result = []; + foreach ($it as $item) { + $result[] = $item; + --$max; + + if (!$max) { + break; + } + } + + $tz = new DateTimeZone('UTC'); + + $this->assertEquals( + [ + new DateTimeImmutable('2011-01-03', $tz), + new DateTimeImmutable('2011-01-31', $tz), + new DateTimeImmutable('2011-02-01', $tz), + new DateTimeImmutable('2011-02-28', $tz), + new DateTimeImmutable('2011-03-01', $tz), + new DateTimeImmutable('2011-03-31', $tz), + new DateTimeImmutable('2011-04-01', $tz), + new DateTimeImmutable('2011-04-29', $tz), + new DateTimeImmutable('2011-05-02', $tz), + new DateTimeImmutable('2011-05-31', $tz), + ], + $result + ); + } + + /** + * @depends testValues + */ + public function testYearly() + { + $vcal = new VCalendar(); + $ev = $vcal->createComponent('VEVENT'); + + $ev->UID = 'bla'; + $ev->RRULE = 'FREQ=YEARLY;COUNT=10;INTERVAL=3'; + $dtStart = $vcal->createProperty('DTSTART'); + $dtStart->setDateTime(new DateTimeImmutable('2011-01-01', new DateTimeZone('UTC'))); + + $ev->add($dtStart); + + $vcal->add($ev); + + $it = new EventIterator($vcal, (string) $ev->UID); + + $max = 20; + $result = []; + foreach ($it as $item) { + $result[] = $item; + --$max; + + if (!$max) { + break; + } + } + + $tz = new DateTimeZone('UTC'); + + $this->assertEquals( + [ + new DateTimeImmutable('2011-01-01', $tz), + new DateTimeImmutable('2014-01-01', $tz), + new DateTimeImmutable('2017-01-01', $tz), + new DateTimeImmutable('2020-01-01', $tz), + new DateTimeImmutable('2023-01-01', $tz), + new DateTimeImmutable('2026-01-01', $tz), + new DateTimeImmutable('2029-01-01', $tz), + new DateTimeImmutable('2032-01-01', $tz), + new DateTimeImmutable('2035-01-01', $tz), + new DateTimeImmutable('2038-01-01', $tz), + ], + $result + ); + } + + /** + * @depends testValues + */ + public function testYearlyLeapYear() + { + $vcal = new VCalendar(); + $ev = $vcal->createComponent('VEVENT'); + + $ev->UID = 'bla'; + $ev->RRULE = 'FREQ=YEARLY;COUNT=3'; + $dtStart = $vcal->createProperty('DTSTART'); + $dtStart->setDateTime(new DateTimeImmutable('2012-02-29', new DateTimeZone('UTC'))); + + $ev->add($dtStart); + + $vcal->add($ev); + + $it = new EventIterator($vcal, (string) $ev->UID); + + $max = 20; + $result = []; + foreach ($it as $item) { + $result[] = $item; + --$max; + + if (!$max) { + break; + } + } + + $tz = new DateTimeZone('UTC'); + + $this->assertEquals( + [ + new DateTimeImmutable('2012-02-29', $tz), + new DateTimeImmutable('2016-02-29', $tz), + new DateTimeImmutable('2020-02-29', $tz), + ], + $result + ); + } + + /** + * @depends testValues + */ + public function testYearlyByMonth() + { + $vcal = new VCalendar(); + $ev = $vcal->createComponent('VEVENT'); + + $ev->UID = 'bla'; + $ev->RRULE = 'FREQ=YEARLY;COUNT=8;INTERVAL=4;BYMONTH=4,10'; + $dtStart = $vcal->createProperty('DTSTART'); + $dtStart->setDateTime(new DateTimeImmutable('2011-04-07', new DateTimeZone('UTC'))); + + $ev->add($dtStart); + + $vcal->add($ev); + + $it = new EventIterator($vcal, (string) $ev->UID); + + $max = 20; + $result = []; + foreach ($it as $item) { + $result[] = $item; + --$max; + + if (!$max) { + break; + } + } + + $tz = new DateTimeZone('UTC'); + + $this->assertEquals( + [ + new DateTimeImmutable('2011-04-07', $tz), + new DateTimeImmutable('2011-10-07', $tz), + new DateTimeImmutable('2015-04-07', $tz), + new DateTimeImmutable('2015-10-07', $tz), + new DateTimeImmutable('2019-04-07', $tz), + new DateTimeImmutable('2019-10-07', $tz), + new DateTimeImmutable('2023-04-07', $tz), + new DateTimeImmutable('2023-10-07', $tz), + ], + $result + ); + } + + /** + * @depends testValues + */ + public function testYearlyByMonthByDay() + { + $vcal = new VCalendar(); + $ev = $vcal->createComponent('VEVENT'); + + $ev->UID = 'bla'; + $ev->RRULE = 'FREQ=YEARLY;COUNT=8;INTERVAL=5;BYMONTH=4,10;BYDAY=1MO,-1SU'; + $dtStart = $vcal->createProperty('DTSTART'); + $dtStart->setDateTime(new DateTimeImmutable('2011-04-04', new DateTimeZone('UTC'))); + + $ev->add($dtStart); + + $vcal->add($ev); + + $it = new EventIterator($vcal, (string) $ev->UID); + + $max = 20; + $result = []; + foreach ($it as $item) { + $result[] = $item; + --$max; + + if (!$max) { + break; + } + } + + $tz = new DateTimeZone('UTC'); + + $this->assertEquals( + [ + new DateTimeImmutable('2011-04-04', $tz), + new DateTimeImmutable('2011-04-24', $tz), + new DateTimeImmutable('2011-10-03', $tz), + new DateTimeImmutable('2011-10-30', $tz), + new DateTimeImmutable('2016-04-04', $tz), + new DateTimeImmutable('2016-04-24', $tz), + new DateTimeImmutable('2016-10-03', $tz), + new DateTimeImmutable('2016-10-30', $tz), + ], + $result + ); + } + + /** + * @depends testValues + */ + public function testFastForward() + { + $vcal = new VCalendar(); + $ev = $vcal->createComponent('VEVENT'); + + $ev->UID = 'bla'; + $ev->RRULE = 'FREQ=YEARLY;COUNT=8;INTERVAL=5;BYMONTH=4,10;BYDAY=1MO,-1SU'; + $dtStart = $vcal->createProperty('DTSTART'); + $dtStart->setDateTime(new DateTimeImmutable('2011-04-04', new DateTimeZone('UTC'))); + + $ev->add($dtStart); + + $vcal->add($ev); + + $it = new EventIterator($vcal, (string) $ev->UID); + + // The idea is that we're fast-forwarding too far in the future, so + // there will be no results left. + $it->fastForward(new DateTimeImmutable('2020-05-05', new DateTimeZone('UTC'))); + + $max = 20; + $result = []; + while ($item = $it->current()) { + $result[] = $item; + --$max; + + if (!$max) { + break; + } + $it->next(); + } + + $this->assertEquals([], $result); + } + + /** + * @depends testValues + */ + public function testFastForwardAllDayEventThatStopAtTheStartTime() + { + $vcal = new VCalendar(); + $ev = $vcal->createComponent('VEVENT'); + + $ev->UID = 'bla'; + $ev->RRULE = 'FREQ=DAILY'; + + $dtStart = $vcal->createProperty('DTSTART'); + $dtStart->setDateTime(new DateTimeImmutable('2011-04-04', new DateTimeZone('UTC'))); + $ev->add($dtStart); + + $dtEnd = $vcal->createProperty('DTSTART'); + $dtEnd->setDateTime(new DateTimeImmutable('2011-04-05', new DateTimeZone('UTC'))); + $ev->add($dtEnd); + + $vcal->add($ev); + + $it = new EventIterator($vcal, (string) $ev->UID); + + $it->fastForward(new DateTimeImmutable('2011-04-05T000000', new DateTimeZone('UTC'))); + + $this->assertEquals(new DateTimeImmutable('2011-04-06'), $it->getDTStart()); + } + + /** + * @depends testValues + */ + public function testComplexExclusions() + { + $vcal = new VCalendar(); + $ev = $vcal->createComponent('VEVENT'); + + $ev->UID = 'bla'; + $ev->RRULE = 'FREQ=YEARLY;COUNT=10'; + $dtStart = $vcal->createProperty('DTSTART'); + + $tz = new DateTimeZone('Canada/Eastern'); + $dtStart->setDateTime(new DateTimeImmutable('2011-01-01 13:50:20', $tz)); + + $exDate1 = $vcal->createProperty('EXDATE'); + $exDate1->setDateTimes([new DateTimeImmutable('2012-01-01 13:50:20', $tz), new DateTimeImmutable('2014-01-01 13:50:20', $tz)]); + $exDate2 = $vcal->createProperty('EXDATE'); + $exDate2->setDateTimes([new DateTimeImmutable('2016-01-01 13:50:20', $tz)]); + + $ev->add($dtStart); + $ev->add($exDate1); + $ev->add($exDate2); + + $vcal->add($ev); + + $it = new EventIterator($vcal, (string) $ev->UID); + + $max = 20; + $result = []; + foreach ($it as $item) { + $result[] = $item; + --$max; + + if (!$max) { + break; + } + } + + $this->assertEquals( + [ + new DateTimeImmutable('2011-01-01 13:50:20', $tz), + new DateTimeImmutable('2013-01-01 13:50:20', $tz), + new DateTimeImmutable('2015-01-01 13:50:20', $tz), + new DateTimeImmutable('2017-01-01 13:50:20', $tz), + new DateTimeImmutable('2018-01-01 13:50:20', $tz), + new DateTimeImmutable('2019-01-01 13:50:20', $tz), + new DateTimeImmutable('2020-01-01 13:50:20', $tz), + ], + $result + ); + } + + /** + * @depends testValues + */ + public function testOverridenEvent() + { + $vcal = new VCalendar(); + + $ev1 = $vcal->createComponent('VEVENT'); + $ev1->UID = 'overridden'; + $ev1->RRULE = 'FREQ=DAILY;COUNT=10'; + $ev1->DTSTART = '20120107T120000Z'; + $ev1->SUMMARY = 'baseEvent'; + + $vcal->add($ev1); + + // ev2 overrides an event, and puts it on 2pm instead. + $ev2 = $vcal->createComponent('VEVENT'); + $ev2->UID = 'overridden'; + $ev2->{'RECURRENCE-ID'} = '20120110T120000Z'; + $ev2->DTSTART = '20120110T140000Z'; + $ev2->SUMMARY = 'Event 2'; + + $vcal->add($ev2); + + // ev3 overrides an event, and puts it 2 days and 2 hours later + $ev3 = $vcal->createComponent('VEVENT'); + $ev3->UID = 'overridden'; + $ev3->{'RECURRENCE-ID'} = '20120113T120000Z'; + $ev3->DTSTART = '20120115T140000Z'; + $ev3->SUMMARY = 'Event 3'; + + $vcal->add($ev3); + + $it = new EventIterator($vcal, 'overridden'); + + $dates = []; + $summaries = []; + while ($it->valid()) { + $dates[] = $it->getDTStart(); + $summaries[] = (string) $it->getEventObject()->SUMMARY; + $it->next(); + } + + $tz = new DateTimeZone('UTC'); + $this->assertEquals([ + new DateTimeImmutable('2012-01-07 12:00:00', $tz), + new DateTimeImmutable('2012-01-08 12:00:00', $tz), + new DateTimeImmutable('2012-01-09 12:00:00', $tz), + new DateTimeImmutable('2012-01-10 14:00:00', $tz), + new DateTimeImmutable('2012-01-11 12:00:00', $tz), + new DateTimeImmutable('2012-01-12 12:00:00', $tz), + new DateTimeImmutable('2012-01-14 12:00:00', $tz), + new DateTimeImmutable('2012-01-15 12:00:00', $tz), + new DateTimeImmutable('2012-01-15 14:00:00', $tz), + new DateTimeImmutable('2012-01-16 12:00:00', $tz), + ], $dates); + + $this->assertEquals([ + 'baseEvent', + 'baseEvent', + 'baseEvent', + 'Event 2', + 'baseEvent', + 'baseEvent', + 'baseEvent', + 'baseEvent', + 'Event 3', + 'baseEvent', + ], $summaries); + } + + /** + * @depends testValues + */ + public function testOverridenEvent2() + { + $vcal = new VCalendar(); + + $ev1 = $vcal->createComponent('VEVENT'); + $ev1->UID = 'overridden'; + $ev1->RRULE = 'FREQ=WEEKLY;COUNT=3'; + $ev1->DTSTART = '20120112T120000Z'; + $ev1->SUMMARY = 'baseEvent'; + + $vcal->add($ev1); + + // ev2 overrides an event, and puts it 6 days earlier instead. + $ev2 = $vcal->createComponent('VEVENT'); + $ev2->UID = 'overridden'; + $ev2->{'RECURRENCE-ID'} = '20120119T120000Z'; + $ev2->DTSTART = '20120113T120000Z'; + $ev2->SUMMARY = 'Override!'; + + $vcal->add($ev2); + + $it = new EventIterator($vcal, 'overridden'); + + $dates = []; + $summaries = []; + while ($it->valid()) { + $dates[] = $it->getDTStart(); + $summaries[] = (string) $it->getEventObject()->SUMMARY; + $it->next(); + } + + $tz = new DateTimeZone('UTC'); + $this->assertEquals([ + new DateTimeImmutable('2012-01-12 12:00:00', $tz), + new DateTimeImmutable('2012-01-13 12:00:00', $tz), + new DateTimeImmutable('2012-01-26 12:00:00', $tz), + ], $dates); + + $this->assertEquals([ + 'baseEvent', + 'Override!', + 'baseEvent', + ], $summaries); + } + + /** + * @depends testValues + */ + public function testOverridenEventNoValuesExpected() + { + $vcal = new VCalendar(); + $ev1 = $vcal->createComponent('VEVENT'); + + $ev1->UID = 'overridden'; + $ev1->RRULE = 'FREQ=WEEKLY;COUNT=3'; + $ev1->DTSTART = '20120124T120000Z'; + $ev1->SUMMARY = 'baseEvent'; + + $vcal->add($ev1); + + // ev2 overrides an event, and puts it 6 days earlier instead. + $ev2 = $vcal->createComponent('VEVENT'); + $ev2->UID = 'overridden'; + $ev2->{'RECURRENCE-ID'} = '20120131T120000Z'; + $ev2->DTSTART = '20120125T120000Z'; + $ev2->SUMMARY = 'Override!'; + + $vcal->add($ev2); + + $it = new EventIterator($vcal, 'overridden'); + + $dates = []; + $summaries = []; + + // The reported problem was specifically related to the VCALENDAR + // expansion. In this parcitular case, we had to forward to the 28th of + // january. + $it->fastForward(new DateTimeImmutable('2012-01-28 23:00:00')); + + // We stop the loop when it hits the 6th of februari. Normally this + // iterator would hit 24, 25 (overriden from 31) and 7 feb but because + // we 'filter' from the 28th till the 6th, we should get 0 results. + while ($it->valid() && $it->getDTStart() < new DateTimeImmutable('2012-02-06 23:00:00')) { + $dates[] = $it->getDTStart(); + $summaries[] = (string) $it->getEventObject()->SUMMARY; + $it->next(); + } + + $this->assertEquals([], $dates); + $this->assertEquals([], $summaries); + } + + /** + * @depends testValues + */ + public function testRDATE() + { + $vcal = new VCalendar(); + $ev = $vcal->createComponent('VEVENT'); + + $ev->UID = 'bla'; + $ev->RDATE = [ + new DateTimeImmutable('2014-08-07', new DateTimeZone('UTC')), + new DateTimeImmutable('2014-08-08', new DateTimeZone('UTC')), + ]; + $dtStart = $vcal->createProperty('DTSTART'); + $dtStart->setDateTime(new DateTimeImmutable('2011-10-07', new DateTimeZone('UTC'))); + + $ev->add($dtStart); + + $vcal->add($ev); + + $it = new EventIterator($vcal, $ev->UID); + + // Max is to prevent overflow + $max = 12; + $result = []; + foreach ($it as $item) { + $result[] = $item; + --$max; + + if (!$max) { + break; + } + } + + $tz = new DateTimeZone('UTC'); + + $this->assertEquals( + [ + new DateTimeImmutable('2011-10-07', $tz), + new DateTimeImmutable('2014-08-07', $tz), + new DateTimeImmutable('2014-08-08', $tz), + ], + $result + ); + } + + /** + * @depends testValues + * @expectedException \InvalidArgumentException + */ + public function testNoMasterBadUID() + { + $vcal = new VCalendar(); + // ev2 overrides an event, and puts it on 2pm instead. + $ev2 = $vcal->createComponent('VEVENT'); + $ev2->UID = 'overridden'; + $ev2->{'RECURRENCE-ID'} = '20120110T120000Z'; + $ev2->DTSTART = '20120110T140000Z'; + $ev2->SUMMARY = 'Event 2'; + + $vcal->add($ev2); + + // ev3 overrides an event, and puts it 2 days and 2 hours later + $ev3 = $vcal->createComponent('VEVENT'); + $ev3->UID = 'overridden'; + $ev3->{'RECURRENCE-ID'} = '20120113T120000Z'; + $ev3->DTSTART = '20120115T140000Z'; + $ev3->SUMMARY = 'Event 3'; + + $vcal->add($ev3); + + $it = new EventIterator($vcal, 'broken'); + } +} diff --git a/vendor/sabre/vobject/tests/VObject/Recur/EventIterator/MaxInstancesTest.php b/vendor/sabre/vobject/tests/VObject/Recur/EventIterator/MaxInstancesTest.php new file mode 100644 index 000000000..d0571ee82 --- /dev/null +++ b/vendor/sabre/vobject/tests/VObject/Recur/EventIterator/MaxInstancesTest.php @@ -0,0 +1,38 @@ +expand(new DateTime('2014-08-01'), new DateTime('2014-09-01')); + } finally { + Settings::$maxRecurrences = $temp; + } + } +} diff --git a/vendor/sabre/vobject/tests/VObject/Recur/EventIterator/MissingOverriddenTest.php b/vendor/sabre/vobject/tests/VObject/Recur/EventIterator/MissingOverriddenTest.php new file mode 100644 index 000000000..5ed47238d --- /dev/null +++ b/vendor/sabre/vobject/tests/VObject/Recur/EventIterator/MissingOverriddenTest.php @@ -0,0 +1,61 @@ +assertInstanceOf('Sabre\\VObject\\Component\\VCalendar', $vcal); + + $vcal = $vcal->expand(new DateTime('2011-01-01'), new DateTime('2015-01-01')); + + $output = <<assertVObjectEqualsVObject($output, $vcal); + } +} diff --git a/vendor/sabre/vobject/tests/VObject/Recur/EventIterator/NoInstancesTest.php b/vendor/sabre/vobject/tests/VObject/Recur/EventIterator/NoInstancesTest.php new file mode 100644 index 000000000..24810db14 --- /dev/null +++ b/vendor/sabre/vobject/tests/VObject/Recur/EventIterator/NoInstancesTest.php @@ -0,0 +1,39 @@ +assertInstanceOf('Sabre\\VObject\\Component\\VCalendar', $vcal); + + $it = new EventIterator($vcal, 'foo'); + } +} diff --git a/vendor/sabre/vobject/tests/VObject/Recur/EventIterator/OverrideFirstEventTest.php b/vendor/sabre/vobject/tests/VObject/Recur/EventIterator/OverrideFirstEventTest.php new file mode 100644 index 000000000..150a13980 --- /dev/null +++ b/vendor/sabre/vobject/tests/VObject/Recur/EventIterator/OverrideFirstEventTest.php @@ -0,0 +1,119 @@ +expand(new DateTime('2014-08-01'), new DateTime('2014-09-01')); + + $expected = <<assertVObjectEqualsVObject( + $expected, + $vcal + ); + } + + public function testRemoveFirstEvent() + { + $input = <<expand(new DateTime('2014-08-01'), new DateTime('2014-08-19')); + + $expected = <<assertVObjectEqualsVObject( + $expected, + $vcal + ); + } +} diff --git a/vendor/sabre/vobject/tests/VObject/Recur/EventIterator/SameDateForRecurringEventsTest.php b/vendor/sabre/vobject/tests/VObject/Recur/EventIterator/SameDateForRecurringEventsTest.php new file mode 100644 index 000000000..1cbd9792e --- /dev/null +++ b/vendor/sabre/vobject/tests/VObject/Recur/EventIterator/SameDateForRecurringEventsTest.php @@ -0,0 +1,56 @@ +getComponents()); + + $this->assertEquals(4, iterator_count($eventIterator), 'in ICS 4 events'); + } +} diff --git a/vendor/sabre/vobject/tests/VObject/Recur/RDateIteratorTest.php b/vendor/sabre/vobject/tests/VObject/Recur/RDateIteratorTest.php new file mode 100644 index 000000000..453d8cf73 --- /dev/null +++ b/vendor/sabre/vobject/tests/VObject/Recur/RDateIteratorTest.php @@ -0,0 +1,74 @@ +assertEquals( + $expected, + iterator_to_array($it) + ); + + $this->assertFalse($it->isInfinite()); + } + + public function testTimezone() + { + $tz = new DateTimeZone('Europe/Berlin'); + $it = new RDateIterator('20140901T000000,20141001T000000', new DateTimeImmutable('2014-08-01 00:00:00', $tz)); + + $expected = [ + new DateTimeImmutable('2014-08-01 00:00:00', $tz), + new DateTimeImmutable('2014-09-01 00:00:00', $tz), + new DateTimeImmutable('2014-10-01 00:00:00', $tz), + ]; + + $this->assertEquals( + $expected, + iterator_to_array($it) + ); + + $this->assertFalse($it->isInfinite()); + } + + public function testFastForward() + { + $utc = new DateTimeZone('UTC'); + $it = new RDateIterator('20140901T000000Z,20141001T000000Z', new DateTimeImmutable('2014-08-01 00:00:00', $utc)); + + $it->fastForward(new DateTimeImmutable('2014-08-15 00:00:00')); + + $result = []; + while ($it->valid()) { + $result[] = $it->current(); + $it->next(); + } + + $expected = [ + new DateTimeImmutable('2014-09-01 00:00:00', $utc), + new DateTimeImmutable('2014-10-01 00:00:00', $utc), + ]; + + $this->assertEquals( + $expected, + $result + ); + + $this->assertFalse($it->isInfinite()); + } +} diff --git a/vendor/sabre/vobject/tests/VObject/Recur/RRuleIteratorTest.php b/vendor/sabre/vobject/tests/VObject/Recur/RRuleIteratorTest.php new file mode 100644 index 000000000..b6a8fdc53 --- /dev/null +++ b/vendor/sabre/vobject/tests/VObject/Recur/RRuleIteratorTest.php @@ -0,0 +1,976 @@ +parse( + 'FREQ=HOURLY;INTERVAL=3;COUNT=12', + '2011-10-07 12:00:00', + [ + '2011-10-07 12:00:00', + '2011-10-07 15:00:00', + '2011-10-07 18:00:00', + '2011-10-07 21:00:00', + '2011-10-08 00:00:00', + '2011-10-08 03:00:00', + '2011-10-08 06:00:00', + '2011-10-08 09:00:00', + '2011-10-08 12:00:00', + '2011-10-08 15:00:00', + '2011-10-08 18:00:00', + '2011-10-08 21:00:00', + ] + ); + } + + public function testDaily() + { + $this->parse( + 'FREQ=DAILY;INTERVAL=3;UNTIL=20111025T000000Z', + '2011-10-07', + [ + '2011-10-07 00:00:00', + '2011-10-10 00:00:00', + '2011-10-13 00:00:00', + '2011-10-16 00:00:00', + '2011-10-19 00:00:00', + '2011-10-22 00:00:00', + '2011-10-25 00:00:00', + ] + ); + } + + public function testDailyByDayByHour() + { + $this->parse( + 'FREQ=DAILY;BYDAY=SA,SU;BYHOUR=6,7', + '2011-10-08 06:00:00', + [ + '2011-10-08 06:00:00', + '2011-10-08 07:00:00', + '2011-10-09 06:00:00', + '2011-10-09 07:00:00', + '2011-10-15 06:00:00', + '2011-10-15 07:00:00', + '2011-10-16 06:00:00', + '2011-10-16 07:00:00', + '2011-10-22 06:00:00', + '2011-10-22 07:00:00', + '2011-10-23 06:00:00', + '2011-10-23 07:00:00', + ] + ); + } + + public function testDailyByHour() + { + $this->parse( + 'FREQ=DAILY;INTERVAL=2;BYHOUR=10,11,12,13,14,15', + '2012-10-11 12:00:00', + [ + '2012-10-11 12:00:00', + '2012-10-11 13:00:00', + '2012-10-11 14:00:00', + '2012-10-11 15:00:00', + '2012-10-13 10:00:00', + '2012-10-13 11:00:00', + '2012-10-13 12:00:00', + '2012-10-13 13:00:00', + '2012-10-13 14:00:00', + '2012-10-13 15:00:00', + '2012-10-15 10:00:00', + '2012-10-15 11:00:00', + ] + ); + } + + public function testDailyByDay() + { + $this->parse( + 'FREQ=DAILY;INTERVAL=2;BYDAY=TU,WE,FR', + '2011-10-07 12:00:00', + [ + '2011-10-07 12:00:00', + '2011-10-11 12:00:00', + '2011-10-19 12:00:00', + '2011-10-21 12:00:00', + '2011-10-25 12:00:00', + '2011-11-02 12:00:00', + '2011-11-04 12:00:00', + '2011-11-08 12:00:00', + '2011-11-16 12:00:00', + '2011-11-18 12:00:00', + '2011-11-22 12:00:00', + '2011-11-30 12:00:00', + ] + ); + } + + public function testDailyCount() + { + $this->parse( + 'FREQ=DAILY;COUNT=5', + '2014-08-01 18:03:00', + [ + '2014-08-01 18:03:00', + '2014-08-02 18:03:00', + '2014-08-03 18:03:00', + '2014-08-04 18:03:00', + '2014-08-05 18:03:00', + ] + ); + } + + public function testDailyByMonth() + { + $this->parse( + 'FREQ=DAILY;BYMONTH=9,10;BYDAY=SU', + '2007-10-04 16:00:00', + [ + '2013-09-29 16:00:00', + '2013-10-06 16:00:00', + '2013-10-13 16:00:00', + '2013-10-20 16:00:00', + '2013-10-27 16:00:00', + '2014-09-07 16:00:00', + ], + '2013-09-28' + ); + } + + public function testWeekly() + { + $this->parse( + 'FREQ=WEEKLY;INTERVAL=2;COUNT=10', + '2011-10-07 00:00:00', + [ + '2011-10-07 00:00:00', + '2011-10-21 00:00:00', + '2011-11-04 00:00:00', + '2011-11-18 00:00:00', + '2011-12-02 00:00:00', + '2011-12-16 00:00:00', + '2011-12-30 00:00:00', + '2012-01-13 00:00:00', + '2012-01-27 00:00:00', + '2012-02-10 00:00:00', + ] + ); + } + + public function testWeeklyByDay() + { + $this->parse( + 'FREQ=WEEKLY;INTERVAL=1;COUNT=4;BYDAY=MO;WKST=SA', + '2014-08-01 00:00:00', + [ + '2014-08-01 00:00:00', + '2014-08-04 00:00:00', + '2014-08-11 00:00:00', + '2014-08-18 00:00:00', + ] + ); + } + + public function testWeeklyByDay2() + { + $this->parse( + 'FREQ=WEEKLY;INTERVAL=2;BYDAY=TU,WE,FR;WKST=SU', + '2011-10-07 00:00:00', + [ + '2011-10-07 00:00:00', + '2011-10-18 00:00:00', + '2011-10-19 00:00:00', + '2011-10-21 00:00:00', + '2011-11-01 00:00:00', + '2011-11-02 00:00:00', + '2011-11-04 00:00:00', + '2011-11-15 00:00:00', + '2011-11-16 00:00:00', + '2011-11-18 00:00:00', + '2011-11-29 00:00:00', + '2011-11-30 00:00:00', + ] + ); + } + + public function testWeeklyByDayByHour() + { + $this->parse( + 'FREQ=WEEKLY;INTERVAL=2;BYDAY=TU,WE,FR;WKST=MO;BYHOUR=8,9,10', + '2011-10-07 08:00:00', + [ + '2011-10-07 08:00:00', + '2011-10-07 09:00:00', + '2011-10-07 10:00:00', + '2011-10-18 08:00:00', + '2011-10-18 09:00:00', + '2011-10-18 10:00:00', + '2011-10-19 08:00:00', + '2011-10-19 09:00:00', + '2011-10-19 10:00:00', + '2011-10-21 08:00:00', + '2011-10-21 09:00:00', + '2011-10-21 10:00:00', + '2011-11-01 08:00:00', + '2011-11-01 09:00:00', + '2011-11-01 10:00:00', + ] + ); + } + + public function testWeeklyByDaySpecificHour() + { + $this->parse( + 'FREQ=WEEKLY;INTERVAL=2;BYDAY=TU,WE,FR;WKST=SU', + '2011-10-07 18:00:00', + [ + '2011-10-07 18:00:00', + '2011-10-18 18:00:00', + '2011-10-19 18:00:00', + '2011-10-21 18:00:00', + '2011-11-01 18:00:00', + '2011-11-02 18:00:00', + '2011-11-04 18:00:00', + '2011-11-15 18:00:00', + '2011-11-16 18:00:00', + '2011-11-18 18:00:00', + '2011-11-29 18:00:00', + '2011-11-30 18:00:00', + ] + ); + } + + public function testMonthly() + { + $this->parse( + 'FREQ=MONTHLY;INTERVAL=3;COUNT=5', + '2011-12-05 00:00:00', + [ + '2011-12-05 00:00:00', + '2012-03-05 00:00:00', + '2012-06-05 00:00:00', + '2012-09-05 00:00:00', + '2012-12-05 00:00:00', + ] + ); + } + + public function testMonlthyEndOfMonth() + { + $this->parse( + 'FREQ=MONTHLY;INTERVAL=2;COUNT=12', + '2011-12-31 00:00:00', + [ + '2011-12-31 00:00:00', + '2012-08-31 00:00:00', + '2012-10-31 00:00:00', + '2012-12-31 00:00:00', + '2013-08-31 00:00:00', + '2013-10-31 00:00:00', + '2013-12-31 00:00:00', + '2014-08-31 00:00:00', + '2014-10-31 00:00:00', + '2014-12-31 00:00:00', + '2015-08-31 00:00:00', + '2015-10-31 00:00:00', + ] + ); + } + + public function testMonthlyByMonthDay() + { + $this->parse( + 'FREQ=MONTHLY;INTERVAL=5;COUNT=9;BYMONTHDAY=1,31,-7', + '2011-01-01 00:00:00', + [ + '2011-01-01 00:00:00', + '2011-01-25 00:00:00', + '2011-01-31 00:00:00', + '2011-06-01 00:00:00', + '2011-06-24 00:00:00', + '2011-11-01 00:00:00', + '2011-11-24 00:00:00', + '2012-04-01 00:00:00', + '2012-04-24 00:00:00', + ] + ); + } + + public function testMonthlyByDay() + { + $this->parse( + 'FREQ=MONTHLY;INTERVAL=2;COUNT=16;BYDAY=MO,-2TU,+1WE,3TH', + '2011-01-03 00:00:00', + [ + '2011-01-03 00:00:00', + '2011-01-05 00:00:00', + '2011-01-10 00:00:00', + '2011-01-17 00:00:00', + '2011-01-18 00:00:00', + '2011-01-20 00:00:00', + '2011-01-24 00:00:00', + '2011-01-31 00:00:00', + '2011-03-02 00:00:00', + '2011-03-07 00:00:00', + '2011-03-14 00:00:00', + '2011-03-17 00:00:00', + '2011-03-21 00:00:00', + '2011-03-22 00:00:00', + '2011-03-28 00:00:00', + '2011-05-02 00:00:00', + ] + ); + } + + public function testMonthlyByDayByMonthDay() + { + $this->parse( + 'FREQ=MONTHLY;COUNT=10;BYDAY=MO;BYMONTHDAY=1', + '2011-08-01 00:00:00', + [ + '2011-08-01 00:00:00', + '2012-10-01 00:00:00', + '2013-04-01 00:00:00', + '2013-07-01 00:00:00', + '2014-09-01 00:00:00', + '2014-12-01 00:00:00', + '2015-06-01 00:00:00', + '2016-02-01 00:00:00', + '2016-08-01 00:00:00', + '2017-05-01 00:00:00', + ] + ); + } + + public function testMonthlyByDayBySetPos() + { + $this->parse( + 'FREQ=MONTHLY;COUNT=10;BYDAY=MO,TU,WE,TH,FR;BYSETPOS=1,-1', + '2011-01-03 00:00:00', + [ + '2011-01-03 00:00:00', + '2011-01-31 00:00:00', + '2011-02-01 00:00:00', + '2011-02-28 00:00:00', + '2011-03-01 00:00:00', + '2011-03-31 00:00:00', + '2011-04-01 00:00:00', + '2011-04-29 00:00:00', + '2011-05-02 00:00:00', + '2011-05-31 00:00:00', + ] + ); + } + + public function testYearly() + { + $this->parse( + 'FREQ=YEARLY;COUNT=10;INTERVAL=3', + '2011-01-01 00:00:00', + [ + '2011-01-01 00:00:00', + '2014-01-01 00:00:00', + '2017-01-01 00:00:00', + '2020-01-01 00:00:00', + '2023-01-01 00:00:00', + '2026-01-01 00:00:00', + '2029-01-01 00:00:00', + '2032-01-01 00:00:00', + '2035-01-01 00:00:00', + '2038-01-01 00:00:00', + ] + ); + } + + public function testYearlyLeapYear() + { + $this->parse( + 'FREQ=YEARLY;COUNT=3', + '2012-02-29 00:00:00', + [ + '2012-02-29 00:00:00', + '2016-02-29 00:00:00', + '2020-02-29 00:00:00', + ] + ); + } + + public function testYearlyByMonth() + { + $this->parse( + 'FREQ=YEARLY;COUNT=8;INTERVAL=4;BYMONTH=4,10', + '2011-04-07 00:00:00', + [ + '2011-04-07 00:00:00', + '2011-10-07 00:00:00', + '2015-04-07 00:00:00', + '2015-10-07 00:00:00', + '2019-04-07 00:00:00', + '2019-10-07 00:00:00', + '2023-04-07 00:00:00', + '2023-10-07 00:00:00', + ] + ); + } + + /** + * @expectedException \Sabre\VObject\InvalidDataException + */ + public function testYearlyByMonthInvalidValue1() + { + $this->parse( + 'FREQ=YEARLY;COUNT=6;BYMONTHDAY=24;BYMONTH=0', + '2011-04-07 00:00:00', + [] + ); + } + + /** + * @expectedException \Sabre\VObject\InvalidDataException + */ + public function testYearlyByMonthInvalidValue2() + { + $this->parse( + 'FREQ=YEARLY;COUNT=6;BYMONTHDAY=24;BYMONTH=bla', + '2011-04-07 00:00:00', + [] + ); + } + + /** + * @expectedException \Sabre\VObject\InvalidDataException + */ + public function testYearlyByMonthManyInvalidValues() + { + $this->parse( + 'FREQ=YEARLY;COUNT=6;BYMONTHDAY=24;BYMONTH=0,bla', + '2011-04-07 00:00:00', + [] + ); + } + + /** + * @expectedException \Sabre\VObject\InvalidDataException + */ + public function testYearlyByMonthEmptyValue() + { + $this->parse( + 'FREQ=YEARLY;COUNT=6;BYMONTHDAY=24;BYMONTH=', + '2011-04-07 00:00:00', + [] + ); + } + + public function testYearlyByMonthByDay() + { + $this->parse( + 'FREQ=YEARLY;COUNT=8;INTERVAL=5;BYMONTH=4,10;BYDAY=1MO,-1SU', + '2011-04-04 00:00:00', + [ + '2011-04-04 00:00:00', + '2011-04-24 00:00:00', + '2011-10-03 00:00:00', + '2011-10-30 00:00:00', + '2016-04-04 00:00:00', + '2016-04-24 00:00:00', + '2016-10-03 00:00:00', + '2016-10-30 00:00:00', + ] + ); + } + + public function testYearlyByYearDay() + { + $this->parse( + 'FREQ=YEARLY;COUNT=7;INTERVAL=2;BYYEARDAY=190', + '2011-07-10 03:07:00', + [ + '2011-07-10 03:07:00', + '2013-07-10 03:07:00', + '2015-07-10 03:07:00', + '2017-07-10 03:07:00', + '2019-07-10 03:07:00', + '2021-07-10 03:07:00', + '2023-07-10 03:07:00', + ] + ); + } + + /* + * Regression test for #383 + * $parser->next() used to cause an infinite loop. + */ + public function testYearlyByYearDayImmutable() + { + $start = '2011-07-10 03:07:00'; + $rule = 'FREQ=YEARLY;COUNT=7;INTERVAL=2;BYYEARDAY=190'; + $tz = 'UTC'; + + $dt = new DateTimeImmutable($start, new DateTimeZone($tz)); + $parser = new RRuleIterator($rule, $dt); + + $parser->next(); + + $item = $parser->current(); + $this->assertEquals($item->format('Y-m-d H:i:s'), '2013-07-10 03:07:00'); + } + + public function testYearlyByYearDayMultiple() + { + $this->parse( + 'FREQ=YEARLY;COUNT=8;INTERVAL=3;BYYEARDAY=190,301', + '2011-07-10 14:53:11', + [ + '2011-07-10 14:53:11', + '2011-10-29 14:53:11', + '2014-07-10 14:53:11', + '2014-10-29 14:53:11', + '2017-07-10 14:53:11', + '2017-10-29 14:53:11', + '2020-07-09 14:53:11', + '2020-10-28 14:53:11', + ] + ); + } + + public function testYearlyByYearDayByDay() + { + $this->parse( + 'FREQ=YEARLY;COUNT=6;BYYEARDAY=97;BYDAY=SA', + '2001-04-07 14:53:11', + [ + '2001-04-07 14:53:11', + '2006-04-08 14:53:11', + '2012-04-07 14:53:11', + '2017-04-08 14:53:11', + '2023-04-08 14:53:11', + '2034-04-08 14:53:11', + ] + ); + } + + public function testYearlyByYearDayNegative() + { + $this->parse( + 'FREQ=YEARLY;COUNT=8;BYYEARDAY=-97,-5', + '2001-09-26 14:53:11', + [ + '2001-09-26 14:53:11', + '2001-12-27 14:53:11', + '2002-09-26 14:53:11', + '2002-12-27 14:53:11', + '2003-09-26 14:53:11', + '2003-12-27 14:53:11', + '2004-09-26 14:53:11', + '2004-12-27 14:53:11', + ] + ); + } + + /** + * @expectedException \Sabre\VObject\InvalidDataException + */ + public function testYearlyByYearDayInvalid390() + { + $this->parse( + 'FREQ=YEARLY;COUNT=8;INTERVAL=4;BYYEARDAY=390', + '2011-04-07 00:00:00', + [ + ] + ); + } + + /** + * @expectedException \Sabre\VObject\InvalidDataException + */ + public function testYearlyByYearDayInvalid0() + { + $this->parse( + 'FREQ=YEARLY;COUNT=8;INTERVAL=4;BYYEARDAY=0', + '2011-04-07 00:00:00', + [ + ] + ); + } + + public function testFastForward() + { + // The idea is that we're fast-forwarding too far in the future, so + // there will be no results left. + $this->parse( + 'FREQ=YEARLY;COUNT=8;INTERVAL=5;BYMONTH=4,10;BYDAY=1MO,-1SU', + '2011-04-04 00:00:00', + [], + '2020-05-05 00:00:00' + ); + } + + /** + * The bug that was in the + * system before would fail on the 5th tuesday of the month, if the 5th + * tuesday did not exist. + * + * A pretty slow test. Had to be marked as 'medium' for phpunit to not die + * after 1 second. Would be good to optimize later. + * + * @medium + */ + public function testFifthTuesdayProblem() + { + $this->parse( + 'FREQ=MONTHLY;INTERVAL=1;UNTIL=20071030T035959Z;BYDAY=5TU', + '2007-10-04 14:46:42', + [ + '2007-10-04 14:46:42', + ] + ); + } + + /** + * This bug came from a Fruux customer. This would result in a never-ending + * request. + */ + public function testFastFowardTooFar() + { + $this->parse( + 'FREQ=WEEKLY;BYDAY=MO;UNTIL=20090704T205959Z;INTERVAL=1', + '2009-04-20 18:00:00', + [ + '2009-04-20 18:00:00', + '2009-04-27 18:00:00', + '2009-05-04 18:00:00', + '2009-05-11 18:00:00', + '2009-05-18 18:00:00', + '2009-05-25 18:00:00', + '2009-06-01 18:00:00', + '2009-06-08 18:00:00', + '2009-06-15 18:00:00', + '2009-06-22 18:00:00', + '2009-06-29 18:00:00', + ] + ); + } + + public function testValidByWeekNo() + { + $this->parse( + 'FREQ=YEARLY;BYWEEKNO=20;BYDAY=TU', + '2011-02-07 00:00:00', + [ + '2011-02-07 00:00:00', + '2011-05-17 00:00:00', + '2012-05-15 00:00:00', + '2013-05-14 00:00:00', + '2014-05-13 00:00:00', + '2015-05-12 00:00:00', + '2016-05-17 00:00:00', + '2017-05-16 00:00:00', + '2018-05-15 00:00:00', + '2019-05-14 00:00:00', + '2020-05-12 00:00:00', + '2021-05-18 00:00:00', + ] + ); + } + + public function testNegativeValidByWeekNo() + { + $this->parse( + 'FREQ=YEARLY;BYWEEKNO=-20;BYDAY=TU,FR', + '2011-09-02 00:00:00', + [ + '2011-09-02 00:00:00', + '2012-08-07 00:00:00', + '2012-08-10 00:00:00', + '2013-08-06 00:00:00', + '2013-08-09 00:00:00', + '2014-08-05 00:00:00', + '2014-08-08 00:00:00', + '2015-08-11 00:00:00', + '2015-08-14 00:00:00', + '2016-08-09 00:00:00', + '2016-08-12 00:00:00', + '2017-08-08 00:00:00', + ] + ); + } + + public function testTwoValidByWeekNo() + { + $this->parse( + 'FREQ=YEARLY;BYWEEKNO=20;BYDAY=TU,FR', + '2011-09-07 09:00:00', + [ + '2011-09-07 09:00:00', + '2012-05-15 09:00:00', + '2012-05-18 09:00:00', + '2013-05-14 09:00:00', + '2013-05-17 09:00:00', + '2014-05-13 09:00:00', + '2014-05-16 09:00:00', + '2015-05-12 09:00:00', + '2015-05-15 09:00:00', + '2016-05-17 09:00:00', + '2016-05-20 09:00:00', + '2017-05-16 09:00:00', + ] + ); + } + + public function testValidByWeekNoByDayDefault() + { + $this->parse( + 'FREQ=YEARLY;BYWEEKNO=20', + '2011-05-16 00:00:00', + [ + '2011-05-16 00:00:00', + '2012-05-14 00:00:00', + '2013-05-13 00:00:00', + '2014-05-12 00:00:00', + '2015-05-11 00:00:00', + '2016-05-16 00:00:00', + '2017-05-15 00:00:00', + '2018-05-14 00:00:00', + '2019-05-13 00:00:00', + '2020-05-11 00:00:00', + '2021-05-17 00:00:00', + '2022-05-16 00:00:00', + ] + ); + } + + public function testMultipleValidByWeekNo() + { + $this->parse( + 'FREQ=YEARLY;BYWEEKNO=20,50;BYDAY=TU,FR', + '2011-01-16 00:00:00', + [ + '2011-01-16 00:00:00', + '2011-05-17 00:00:00', + '2011-05-20 00:00:00', + '2011-12-13 00:00:00', + '2011-12-16 00:00:00', + '2012-05-15 00:00:00', + '2012-05-18 00:00:00', + '2012-12-11 00:00:00', + '2012-12-14 00:00:00', + '2013-05-14 00:00:00', + '2013-05-17 00:00:00', + '2013-12-10 00:00:00', + ] + ); + } + + /** + * @expectedException \Sabre\VObject\InvalidDataException + */ + public function testInvalidByWeekNo() + { + $this->parse( + 'FREQ=YEARLY;BYWEEKNO=54', + '2011-05-16 00:00:00', + [ + ] + ); + } + + /** + * This also at one point caused an infinite loop. We're keeping the test. + */ + public function testYearlyByMonthLoop() + { + $this->parse( + 'FREQ=YEARLY;INTERVAL=1;UNTIL=20120203T225959Z;BYMONTH=2;BYSETPOS=1;BYDAY=SU,MO,TU,WE,TH,FR,SA', + '2012-01-01 15:45:00', + [ + '2012-02-01 15:45:00', + ], + '2012-01-29 23:00:00' + ); + } + + /** + * Something, somewhere produced an ics with an interval set to 0. Because + * this means we increase the current day (or week, month) by 0, this also + * results in an infinite loop. + * + * @expectedException \Sabre\VObject\InvalidDataException + */ + public function testZeroInterval() + { + $this->parse( + 'FREQ=YEARLY;INTERVAL=0', + '2012-08-24 14:57:00', + [], + '2013-01-01 23:00:00' + ); + } + + /** + * @expectedException \Sabre\VObject\InvalidDataException + */ + public function testInvalidFreq() + { + $this->parse( + 'FREQ=SMONTHLY;INTERVAL=3;UNTIL=20111025T000000Z', + '2011-10-07', + [] + ); + } + + /** + * @expectedException \Sabre\VObject\InvalidDataException + */ + public function testByDayBadOffset() + { + $this->parse( + 'FREQ=WEEKLY;INTERVAL=1;COUNT=4;BYDAY=0MO;WKST=SA', + '2014-08-01 00:00:00', + [] + ); + } + + public function testUntilBeginHasTimezone() + { + $this->parse( + 'FREQ=WEEKLY;UNTIL=20131118T183000', + '2013-09-23 18:30:00', + [ + '2013-09-23 18:30:00', + '2013-09-30 18:30:00', + '2013-10-07 18:30:00', + '2013-10-14 18:30:00', + '2013-10-21 18:30:00', + '2013-10-28 18:30:00', + '2013-11-04 18:30:00', + '2013-11-11 18:30:00', + '2013-11-18 18:30:00', + ], + null, + 'America/New_York' + ); + } + + public function testUntilBeforeDtStart() + { + $this->parse( + 'FREQ=DAILY;UNTIL=20140101T000000Z', + '2014-08-02 00:15:00', + [ + '2014-08-02 00:15:00', + ] + ); + } + + public function testIgnoredStuff() + { + $this->parse( + 'FREQ=DAILY;BYSECOND=1;BYMINUTE=1;BYYEARDAY=1;BYWEEKNO=1;COUNT=2', + '2014-08-02 00:15:00', + [ + '2014-08-02 00:15:00', + '2014-08-03 00:15:00', + ] + ); + } + + public function testMinusFifthThursday() + { + $this->parse( + 'FREQ=MONTHLY;BYDAY=-4TH,-5TH;COUNT=4', + '2015-01-01 00:15:00', + [ + '2015-01-01 00:15:00', + '2015-01-08 00:15:00', + '2015-02-05 00:15:00', + '2015-03-05 00:15:00', + ] + ); + } + + public function testNeverEnding() + { + $this->parse( + 'FREQ=MONTHLY;BYDAY=2TU;BYSETPOS=2', + '2015-01-01 00:15:00', + [ + '2015-01-01 00:15:00', + ], + null, + 'UTC', + true + ); + } + + /** + * @expectedException \Sabre\VObject\InvalidDataException + */ + public function testUnsupportedPart() + { + $this->parse( + 'FREQ=DAILY;BYWODAN=1', + '2014-08-02 00:15:00', + [] + ); + } + + public function testIteratorFunctions() + { + $parser = new RRuleIterator('FREQ=DAILY', new DateTime('2014-08-02 00:00:13')); + $parser->next(); + $this->assertEquals( + new DateTime('2014-08-03 00:00:13'), + $parser->current() + ); + $this->assertEquals( + 1, + $parser->key() + ); + + $parser->rewind(); + + $this->assertEquals( + new DateTime('2014-08-02 00:00:13'), + $parser->current() + ); + $this->assertEquals( + 0, + $parser->key() + ); + } + + public function parse($rule, $start, $expected, $fastForward = null, $tz = 'UTC', $runTillTheEnd = false) + { + $dt = new DateTime($start, new DateTimeZone($tz)); + $parser = new RRuleIterator($rule, $dt); + + if ($fastForward) { + $parser->fastForward(new DateTime($fastForward)); + } + + $result = []; + while ($parser->valid()) { + $item = $parser->current(); + $result[] = $item->format('Y-m-d H:i:s'); + + if (!$runTillTheEnd && $parser->isInfinite() && count($result) >= count($expected)) { + break; + } + $parser->next(); + } + + $this->assertEquals( + $expected, + $result + ); + } +} diff --git a/vendor/sabre/vobject/tests/VObject/RecurrenceIterator/UntilRespectsTimezoneTest.ics b/vendor/sabre/vobject/tests/VObject/RecurrenceIterator/UntilRespectsTimezoneTest.ics new file mode 100644 index 000000000..1663c783d --- /dev/null +++ b/vendor/sabre/vobject/tests/VObject/RecurrenceIterator/UntilRespectsTimezoneTest.ics @@ -0,0 +1,39 @@ +BEGIN:VCALENDAR +VERSION:2.0 +X-WR-TIMEZONE:America/New_York +PRODID:-//www.churchcommunitybuilder.com//Church Community Builder//EN +CALSCALE:GREGORIAN +METHOD:PUBLISH +X-WR-CALNAME:Test Event +BEGIN:VTIMEZONE +TZID:America/New_York +X-LIC-LOCATION:America/New_York +BEGIN:DAYLIGHT +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +TZNAME:EDT +DTSTART:19700308T020000 +RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=2SU +END:DAYLIGHT +BEGIN:STANDARD +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +TZNAME:EST +DTSTART:19701101T020000 +RRULE:FREQ=YEARLY;BYMONTH=11;BYDAY=1SU +END:STANDARD +END:VTIMEZONE +BEGIN:VEVENT +UID:10621-1440@ccbchurch.com +DTSTART;TZID=America/New_York:20130923T183000 +DTEND;TZID=America/New_York:20130923T203000 +DTSTAMP:20131216T170211 +RRULE:FREQ=WEEKLY;UNTIL=20131118T183000 +CREATED:20130423T161111 +DESCRIPTION:Test Event ending November 11, 2013 +LAST-MODIFIED:20131126T163428 +SEQUENCE:1387231331 +SUMMARY:Test +TRANSP:OPAQUE +END:VEVENT +END:VCALENDAR diff --git a/vendor/sabre/vobject/tests/VObject/SlashRTest.php b/vendor/sabre/vobject/tests/VObject/SlashRTest.php new file mode 100644 index 000000000..688563af1 --- /dev/null +++ b/vendor/sabre/vobject/tests/VObject/SlashRTest.php @@ -0,0 +1,19 @@ +add('test', "abc\r\ndef"); + $this->assertEquals("TEST:abc\\ndef\r\n", $prop->serialize()); + } +} diff --git a/vendor/sabre/vobject/tests/VObject/Splitter/ICalendarTest.php b/vendor/sabre/vobject/tests/VObject/Splitter/ICalendarTest.php new file mode 100644 index 000000000..5addf9f6d --- /dev/null +++ b/vendor/sabre/vobject/tests/VObject/Splitter/ICalendarTest.php @@ -0,0 +1,323 @@ +version = VObject\Version::VERSION; + } + + public function createStream($data) + { + $stream = fopen('php://memory', 'r+'); + fwrite($stream, $data); + rewind($stream); + + return $stream; + } + + public function testICalendarImportValidEvent() + { + $data = <<createStream($data); + + $objects = new ICalendar($tempFile); + + $return = ''; + while ($object = $objects->getNext()) { + $return .= $object->serialize(); + } + $this->assertEquals([], VObject\Reader::read($return)->validate()); + } + + /** + * @expectedException \Sabre\VObject\ParseException + */ + public function testICalendarImportWrongType() + { + $data = <<createStream($data); + + $objects = new ICalendar($tempFile); + } + + public function testICalendarImportEndOfData() + { + $data = <<createStream($data); + + $objects = new ICalendar($tempFile); + + $return = ''; + while ($object = $objects->getNext()) { + $return .= $object->serialize(); + } + $this->assertNull($object = $objects->getNext()); + } + + /** + * @expectedException \Sabre\VObject\ParseException + */ + public function testICalendarImportInvalidEvent() + { + $data = <<createStream($data); + $objects = new ICalendar($tempFile); + } + + public function testICalendarImportMultipleValidEvents() + { + $event[] = <<createStream($data); + + $objects = new ICalendar($tempFile); + + $return = ''; + $i = 0; + while ($object = $objects->getNext()) { + $expected = <<version//EN +CALSCALE:GREGORIAN +$event[$i] +END:VCALENDAR + +EOT; + + $return .= $object->serialize(); + $expected = str_replace("\n", "\r\n", $expected); + $this->assertEquals($expected, $object->serialize()); + ++$i; + } + $this->assertEquals([], VObject\Reader::read($return)->validate()); + } + + public function testICalendarImportEventWithoutUID() + { + $data = <<version//EN +CALSCALE:GREGORIAN +BEGIN:VEVENT +DTSTART:20140101T040000Z +DTSTAMP:20140122T233226Z +END:VEVENT +END:VCALENDAR + +EOT; + $tempFile = $this->createStream($data); + + $objects = new ICalendar($tempFile); + + $return = ''; + while ($object = $objects->getNext()) { + $return .= $object->serialize(); + } + + $messages = VObject\Reader::read($return)->validate(); + + if ($messages) { + $messages = array_map( + function ($item) { return $item['message']; }, + $messages + ); + $this->fail('Validation errors: '.implode("\n", $messages)); + } else { + $this->assertEquals([], $messages); + } + } + + public function testICalendarImportMultipleVTIMEZONESAndMultipleValidEvents() + { + $timezones = <<createStream($data); + + $objects = new ICalendar($tempFile); + + $return = ''; + $i = 0; + while ($object = $objects->getNext()) { + $expected = <<version//EN +CALSCALE:GREGORIAN +$timezones +$event[$i] +END:VCALENDAR + +EOT; + $expected = str_replace("\n", "\r\n", $expected); + + $this->assertEquals($expected, $object->serialize()); + $return .= $object->serialize(); + ++$i; + } + + $this->assertEquals([], VObject\Reader::read($return)->validate()); + } + + public function testICalendarImportWithOutVTIMEZONES() + { + $data = <<createStream($data); + + $objects = new ICalendar($tempFile); + + $return = ''; + while ($object = $objects->getNext()) { + $return .= $object->serialize(); + } + + $messages = VObject\Reader::read($return)->validate(); + $this->assertEquals([], $messages); + } +} diff --git a/vendor/sabre/vobject/tests/VObject/Splitter/VCardTest.php b/vendor/sabre/vobject/tests/VObject/Splitter/VCardTest.php new file mode 100644 index 000000000..a7e4ea3d2 --- /dev/null +++ b/vendor/sabre/vobject/tests/VObject/Splitter/VCardTest.php @@ -0,0 +1,242 @@ +createStream($data); + + $objects = new VCard($tempFile); + + $count = 0; + while ($objects->getNext()) { + ++$count; + } + $this->assertEquals(1, $count); + } + + /** + * @expectedException \Sabre\VObject\ParseException + */ + public function testVCardImportWrongType() + { + $event[] = <<createStream($data); + + $splitter = new VCard($tempFile); + + while ($object = $splitter->getNext()) { + } + } + + public function testVCardImportValidVCardsWithCategories() + { + $data = <<createStream($data); + + $splitter = new VCard($tempFile); + + $count = 0; + while ($object = $splitter->getNext()) { + ++$count; + } + $this->assertEquals(4, $count); + } + + /** + * @expectedException \Sabre\VObject\ParseException + */ + public function testVCardImportVCardNoComponent() + { + $data = <<createStream($data); + + $splitter = new VCard($tempFile); + + $this->expectException(\Sabre\VObject\ParseException::class); + $this->expectExceptionMessage('Invalid MimeDir file. Unexpected component: "BEGIN:VCARD" in document type VCARD'); + while ($object = $splitter->getNext()) { + } + } + + public function testVCardImportQuotedPrintableOptionForgivingLeading() + { + $data = <<createStream($data); + + $splitter = new VCard($tempFile, \Sabre\VObject\Parser\Parser::OPTION_FORGIVING); + + $count = 0; + while ($object = $splitter->getNext()) { + ++$count; + } + $this->assertEquals(2, $count); + } + + public function testVCardImportEndOfData() + { + $data = <<createStream($data); + + $objects = new VCard($tempFile); + $object = $objects->getNext(); + + $this->assertNull($objects->getNext()); + } + + /** + * @expectedException \Sabre\VObject\ParseException + */ + public function testVCardImportCheckInvalidArgumentException() + { + $data = <<createStream($data); + + $objects = new VCard($tempFile); + while ($objects->getNext()) { + } + } + + public function testVCardImportMultipleValidVCards() + { + $data = <<createStream($data); + + $objects = new VCard($tempFile); + + $count = 0; + while ($objects->getNext()) { + ++$count; + } + $this->assertEquals(2, $count); + } + + public function testImportMultipleSeparatedWithNewLines() + { + $data = <<createStream($data); + $objects = new VCard($tempFile); + + $count = 0; + while ($objects->getNext()) { + ++$count; + } + $this->assertEquals(2, $count); + } + + public function testVCardImportVCardWithoutUID() + { + $data = <<createStream($data); + + $objects = new VCard($tempFile); + + $count = 0; + while ($objects->getNext()) { + ++$count; + } + + $this->assertEquals(1, $count); + } +} diff --git a/vendor/sabre/vobject/tests/VObject/StringUtilTest.php b/vendor/sabre/vobject/tests/VObject/StringUtilTest.php new file mode 100644 index 000000000..c614f6aac --- /dev/null +++ b/vendor/sabre/vobject/tests/VObject/StringUtilTest.php @@ -0,0 +1,50 @@ +assertEquals(false, $string); + } + + public function testIsUTF8() + { + $string = StringUtil::isUTF8('I 💚 SabreDAV'); + + $this->assertEquals(true, $string); + } + + public function testUTF8ControlChar() + { + $string = StringUtil::isUTF8(chr(0x00)); + + $this->assertEquals(false, $string); + } + + public function testConvertToUTF8nonUTF8() + { + $string = StringUtil::convertToUTF8(chr(0xbf)); + + $this->assertEquals(utf8_encode(chr(0xbf)), $string); + } + + public function testConvertToUTF8IsUTF8() + { + $string = StringUtil::convertToUTF8('I 💚 SabreDAV'); + + $this->assertEquals('I 💚 SabreDAV', $string); + } + + public function testConvertToUTF8ControlChar() + { + $string = StringUtil::convertToUTF8(chr(0x00)); + + $this->assertEquals('', $string); + } +} diff --git a/vendor/sabre/vobject/tests/VObject/TimeZoneUtilTest.php b/vendor/sabre/vobject/tests/VObject/TimeZoneUtilTest.php new file mode 100644 index 000000000..f39a8330c --- /dev/null +++ b/vendor/sabre/vobject/tests/VObject/TimeZoneUtilTest.php @@ -0,0 +1,359 @@ +assertInstanceOf('DateTimeZone', $tz); + } catch (\Exception $e) { + if (false !== strpos($e->getMessage(), 'Unknown or bad timezone')) { + $this->markTestSkipped($timezoneName.' is not (yet) supported in this PHP version. Update pecl/timezonedb'); + } else { + throw $e; + } + } + } + + public function getMapping() + { + TimeZoneUtil::loadTzMaps(); + + // PHPUNit requires an array of arrays + return array_map( + function ($value) { + return [$value]; + }, + TimeZoneUtil::$map + ); + } + + public function testExchangeMap() + { + $vobj = <<assertEquals($ex->getName(), $tz->getName()); + } + + public function testWetherMicrosoftIsStillInsane() + { + $vobj = <<assertEquals($ex->getName(), $tz->getName()); + } + + public function testUnknownExchangeId() + { + $vobj = <<assertEquals($ex->getName(), $tz->getName()); + } + + public function testWindowsTimeZone() + { + $tz = TimeZoneUtil::getTimeZone('Eastern Standard Time'); + $ex = new \DateTimeZone('America/New_York'); + $this->assertEquals($ex->getName(), $tz->getName()); + } + + /** + * @dataProvider getPHPTimeZoneIdentifiers + */ + public function testTimeZoneIdentifiers($tzid) + { + $tz = TimeZoneUtil::getTimeZone($tzid); + $ex = new \DateTimeZone($tzid); + + $this->assertEquals($ex->getName(), $tz->getName()); + } + + /** + * @dataProvider getPHPTimeZoneBCIdentifiers + */ + public function testTimeZoneBCIdentifiers($tzid) + { + $tz = TimeZoneUtil::getTimeZone($tzid); + $ex = new \DateTimeZone($tzid); + + $this->assertEquals($ex->getName(), $tz->getName()); + } + + public function getPHPTimeZoneIdentifiers() + { + // PHPUNit requires an array of arrays + return array_map( + function ($value) { + return [$value]; + }, + \DateTimeZone::listIdentifiers() + ); + } + + public function getPHPTimeZoneBCIdentifiers() + { + // PHPUNit requires an array of arrays + return array_map( + function ($value) { + return [$value]; + }, + TimeZoneUtil::getIdentifiersBC() + ); + } + + public function testTimezoneOffset() + { + $tz = TimeZoneUtil::getTimeZone('GMT-0400', null, true); + + if (version_compare(PHP_VERSION, '5.5.10', '>=') && !defined('HHVM_VERSION')) { + $ex = new \DateTimeZone('-04:00'); + } else { + $ex = new \DateTimeZone('Etc/GMT-4'); + } + $this->assertEquals($ex->getName(), $tz->getName()); + } + + /** + * @expectedException \InvalidArgumentException + */ + public function testTimezoneFail() + { + $tz = TimeZoneUtil::getTimeZone('FooBar', null, true); + } + + public function testFallBack() + { + $vobj = <<assertEquals($ex->getName(), $tz->getName()); + } + + public function testLjubljanaBug() + { + $vobj = <<assertEquals($ex->getName(), $tz->getName()); + } + + public function testWeirdSystemVLICs() + { + $vobj = <<assertEquals($ex->getName(), $tz->getName()); + } + + public function testPrefixedOffsetExchangeIdentifier() + { + $tz = TimeZoneUtil::getTimeZone('(UTC-05:00) Eastern Time (US & Canada)'); + $ex = new \DateTimeZone('America/New_York'); + $this->assertEquals($ex->getName(), $tz->getName()); + } +} diff --git a/vendor/sabre/vobject/tests/VObject/UUIDUtilTest.php b/vendor/sabre/vobject/tests/VObject/UUIDUtilTest.php new file mode 100644 index 000000000..579928f38 --- /dev/null +++ b/vendor/sabre/vobject/tests/VObject/UUIDUtilTest.php @@ -0,0 +1,36 @@ +assertTrue( + UUIDUtil::validateUUID('11111111-2222-3333-4444-555555555555') + ); + $this->assertFalse( + UUIDUtil::validateUUID(' 11111111-2222-3333-4444-555555555555') + ); + $this->assertTrue( + UUIDUtil::validateUUID('ffffffff-2222-3333-4444-555555555555') + ); + $this->assertFalse( + UUIDUtil::validateUUID('fffffffg-2222-3333-4444-555555555555') + ); + } + + /** + * @depends testValidateUUID + */ + public function testGetUUID() + { + $this->assertTrue( + UUIDUtil::validateUUID( + UUIDUtil::getUUID() + ) + ); + } +} diff --git a/vendor/sabre/vobject/tests/VObject/VCard21Test.php b/vendor/sabre/vobject/tests/VObject/VCard21Test.php new file mode 100644 index 000000000..9dd07288e --- /dev/null +++ b/vendor/sabre/vobject/tests/VObject/VCard21Test.php @@ -0,0 +1,51 @@ +serialize(); + + $this->assertEquals($input, $output); + } + + public function testPropertyPadValueCount() + { + $input = <<serialize(); + + $expected = <<assertEquals($expected, $output); + } +} diff --git a/vendor/sabre/vobject/tests/VObject/VCardConverterTest.php b/vendor/sabre/vobject/tests/VObject/VCardConverterTest.php new file mode 100644 index 000000000..72c3ac64a --- /dev/null +++ b/vendor/sabre/vobject/tests/VObject/VCardConverterTest.php @@ -0,0 +1,551 @@ +convert(Document::VCARD40); + + $this->assertVObjectEqualsVObject( + $output, + $vcard + ); + } + + public function testConvert40to40() + { + $input = <<convert(Document::VCARD40); + + $this->assertVObjectEqualsVObject( + $output, + $vcard + ); + } + + public function testConvert21to40() + { + $input = <<convert(Document::VCARD40); + + $this->assertVObjectEqualsVObject( + $output, + $vcard + ); + } + + public function testConvert30to30() + { + $input = <<convert(Document::VCARD30); + + $this->assertVObjectEqualsVObject( + $output, + $vcard + ); + } + + public function testConvert40to30() + { + $input = <<convert(Document::VCARD30); + + $this->assertVObjectEqualsVObject( + $output, + $vcard + ); + } + + public function testConvertGroupCard() + { + $input = <<convert(Document::VCARD40); + + $this->assertVObjectEqualsVObject( + $output, + $vcard + ); + + $input = $output; + $output = <<convert(Document::VCARD30); + + $this->assertVObjectEqualsVObject( + $output, + $vcard + ); + } + + public function testBDAYConversion() + { + $input = <<convert(Document::VCARD40); + + $this->assertVObjectEqualsVObject( + $output, + $vcard + ); + + $input = $output; + $output = <<convert(Document::VCARD30); + + $this->assertVObjectEqualsVObject( + $output, + $vcard + ); + } + + /** + * @expectedException \InvalidArgumentException + */ + public function testUnknownSourceVCardVersion() + { + $input = <<convert(Document::VCARD40); + } + + /** + * @expectedException \InvalidArgumentException + */ + public function testUnknownTargetVCardVersion() + { + $input = <<convert(Document::VCARD21); + } + + public function testConvertIndividualCard() + { + $input = <<convert(Document::VCARD30); + + $this->assertVObjectEqualsVObject( + $output, + $vcard + ); + + $input = $output; + $output = <<convert(Document::VCARD40); + + $this->assertVObjectEqualsVObject( + $output, + $vcard + ); + } + + public function testAnniversary() + { + $input = <<!$_ +ITEM1.X-ANNIVERSARY;VALUE=DATE-AND-OR-TIME:20081210 +END:VCARD + +OUT; + + $vcard = Reader::read($input); + $vcard = $vcard->convert(Document::VCARD30); + + $this->assertVObjectEqualsVObject( + $output, + $vcard + ); + + // Swapping input and output + list( + $input, + $output + ) = [ + $output, + $input, + ]; + + $vcard = Reader::read($input); + $vcard = $vcard->convert(Document::VCARD40); + + $this->assertVObjectEqualsVObject( + $output, + $vcard + ); + } + + public function testMultipleAnniversaries() + { + $input = <<!$_ +ITEM1.X-ANNIVERSARY;VALUE=DATE-AND-OR-TIME:20081210 +ITEM2.X-ABDATE;VALUE=DATE-AND-OR-TIME:20091210 +ITEM2.X-ABLABEL:_$!!$_ +ITEM2.X-ANNIVERSARY;VALUE=DATE-AND-OR-TIME:20091210 +ITEM3.X-ABDATE;VALUE=DATE-AND-OR-TIME:20101210 +ITEM3.X-ABLABEL:_$!!$_ +ITEM3.X-ANNIVERSARY;VALUE=DATE-AND-OR-TIME:20101210 +END:VCARD + +OUT; + + $vcard = Reader::read($input); + $vcard = $vcard->convert(Document::VCARD30); + + $this->assertVObjectEqualsVObject( + $output, + $vcard + ); + + // Swapping input and output + list( + $input, + $output + ) = [ + $output, + $input, + ]; + + $vcard = Reader::read($input); + $vcard = $vcard->convert(Document::VCARD40); + + $this->assertVObjectEqualsVObject( + $output, + $vcard + ); + } + + public function testNoLabel() + { + $input = <<assertInstanceOf('Sabre\\VObject\\Component\\VCard', $vcard); + $vcard = $vcard->convert(Document::VCARD40); + $vcard = $vcard->serialize(); + + $converted = Reader::read($vcard); + $converted->validate(); + + $version = Version::VERSION; + + $expected = <<assertEquals($expected, str_replace("\r", '', $vcard)); + } + + public function testPhoneNumberValueTypeGetsRemoved() + { + $input = <<convert(Document::VCARD40); + + $this->assertVObjectEqualsVObject( + $output, + $vcard + ); + } +} diff --git a/vendor/sabre/vobject/tests/VObject/VersionTest.php b/vendor/sabre/vobject/tests/VObject/VersionTest.php new file mode 100644 index 000000000..0ad9627f8 --- /dev/null +++ b/vendor/sabre/vobject/tests/VObject/VersionTest.php @@ -0,0 +1,14 @@ +assertEquals(-1, version_compare('2.0.0', $v)); + } +} diff --git a/vendor/sabre/vobject/tests/VObject/WriterTest.php b/vendor/sabre/vobject/tests/VObject/WriterTest.php new file mode 100644 index 000000000..e30fac501 --- /dev/null +++ b/vendor/sabre/vobject/tests/VObject/WriterTest.php @@ -0,0 +1,39 @@ +getComponent()); + $this->assertEquals("BEGIN:VCALENDAR\r\nEND:VCALENDAR\r\n", $result); + } + + public function testWriteToJson() + { + $result = Writer::writeJson($this->getComponent()); + $this->assertEquals('["vcalendar",[],[]]', $result); + } + + public function testWriteToXml() + { + $result = Writer::writeXml($this->getComponent()); + $this->assertEquals( + ''."\n". + ''."\n". + ' '."\n". + ''."\n", + $result + ); + } +} diff --git a/vendor/sabre/vobject/tests/VObject/issue153.vcf b/vendor/sabre/vobject/tests/VObject/issue153.vcf new file mode 100644 index 000000000..180949c5e --- /dev/null +++ b/vendor/sabre/vobject/tests/VObject/issue153.vcf @@ -0,0 +1,352 @@ +BEGIN:VCARD +VERSION:3.0 +N:Benutzer;Test;;; +FN:Test Benutzer +PHOTO;BASE64: + /9j/4AAQSkZJRgABAQAAAQABAAD/4QBYRXhpZgAATU0AKgAAAAgAAgESAAMAAAABAAEAAIdpAAQA + AAABAAAAJgAAAAAAA6ABAAMAAAABAAEAAKACAAQAAAABAAABQKADAAQAAAABAAABQAAAAAD/2wBD + AAIBAQIBAQICAQICAgICAwUDAwMDAwYEBAMFBwYHBwcGBgYHCAsJBwgKCAYGCQ0JCgsLDAwMBwkN + Dg0MDgsMDAv/2wBDAQICAgMCAwUDAwULCAYICwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsL + CwsLCwsLCwsLCwsLCwsLCwsLCwv/wAARCAFAAUADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAA + AAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKB + kaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZn + aGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT + 1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcI + CQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAV + YnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6 + goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk + 5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD8J7JbO8tYo1tIFCDLOVG5qfdaVZRwmSOFWzyA + F4H1rLt5WViMhdp6HgmtKK8O3B+4Rhx6fSgBI9FtjaNN5aErwRjilSys7lFAt41xyTtqc2yJCVlY + 7eqgGqv2jyLcebjZnGPWncdzT0+w0u5eQXtrGiBcIyoPmNMXwpb/AGMTSRRbH6YAyPwqK21GKdfL + BAVfu+1SQX4jnjKFsp03dPypCKN9oEaKSkC7R0bGKpnSlSPdHErZOORXV3Ouy337sCLB6kpx+FY0 + t+VfyrgcbuCB1oAfoMemrcImq2sZX+I7ATXS618PdK1DRlvvDEaMq5LoV2nisx4LVrUfu5BOePau + m8EQS6PY3HmFXjljKhTzjOf1oA4mz8OxvMrLbW5RD8wbByKg1LRrRriRYY408w/KAMba1pRaWt/H + a6a7CVm2u7N8lUPEujzaRekzSK6tgqVNAGNBZJauY5Yon92GTRJp0ROY0Un0A4q3c2odkaYOMjii + KL7NIDGcj1NDAZBplmmWv1xnoFHStfS/DFpewqYoYm3DutZ8lv8AapdyOqk8EVteEbSe3KBSrDrQ + BT8S+HbawiiWGCAPjsuMnPesqHS4JSFlSMP7DitbXbvfrkkM2eGw3p+FMfTh5X+hr8w7t3oAhOhW + u8MkMZUY3fL0Heo9UsrN5FFrbxKmMBgoG41fWFra0Acjpzg9aoXjtgRoo29vagCoun27kbY059qn + bwykskYjRArdTT7GEl2UqMr2q/JtVU27iR15NADdK8DC/wBPle2iicxNg5ALH6Umm6FZ/a3ttQt4 + g2Cqnb0PbJ+tamn3j6ZCW0nILfeBORWVfO4dhLw7fMW7560AZuqeHf7MuTFcRpv6qVGVx70q2Eci + QwyW0SsPvOqjJrUtb6S9tHQKGeMZYuM8VUs7gRxbrncy9mWgB1x4QtTHvsQWkHJVhhax3tkhugHh + UkfeAXIFdPZ3v2uxkQ9G4jI6/j+tYun3r2Fy6yxeb2Py5IoAqXenJ5xaGNNvXH/1qcLSGeBdkSg9 + CcdaswC3be0pfexOMnpn2qaS1KQkQASKoydvLCgDNi09RKTNCuO2BxVjSobc6gqXMERQHkleDUsc + u9VADbG6qOWAp11bLbptkjlCkZRsde9AFi5sbO3kKfZYTnkHaOlVbuO2F5thtYcADjaKXUpHj8ku + Co2VDFL5wLeg696YFwQ2z7Qtlb8HJO0c1Zsr7T7a9kL6XazZ4CmMFRWfHdkEgjGRjPpU9raP5LSP + j5h2pAWdQ0+z1KdG+y21qvcRqBn8qXSvC+iTu63ssqyE/IAuR+NQwSrGm1g+c8E9qiSQW9wPNYYP + OR2oAW68GNa28k3lwGNHwvzDJGfSqM9nHBgm3j59QMVdmma4zIjsUBHy5OKp6o8s2BJjZjjAoAro + /nysbgYY9zWmLPCR+WQQwyaz4k2F/Pbft/GtKxvUeFN+B2x+NAEptsWpZSdo9etZe8su2X7pPFdU + LeOazKqVwevNYt7pw5EA5HIxQBQA8tAIeGz1NWIJvJlhW5OQBzjrUMR/eN9pwoXjB4qQ3ERJeYcy + 9P8AZoA0jf8AmybVxsHAFS6jp63ixmwjIwOfrWfaou12GcDpmt/w5qJhXc6hh2GM0AZkHiRpblVl + G0RjGMdxXQ+H/E0Rm+bjdw1crqEHm3EksY4Y9PTmq0cskc42qUOfpmgDovHOhLBOZ9O+aEnIUdRW + QZft1sgum/1Ywua3fDfiFDL5WoEPEwxzzirPizwTFPZC60kYUjcAp4NAHPSq91EoRS3061DHD9nb + 94Mkfw020v57GbcCRt4IIqzNcedIH2jc3JyOaAIYrRZmJxtNdB4fkGn2hluBgBR+NZ2n2X9ozAQD + 5qvaxGbKIRXkuFU4C96AMDxBKZdQkuEUkStuUegpNM1eWScAkqpHTHNPlwbjMzExZ4Pal1PS/s6+ + dY/6vuwPSgC9G8c0A+1xEknrnpUVxaeXNm2dVUfjVazvEZAEkMrccZzV1YYyBIhJP8SZ6fhQBSmV + 4JfMVT+96UJdSQdcMO4A6fjVmTUoJiqTOMJ/q+elRyQs0TtaxF0PVhzmgCzpd55r7YI2HHPTmrV0 + sDTF7gnJXGO4OKyNKgn80NbFhjoBzWjqdg6SISPmIBOaAKVnI1leyhsMJOD7CqOqRtZqotjiFulW + rhsSMshKH1ogsZbmF475TKifdf0oApabevHIAhCYOdxp0t59luS0I+995uxqpdRyWsrqmXGeCR/K + rVlZfaogqv8AvD/CaAIY42kV3K5zzn1p9jNLp6u/A80YPNWWsJNPAVpC4JAZT2HfFWJoVmVVjhVk + HTPrQBPoi2wsoo4APtBHL+tP1mS5uVEFxgJGNqH15plp5WmyBriMRsowM8UybXTNdbrpd6A/KKAD + xbJAGs44FIPlnd9c/wD16ynt/LiDW2SR2qa5vP7RnMs6BNuQMd6jhkAUb2K8+tADYp0fhj8w6itC + yQ3CFYeAOoqi8Uew+UMuf4u9T2NwIW+UgMetO4FmS6RJ1ik6HqxHAqC+gimUiA8DvjrU0kcE8ieY + itu+8c0+bShaWxksSZoM4b0SkBTgha0cq33Cuc1SvrrLFV6jpWqbuGe1HnnDdAKy7i3WSY7OT2NN + AMulWSV8ZDNzxV7SlbaFjClx69Kpww7W3ct7jpUtnNJHd5UjZnt1NIDdt7h7NQ7qGfpt7VR1XVEh + dhEpP94/4VpafexTy7ZlbBGDVHxFbQh1j04HaOTkdKAM5ZVlYso3E+tVp4w8gx0Bqd7QxNu+6D6V + DIoVySxAx2NAFyNmli2pjYBz61paW3lWrFS3BwP8/hWJbTBFJy2D6HgfWtiTWPsqxraBHyOeBg0A + RSoLSTdIepzz0606exTWyQGMXljORTNT1B7+ECZR5fHzDqapfbHjbFkTsIwSTQA43ptyyS44Paun + 8N64Z7Bre4YlZBtU5+7XLTQbjwN4Pb+IfWn2lw9uyrIw2Z5HpQBv3GirHc7LxWVZOVI71FNp7WDg + QYlIIGD6VvaPdi+tljb5yeAzcn8DT9YtbPSpVhDM87jJ3Htjnn6UAUIrJreD7Si7MDoKhv8AUxqt + pGt5GqIOr9zRfLM8ZFgZGtex2nGe4zWKN8rsDhYx2JpJ3Atx+HxcRSzWcpcL/CRwaj0zW1sQy3cS + nsFPSoYJpbIl7dm8tT8wzV7+0hqEO1Y4lQ9cqMn9KoCp9kW7kaaxU+Yx+5j5etWrb/RGxfr5bkdu + lW7KFILpfspDbVyc1fjNnrLtHqOYWP8AFjGfxpAc/e6Ql/GzW4AfqBWfpupS6Xer5vPlHmMjg10V + 5pp0u4JhYNGvAYHrUn2WLWrVo41AvSMRZAC/8CPr1oAvafdWOuNG+lqDekY+zg8MPXPX/wDXWZrF + tcWNw0erKElB4Rf4R6c1BpqyaBdbrnEcwyAc4x06H0rQS9a9jUTgOXPzMwycexoAw7u1jYb3zkU3 + Srtgdk54PFamv2C2pDQbWjcfKCeSa56aJld23YA6ZOKFqBrXGjjULuOKxKuZOTn+H/OKwr/ztOvs + uCrg7RgVLYapPbXAEW4EkHJNdBNBH4gtgyhFmXuw60AVpbT7VpiPJ94jLetQWsDRSIYz8mec1c0+ + 1nexdrw7GjJXk/epsFtDPG0bOdw+b5SaAKWsXA+14Y71FQi5S4RvlAC8A0y5hHmHarhvQ9BVGSQx + sUXPHX3oAmDCJ8rzgHg96gQ+ZGWbg9vahNRG7EnalkkF6hEXyD270MCWF3aEhdue1OsmNnMAih/r + VaBgAUY8561PaubdnMxJXseuKANhIY5Assp2v12itZtAgubEi2nb5xuKYHWubstQaO6SVzujTqpP + X8K2rXWLRF8xZJPMfjAzgUAcxcNiaRSpUocc96sW+yNgZCMVF4lvJdRvTOYkj52jbgZ98D6VWmlY + 2qCUnJOKaVwCzviibANwYc8Utkdl7tbKhjxmpUspvm8tgn16ipigSEG4G4pxu9TSA27GeFbRlGGm + P3cdhUN8GEP2hV3JjafrWfpU/wBmuAcZLA4/Sr1trkarJHcRmSEZO3uTQBmrcbZCLoDZ2x1qOHSi + yebJIAPQipp4kmbzI1EQJ6GtCxsoHP8Ap91GB2yDQBlSWO+M/ZsBHHzZ71XkfMIWNgGU9vSt3U9N + t9m21uonz0Iz/hVCfRkjg82FhtHDGgCuZ8EMjDZjBzSZ8pAwU7XbGT0pWtEjjAZgV4PFOml2QKqk + OoOcU1qBNYRSrdkrhw3BIrah8KwXoV/m3PyVzyDWNp999kccgZq/ea7PFAGgZlJ6EUgN23thpdi4 + V1Eucr7ev9K53V/ER1a/MkuWdBtG04zioLrXJ5wDK2XAxmqVqmZ2YPtHJ/GgDsvC3i0ppr2d2ish + yFAHIz706bRLNdOPnErKw4y3NcvZ3pjA8o4kB61o3OpSX9nbx3QIkU/MwoAj/sGaPzFjlWSJjk46 + ioYYwqssjIHHAHpWm4ESN9nYDIFZV+I7uVI1wrY5b1oAtafcvb3W4MM9Nx6U/VZpNRys54ToU4zW + KXaDKrJuC8cVdtpi1gzs43HNAD9N195bdYtRIUR4wD1NX2KuA9uThuSQelcsZwzq9xyzfezV/SdX + e3m8pXJhkPKkUAdYZk8RywjVVJES7U2cE/WtA+HDHohuY3Uxg7RF/GeaPBlxaawMW6rHKnAU9SOO + lX/FFv8A2bpzTQk+cpAAz93nrQBx+r4c5CODEOA3Y+wrKu5V1C1GFKznkk9K6Wzv49fs8Xf7y7DY + MhGNgrmtX0s2t66WknnKvUp0/WgCnbrJFdot0NwJxkDFdDYp86oMjjIArJivxbR7LuMyEjKitS21 + MW8auuW44H93/PFAG15aXdr5Uv7uULkA/wCFc+Yvstw0at8+eoq/p+rm6vRJMNwIx9KranYySXSy + WEZZHOCw7UARXFyj5STAk7ntWVf2gALLyfUVoataLbfLO2SO/Ws2c+VwhLK3QDpQBmz2xAyCG56d + 6uWPlnCkFcjoTzUBkMc/3cZpwn8oZkDFs8HsKALN1apDIHOeaiLkRkMOtSXE6yxAsRUcdxldswIJ + HANMCuJW8xQgOP51oacWPPGAeRUUOIZQzDhecd6mbIcbPusM0gLmq6bHPohlhDeZuH4c1zzF1+Rs + HByDXTae0s0IhjjZg3GPWqOs+HpLCTbNGyb+cHrQBZitjPEzW/LL97vinw2v2m2aORec9AKXQbsw + ygBBiX72TWxfaS8kiGFQAwz8vWkncDlbqNraT5cjb/n+lMGckx8kjOa1tU2TxkPkMpxyKyrhJ4Wa + KIDbTAkgvIp7URzgBwe/BpZYrd4vmZWNZ81x5cgBXDdzVlIvtUOGIBHpQA2aEROpR8DsB2q3bvG9 + iySzEsTkLnrVMqViCZzt7nrT7GBVuQRnODQA6Q+Sx80A4HApEJB3BAR9K19EmhkvCJ0ZsKe3tUc8 + Mc1yy7cpn6YoAzoUiclnYYY8AHpUl8zRxqpPy9qtC2tULgSMAvQ460lzIl9b7YiDt4GaAKMMQlJ5 + z9Kj8gIW5yKnS3Crlzhh6d6k0mbyZT565Q5z60ANtrRpPmhzWhbwy7DJcDhhwMdKlt7aK+gb+z33 + yKdxVuMCqaz5cqGYfWgB6yu8rBB8o6Gs/UpjGQXBGPTvVmSfyImyepqrqjbIw3WgCDz1ib9yOTg4 + NbVlNBJYvlVBHt1rBaPzQWU4IHSn2FwRJslJxQA6e3M0O4oAzdB6VXR2iKGQENGOK0ms1eAkFjF/ + BjrVGaAo371smgC7pety2kwl06Vo5AOWXmuwm+Itv4g8Ota30aWlySAJQfmkP/1zXIeG4Y5SVBB3 + evamXGly2tydwG0nKkHpQBZ86fRbpBLI252y4PGRWhO8Ml1IbJhHn+BTnNU9O1oRwvDqqhB2lHJP + 4U6awb+z4JdKbzdh5ZurDHtQBat5LaRHiaOP7QejEZKD/Oauy+FI7W3Bsroyhxkq3QH8q5a7ujM8 + nWOQnBqTR9burCT98xdR60AbbaHc6ZG3ymJsZC/3hVnw/fNIXt7hygHzZp2oeIBqCxzqfmCgEe3+ + RVdrmLVAEtf3bxfOW/ve36UAV7+7DXMu5Q4/Os2e3eRWkiAGOijtWrPodxfQmeNVAPOPWsppJIpi + JxsKcY9aAMwRyTSbpflx68VOYvOXb97OKtXAiZdzkqT0AGc037BIIRLHjsR60AVprZrZwGj4qTY0 + xyRj3PUVMJDduFfqvFRzxJCzrCzEr60ALEu+YI53c4qeGB7lGCnBU4FUopTBLvfk1at9R2sAMjNA + GtaXsnhy2FzPHvC46jgnNQ33imTXrkz3oVFAwo9Kfrtq03hAzEfJ5gyc81hWM5hhKrhgT0NPcByS + P5g2uVI98Vp6X4uuNGlyzCQIQR0bI7/1rNQxqW+05J7Y4qK5ZYUP2ZCW9TSA7SR9M8V30X9nMFZw + WfcNi5qPWPDtjo0pE7O03U/Mf055rmtFmN9E0DEox+atPWbiW7lSO8Ja4jQbcDC4A9PXFADYtM0+ + 6nc3u7aOm3IP6Vnak9tYt/xL/M445zTIbieOdmWNsE46cip42EkyC4hYx469KAFsrT7XEJgFPOT6 + 1s+H9PD3XlzxnL/MDtqn9pghgb7GjL/eJORWqfEnmrA9oFRoxjJ5BoAp6NqDW2pzRXtuyIAw3FMf + rVS4iF08pydmeCDxWvqeuC+Ro9qglcMw71mwReXD5aAlFJPPU0AZ0cEsbkSZKH15FD2xJJiJVj6c + VfnzLGEXAA71PFpDPaebE6/KOh60AYVws8TBgrFe57CmHUG25RVJA7AVozzSLbNvX5T1AHNY/m/Z + nPlqwDetAEtvqzJNu3FZBwQBjI96vPqkd3mRtokH31UYx+VZqWruxaFl+frkZxT1tvs1ujJgEH5m + PR/pQAXl2S371XAHI+Wkaf7VD8hGR2arKySylRccQ98DmiS0jifdsdgeODQBQd9x3IBx1xTYlBm3 + En86sXUAwPswKg9QeaBErIEj6nrQC0NHRtUjt0K3AHzDABGcVW1fTzJL51jyOpz0NVooispebBI4 + wK2YFEthk8qR07igDAgJil+TKtnnHFaP2h5yI3ZsgdSfaqd2P3im3BGM9aktsjmRgCOaAJZrMwR7 + 3A5PT0pdMvZtOning+byzuVDyh/A8VHczSzDPy7RwOKgiuHEewjKeoFAzp7TUNM8XXEw8RhYNQmP + 7ny18uNeOM7cCtMfDiS8uY0tDEYghyynjPbn864htP8ANhLIehzWzovxDvtFsDB9+PI4I/rQI0r3 + wNc6DO0N2VaQqW2q24YxmqFhYRgE/vkkDfMGBBP4GrSeJ7tZd6SxvIfmK4yQP84p0XiyC71gS65G + 00zAKGX5Qv4UAbFpd28WnIsBLsDzmub1+AXt1LJEoQqfu4xu+lbWsWgs4/NsCXjPIbqK5+5kklmE + rDD54BFAGb5cjybCrAnnB6ipEvXil2sM4GMVpFY7m4UNmNyOWJ4qteaM0BISVZe+RQBFHC2/zISg + B69KlIVhIHA3HuR70lqotlBulY5P4Vcls44k3u6N5oyoHb60wM6O1SRir5LemOKv2vhuW4iLg7VA + 6k4FTR2ax4aaVIwR3HWqGua5PcQm1WRBH6jqaQFzWbE2nhzynuIi+8HaHyKweJSEQEN6jpVcKyOw + cMVznOeKmtZvOPDKuOKAJbi0JYFf4eue9IW8sncfvdqnlvVFyFyu09abI0bysMZx0oArC4eCTcgb + juK2dNvE1N1M0ohljGQzc5A7cfSs6aweWAk7kTuapQysIT9mOSvG49aAOkvzLMxk06QNuG1l7j3r + PlnnJAuGJij+nNQ6XqT7wEYqyn5v9utLULaW7j321uiEjLqMkKKAIotbghb/AI8hKGPIBHNXLG6t + 7uzk3RLbKG/iP+Fc+8f2d1eFztzyD2q5p2oCFWRoxOX52nPFAGgLyC2lyZFKdB70r69buxRJBHjr + nvWVdeXLE7xE8fwnoPpVKZUnQPkBhwRmgDq7a9tLyARWiiWYngL1qG4gurJ28+NowO2a5a3v3smD + aa5WUd1HNbC6zI0KSX13JO7D5lbHFAE4V7pi0b5x1GazdUtXSM7v4iPw5rQ0/XrcXX75FgUdxzuq + /qFrp+sWRe3uDkc4BFAHLRDY42ycd6uPOXiiV+RGPlWnXOg3IQvEmIB/Ft6/jUUEZmMcgydvzECg + C1G2+Ly3YAvyM9qY88kaFcmmp807uwPJ4FS3do+Fzn5ulAFVrjbgS8Z4yah2C03SMffNWZdPknVA + iluQOnHWmX9pILvyY13HHK46UAVre7LSyOCTmtjSiy7VijLeZ0IqO08OzPIUiTI74Ga6bRP7O01F + h1KYJOv3V4BoA4zU1lExMrkbOAvpVcSifhjgrzmtjxPp7pO7SggOcqfUViy25hG5fSgC8rrLAojb + d7d6SexlEgwpRfTNV7e5LFBbKAwPNWHeX7TguxI7GmBPBExhaNVIJ6egqOVknO1fkx1J61aj1gLC + UEKlk4LVWvozC67kCFxkD1pAQ24e3uDLC3z9CR3H/wCqrczJdOGiOxvYc5/CocMYhtUBj3xU8Qjk + XbKPIZOjqclvzoAu2HiO60xPKvd7wY/1fGBWnJo8WuW6y6XIPMYZEAzuH9KxISonAuzuRzgk9qtR + 79KmMuhTt5cRyxznFADLzS2tMw6pAY5OoDEZ/Sm20TQQ74YwVQckGtMatB4kUpqreVIRw5+8aqXF + jc6bAsbD9yThWz94UAOmmjvrRCMJjOQRVS0sD9pLyABM5Of6Vdtrdn+RUGcZqO6uRBG0MuFI79KA + MfV7r7ZqDI7kohAVT6U2eJNimJQOuTnpSXFussrMvBz1pJov3YUsR9O9ABblRncQ3bAqY2EUwIiA + Vqr20ojfYqZx3q9bSKAGcYJPIoAoq7OCEQBffrRDGEcleM8nNPjuGkhHmbB74ApvmxltsuTnuDQA + +SFEjDwu5buD0qpLL5vMg2kEdOlXECMAyZGOMMePyprQRI5N0rt3BXO326UAV4b0Wt0pC5HrXS2W + qq9zE7jcO+OhFc81kbg7iMqeAFHSpLa8eymaNOUIwD6UAavjPQYYybq1bBmXcF9O39Kw4iXdDKcE + DAxW3q7NdWELISdiYIz71kz6ZNZNHI0cjqQfujIFAEtzAtu/7vODzmqlyzNyAo9vWp7uWSWJd+AM + jjGGqOWCSWRVVW2+uKAKskpWU5TP0p8c+ExsPPNTmCVD+5U/QrzRJHJGymeOQc45HFAFczh497KR + jirWlEsAudvII9znitEeBp7yAPZvEVPJUsP5ZqCO3j0yYDUNwliI6dOPpQBt/wDCR3Wj6eHFujvI + do3DIX9KoHXoL6J11CJYZAONlaWueIYtY8Nwx6ZHu2MdxVeTXKG0eaXKRuCeuBQB0mn+HRe2Yeze + MqRkFmwfyra0rwsIrRmvZICcgDLVw7xXFuFd2uEQfeAJAxUkkjSxh4J7gjPAErf40Abvjq1i0y4S + KByCdrfL+FUI7SR4Wc+WzMOCW5qhf3Mt9cCV2ZiihRk5qpdTSBgRI+R2DnFAFw2k6AqJZMjuD1qn + cxzyyAkPuiP3ieT/AJzV+01R7a2RpMZPVmGQ1WVuTqLDCptcfMBwRQBEkst/YMCSTH8vJqtJaoYQ + JPv1o+ZDZKAo+UnBpmrCBpRNp4/0crgZ9f8A9dAzCdGgkOynxSus2xjkj+L1qW5/fxYj+8D+NRWz + R4fzCd2O9Ai0lzI6mPaMOcZqW4uI7rbtJ3IMc1XScKqncQT0olPlKWfBz6UATKjSDcmdoFWtPCyR + kzckHiqUV0623lKVIPzHHWp7Ic/vSRz0zQBcCqdyT4J7YqC3uZdKv1a2UupO7B6H2NMglMUsmcnd + 0Lc4q3BmaMBiDjr60AWJRBfyb9P2RueWJ6KfQVLHqMdtcEysxJXayN0x0yKyWihWQBdwTOSdxHNb + zWEF5ErXhX7QQAMNge2f0oAnhs4rq2kksHwirkg9SfauXnJnmL3AbL9jXSRWh0N28x1cEfMqtnA/ + Cs+70+O9/fWRIb+76fhSTuBimbyyyKDgnipLk7AML1pZbCWO7Hnjn26U6ZykRL+veqAryuvm/Jwf + Sk3mo2AyHyCT6Ux5pLU5Gwg88gGkBPNAILUO3KmooyjL8ueegzTvPMsRjG4qBwKrW1sxJZzsIPGa + AJbmfp5q7MZx71NZawEi8qZSyHg4NRGLzCPtB3eme1R3Nutocodyd8UAaVtqEUDlI8/N3PaqV2Ht + X2x4lIOSwHFSWkEFyo+cD1BpbmNbNdkh20AMh1UiJ1c9RzWj/wAJa1vYiK1RmRvvetY5gDENxgnp + UlhN5TiI4O4845oAmu51lXzFDGQ8jnpTra4uJkBAOQavXvhG8tIhPawvJAfmY9gKE1COwgIiAZiO + 3rQBV866T52Qsw6YrXguZNTs0WSJ8IPnHr9KwZNamNumZSpPU4pbPxBeRy/uJjtXqfWgDodMtnXK + QjYeo3VnalpiXjMzXMKS9O9VV1ydCXkmLY/SorWwTVJTmQEt81AHTeCY49Mik+0SJKmOg71W1bxH + HLdgaXaSRNnjdzWapGlBBG2ec4GKtQ6yZD5hjLMvbIzQBfutWC2ajV4ywwN2OM/Sql/JY2kKGzU/ + McnBBqlf3Lam5e8lKMv3Yz2FU4VjgzsGQ3WgDa0ya0u7kxzgqCCcn1q43hizkEjRkOoXcAOua5Ka + 6Mc3ygEVb0nW57ac/ZC4Xuo5zQBBeZjcwuMxRn5fUUmnySx6kv2cgg98deK1LjT31pTLpymSVuWi + Xqv17U2GzFgFBUCVOo7igCTT7cnTp/ty5ZnyCvGOKz2uwimOY7geQB0FWY7tzu8xiqk8A96qOvmy + MSowOc0AVpkkgk3uAiP39KkjtonYtnO4cKOP1q1Z3K+X5V2N6OeM8gfWiewaxiKhDsAyJB2oAk0u + 1juAwniYshwoB61FLZfaJDv/AHWexpulXRNwpjkP7s8nu1Wd4uC7zfezxQBTjxZTHzlMigbdy8Up + YXEv7nPvk1aNqbhDhgARnFZMCvbzuWZgc/nQBo2l6qs63AJA6VIsiG4DI4jXP8XeqcbrK5JH3xkH + 0pWhWVR52CF6UAa8kUd7H8rD5f1p5txHAfNPasWRCjgh8D0BrV0a+DgCdfM3DaB9RigCml/JFPyB + 159xV+C/wfNHAbtUN9orxO3k5dhycfw1XmT7JarIjb1k6U2BcuNSVGDSAPu6be1QTXcO0CVSwbPA + 7VRtpftEmxW2Mx6HvUv2V1J2jkdaQBFJB5jBVYemetRyW6SqTKCfTFNllCHBX5vWkLBPvk4NADTG + 0ePKB5qdLN5NjycqvNQIpZAFVj71LsaJQBuGaAH3aCVwycKODUMsZgJjxv8AXIzUs0DpHhmBycjm + gOd37wdRjNAFETeTcARAbSeTViApfrhjufHXNJNCsUu18Z61Xit3Q5JxQBdW0MYKyn5hSf2BPIjS + 24I29T6f5xUMMrs5HOF71ooVmtMyu3ynAAzQBqeCfG7aaPsmuYkiYFG3HseKq67YQW2rSNpLCS0l + GQ5GSh74xWZc2SyxK4OZl5x7d/0rV0K+j+xPFOu4Pwpx0oAo3OnFreM7AR9Kp/2eYpxtyCx6VoXd + g2nSlQzMh6UxJdjqSpKgfN6mgCOLSZGkKyYw/wCn+c1YltRodoWA+Y8Z+taPhWz866DQqxLdmq34 + x0ZbS23yY3NgkUAcZcSyrjcc7zw3YU62meOeTazdOhrZ07TYLkYvSFVfmqveQWkDj7CW9zg0AZs9 + 8wbO3L8ZpvmGRsyZQDsO9WLu0EwZojwMc1DJCrsA5we1AFmGVZLc7Y1bA6nvU1gIyNzgxtnoKr7I + NgHO8dx0pJ3AYG3UnHegDRS+NpL5lsxh3dQverj38OtL/pKCKSPhWU/f+tYEt98xMnC9qgludrrJ + GzFl7DvQBq6pYNGdzHGO3aqS33kEBhlSME0+01z7OcXGXRupJ5H0q5fafFqNuJLLnofmGDRsBmJe + DzMEZGevpW7o8sN/bzLqTBML8oB71k/2YYh83FQRqbdtr7sDv60AX7jSo4ZsiVo067hj9anuNHey + jVizMj8gkdaqQyi+UxjO7O0A96tXDz6rEFucp5HygUANGEQKjDJGaqzWbzgyn5QOPY1p2xZtOaGN + VMo5BPoKqxa1NHHtmij+Q4xkUAUraZFiYScMOgNMf76CIZHf2q5KRq8arEjK4OTsGaki0oKwAEhP + uDmgCohEsqq/O6rrMNMj3AEdgfQmn3tqUgEcaYz1JFMtLdn0wpFGxYHhjQBa026M0XM2WQ/NnHzU + 6Yw6tCPt6rbpH0CdvzrPtrZ45ceU4cHk9qtzW6XLOjqwY9+1AEa+HWun8zR28xU5LAZx+VLaGSV9 + jrkr145amvEY4hGkjKMg5XoPY/571vaHFDr95HHqDMkoU4C9G+uKAOevoo5iSBjBxVYwLdRkL1Xt + XSeK/CdzpkjRMqyJ95SjbsD3rmJbUwoeuGOCfSgC9eWc9rcbbdA0KHPmhcq39Ka8e9DkBS5zk1X0 + /wAR3dvEtuTm3AwVzW/D4w0xIEivbOaSTAVWBAH40AYMu6CZDkFcHcTz6UrtkYlwVHIwOtb91olr + qtuRZSL5h5EX8VY97pc1jKAqZ2jB/wA/nQBRJhubjE4YOOnNMC+S+DzmrMkIA819wPTbjmqwfzcM + 4w3vQA9mbYwgIz/ENvSm2t+6jZsYKeTkVYjn/eqwGAOp9aeW+2sdkgVf5UAQLKY5MHGferNv+6IM + XT07CmyaeZIS1vtmkUdQKbZ+akOZoyqMe45oAvRzjUJPLLgSds8/zqyPDzwETagy4U8YwARWMbcw + NuDDePenPrbXEfkTn5hwrdqAO709LPSbbzlZdvqD0Ncnr/iufX793uWQrGdmFGBjpmstdQeFRHKx + 2Nn5f73+f61E7iLCxDnrjvQBaubtNypAxyRzg0q263DMsJIzzyc1mwyDeSD82e9XIGUIrSyBNw+X + 2+tAD3tSpcFvufrVZbdL2XbnDdjnGKnhs2nkYtcIEJ6461HMiJIApBVe5HWgB8mmtpzDzSrrkZYU + 65mRGYoBgirEkCStiJlC7c5IqjLNsYhtu0d6AKkshbAZcAdc81Gdwb5SD6cVZjYy5WXBVu/pWppn + h63urfdLdxR47MDk0AYjnhehxntVq11OVANuTj8q2/8AhBZ7mwkm00CYKQBtHXrWe+kTWS7J4zE+ + OQ1ACQX/ANrkC3DD0wODV280KQwM0jxheueKdZWcCrvkjYYHUHvRe6jFLapHtLKeDjg0AVrDQ5xd + xuhIUEMHx8pH1roZtH+2W+dPIbHDMOcms+81YNoqWltlFKhQD1HNP0e5udHsHFkcyMRkDoaALUPh + aa1n8yUgqRgjPOO/eq+reDkvHzoQYIB85JzzW5HBLqWmCSWQJM3UEdB3/Sk0S3uNPmIkBlgJyXAw + o/Ci4EHh3QYfDsfm3mHklGGLdFqS91HSYpvMw0jjkhTx/KqXjLUg8hihYiMn746H6Vg+QYxuV9vH + 1oA3xrem38TNe28rqp+VUyD+gpbTU7O6ylvEYoEBPzjDAjp2HeuUk1aeyfNqMH+8BTrvVhqEAMuP + O7n1oA3X1Q3U0klp5S7OGHFZt7rj4DwxlTJ6riqMTiDZsHTn6/WpbfU5EP8AxMVMqdFIOMfWgCZb + lpEO/GDgn9K6bwZpktjcC7lUsAMYPvj/AArBi0lrpc2sqbZsHbjkV20SvDp8UUZBcDp60AY+ueIZ + dIu3Frh0lbD+YNxAPXBPSqLrpuunyNPBSSM7mZyQpJ/KtWQ2uqvNDcjypQjAFjnJx0rhNYhntbvy + 7jcucgIe9AEUMOy5ImYgg4xViVVa4UFSoToc9a6DxZoEdqv2rTsHzDlx/dFcujFpG27vlPGe9AEi + anPpV359o7b143jqo/yP0rWs/FSavF9l1JltlB3tOerd+axl3XGfMXC9896iu7UbtyYIxg0AdTc2 + Vrqe3+zZxIF4Uj+I1S1Hwpexu0kts8aL7Vg2t9JZ8REjJ+UD+Guh0TxjeaW3/EwAuFAxh260AY8y + ujfLkBOCOuabHcqgCxYAbrz0rsbSysfHdzks1rO33Y0AwTWd4h+D2r6M5mmt0ER5D85P1oAxLfWZ + LSYrbnAb5eKnudVnyELFkHOcCqUmjzRzBWyD9K6W38JtLo6TtkLzmgDHtryGZiZUDZqDU1Vl3wp8 + g+9jsf8AOKmGnw2cpE8jFR1I7VdGjRXMQa0kdoSPmHrQBn6bYnWz5NydjgZVgORWeztBK8ZBJQld + x6nFdZ4ZtoNI1QPI7O+OB7VX8faO9rdC7ESrC4BJHqaAOcgUTtuORiraW0M9yiXLAIeoPc+1RWar + u6Haxq7e6ekEZkBGzGVz1ptgVprUw3ku3iJDgDPUYFEzAwZRN2CDgUw3JEkezD7+xolvytwn2pVV + RkADv060gLVlMk4aLIDHp7+1Vbu1+yzgThiHOOelElyIZl8v5CDkVtxWkGtaYs0bMblCcr/KgDCe + 3LzsN20L2HepUQJnHI9KsX+gT29pHKCd79qWw0u4aPcwU4796AL+meIr2G1aDSbiWHOMhR1qxZXz + xXBl1n/iYBBlg/FR6VZW1nciS9mdJADgYGO1Q3pIOOu5hz60AO1vxLDqluP7Pt47eJSQ2KzvtiSg + eWuPpU89gsfzH5cc+1ZaSpbXRZT8tAGjjz237gNuPwrc0O48uUPOM4GBXORXC3HmJD1bB/QVZivZ + fLwp+71oA6fVfEiwXC+UBGjfKTj14qZbi7gtJWjkY2zx5C9s4rnbCRdZiaOUkFQTke3P9KbYa1c6 + XcBARLEWxhzwBU2AotqzH5Ls5YdFPOKmiu1KgxfvCOqHrXTL4EXxLbl9MO6bGRkYzXPal4TuNLu2 + ju/3csfUD9KoDO19yChhO3OcqO1VoZEUbHVckZL9x3q09s8a5uDkZxUDWX2i4OzgHvQBLCwkwyEF + c4z6VNDZm7utkROCfwqCzAhuGRhhV/WtR5okjjkQ7ST2oAlSRtMdUjHzR1p2OuOI2Ly4kHQViS3K + iYBMsW5zSNF9klEjPnPSgC1dzm4uVKSMZd4JP41oeJPD8+r6ZHLbwmW5H3yCMqvr/Os6xu/tDfvU + CqSOfWuj0yf7OxLO2CAG9x6UAZs6vcIqSiVw3GQMisR7RVvpFkGFU46e1dN4c1hYmCXm0quDIO9c + 54quVl16drdDHGzZX6UAV5bTzWIi4Ws6/DQEoQSpI5q9BfywxkS7WU9OOlMa3F8hG7bj5sn86AKc + ErggKVA96lFwLcYHX3NQPAHnYD5e26pAnluA/JoAu6JevFqsEqs4YN0HQV39p8aL+CJVnWKWOP5c + OAf6VwCzrbxAIMMefpT48zEFD9RQB6hZ+PNE8YqsfiJFt5GOC0abcH6ioPF+i2/hiGK50xmuLOQ4 + AjO9s/T8a8wlzLIdxKkHIwcc1s6R43vdJi2xurxsdriQbto9RnpQBal1C1urtzcIVjfqu3FRMNM8 + zbpplViehyAKnuU0/X4N+ixtFdR/67e2fN+g4xzWPcWzWFyDL8gP3Qw+9+NAGhqulSWzpJHt/wBn + Bzj2NejeHLG28f8Ahox6/HsmA2DHBGO9eTrrksUTKSOD0Par+n/EnVdMRVsZYgpHIK9u9KwEvjn4 + eTeF9UY2Jie3HI+bJFc6b6eMkt909j2rsrTxpYa7bGHWYpXlc8Ord/yrOu/B8gEjQul3Ao6RjLL9 + cGhaAcu0skr7mK8HtTjEAcMMk881Zm0l7JXxg7uQBywqqzysygDBPr1qgHSWqzANL6UunXjWBOxW + KsaZcggbu4HSlindrf5ANxNIDqblPteiWrESNC2fujJ7Vd0bRY7KLfZswWYZYSdT2/pWJ4Q8ST21 + 1b2krIYj8pBFdd4k024ht0nsdpjA4AHNAHO6npkSs2SwPase6ieJcSYdenB+atGbWykgF9G2cHvi + qGqMxiWW0GFyCSRnFAFeSN4yGiLE9we1QXYEhzMo+bnAqaC9YzbpSGY8CoL/ACwDQ80AV1mxdJwQ + q9h1qd71WHU/QdqgDO0gJAyevFE4WI8dW60AafhzUHt5v3ZAzxVzXNFku/38Odg9KwbK4ELA4z+N + ddourgQKJsMv92gCr4Y8Qy6VGUmkdLcDjn5/8a6vS5tM8SWTG3kkaZeP3xIyfxrmPEuk/ZXF9akG + CY/LHj7tZy38tvcxSwnYw7DpQB0viLwrIigwhcHqAeKxDpbmcgJtKjOfStXRPHgjlEeuAzZ6bf4e + lajX+navE4gZIyQcFmxQBxd5ZPG+9iuDxmqitHGR5oO09M+tdDqmjNsDl90YPBHSsJ4N7uH7dOOt + MByxj+EkE/d5qwYGkUNu+VetUgxVz6gVNAryx7Y84J5PpSAeZWjG8A/Lg1sabqn2hF8wnniqPkK6 + qk/z/TilaEWo/cgqKANPSbRba8zM6MXGDzVPxHYPPOzOOVPy471R03XmSRXlQEHv6VstqaakgJKh + h0X1oA5jBjYrP8uTkA9TQ0qoxLHqPyrQ1+z6TMu104x65/8A1ViSsVc5GdwoAseWbkDyQWC01QVv + S+5WGcbe9OguTFZqIjhxnPHWnWTCO6LyKjPnpQBDfs4n3sMc8Y7VPBKWT922498U7X0RCjRnJmAL + KP4aq2rtA/ycBu5HXFAGkYg0GT8rY5J5qIw5jyMORxU28zwAou5jxj1pnktAzCUlT1xQBHFP/Z8w + dpNsg6ccj8a6jQPFNjqdqbfxJbvPM/yxTE/LF9c1zsNsJ1U3EYIP8VPe1iicCORsnnHTBoAtat4Z + mS92Wn79WBK7aw0ia3uXW4jdChxkjvW/Z+KLjTZFd4hKwyAc44qy+nwazpxEOPNdvMdx1UdTQBzb + AbSNyqGPf+lWvDPiW58IXDtZzOIpRiVVON4qS/0ePcG04/aYV4Z8YwaoPGJrgq2AqnAPY0AdVdww + eJLX7XoxSKfbnyRwzn61zGooyMzsreYpwQTyn+P/ANap9NvX0S4DQtzu7dhW/rel2viWzWfRiPtC + L88a/wAfuaAOQEvyDepIOOamtbFJZWKzrH7Gpk02QRBLgYYHkDtSTaf5LBgM7u1AEVxbS2aiSNfm + xw3St7RfiTLFZi2vUe4VRt44xWJDczTzoLoFgvO096bMomlkaJfI5ztFAG7Jqdlrcm2WNYHA+82C + KidbiCAoVLWzfKoHOawo1dyGO4bQcc9frWppOvSwQLDcDzQSOvbmgCjcWBQsqDYwOTmo44BdAZfG + OeuK1NYdZLjzCdu8dAKzpLYQt+6OKAK88ciXREQ3AY5/Ckmt3dlMoznPSrMU2zJxgD2zSSRmX5kY + gdiO9AFWO3KSDgqMjrXQ6fYuUAjG3HO7rWRawNeSDLYKnHPeunVG0bR4ruTnc20g96AHxn7ZbNA7 + qzgcVzup2s2mzOl0CAT8jYzvrb1TxpZ3tgr6fBFFL/EUqpp+pJqpxeqJAPulucfSgDDfcjgxAqSP + mB60xXXlZFBPXpV2+tms5W2oTnpk1nht0uZCAfTFAG9oOvCJBb6jueJj8qj+Grer6XFCqvHMvHTA + zmuajlMUmWHznoKvQ6tLDEPtKeZnsT0oAkaBVLGX7x54qOG6NvkEEA/rV2dYLi08y3fMhH3e4rMR + mkDLOMkHg9KALcN7vXI4Iq9ZyG5jw7An1rFuWMWMAopxTzqMkIxZAuOpINAD7ZAcg9F6VqaXdRFg + pX5h92sPzRbfKQdvr61c0+4MjDyxsYHkkUAdA2lvdQ+ZcDIPGOuawNY0wWNywjwVbocdK2E1ubTF + +T5gw5yM1Lc2kOqaX5kXMxG4nPT8KAOSUSKu5VGM03aZmRo22k9Tird26Fgp+6hwcVAZfNmCnBVu + mKAJp7N71FDcuOI8d6pJlLlt+d44PoK0dTZLKCI2HmCZQCd33c+1R6iqXKpJBu34+bPQGmBNpzND + bgH7zHjPapLiXMhEvzMRwarQXG+ILcfMP7w7VZjdHj+QgMOmaQCRF7AsVBZO2am2G5t2kIAJ9O1V + 2vzM21l+UU9Cjj5M8eh4NAAIXjUeRl8/pUa6k1hGFtWyG6n+lWYX25Y8dsUs9t5tkVkK7Tz7+tAE + 9l4hAj8q/RUf+Db0P1qZ/DUWrTO0paK9cfLGg+Qn61zc0SeYc53DgVr+HNfk0u623LgwSDaxHLY9 + QaYFa80a60G58vU1VmbqF5AFWdC1k6PqaTW6qyEbSD+FdRJd2s8IikZJbO46MTmRB7nr2/WsrxD4 + QjtohLo+9kHXPb0pAd6uh6Lrekm6hkkQSRgNtQfK/p+dc1f/AAsuGUnSWSVScgynbisHQfGFxpki + RKw8tRyD0z/nNWPFHji/1lFihkCxKMAocUAaNt8NNSt3bzYrYsnT5xTLvwZYQTIuqzlLh/vqigqP + xrk/7QuIwRHcXG4jnMpP9ary3kzhvtUkrSH7p3E0AdXqPgvT1vI47K4kfcCcYAx0/wAar2ngu2uW + ZIJX3pnjHFc3DqUikfPIGHU5PFb2ka3PDe7dPZGGzGW7/wCc0AX7LRLSzcxb3eXrhhxVG78JeVcA + bvvcVfEgudqaoyrOrbiV9Pwpmo311pMnmWmySH3w1AGRrXh6TRfLMq8yfcHGPxqxZ6fpmnmNddml + jlk5+RQRx/8ArqO51ptT3vMwWU9iOF/CsOZHnkIkYu3YnmgDo7qPTtPszcWTu5LcAr1ycVl6p4hk + 1BRbsCEXkCqEGqz20wEWGEZGAeRxVy+vRqV2JpUVJiACQMAUAZ0+mvaNuuz88hwAOmaktbt7C4Ub + c8jvW5rGkp/YUEsRM0nLSf7PFYogSWEF/lJ6CgDWcjXyuMhwOAO9Y09hLbSyKy9+pqzpM9xo90Jr + co2OMMM5ropr2PxBYGK7VVXBbIXG4jnrQByUI8xSADs6HPWpPLIjGxssvr3pxQmcqx+VGwFHenJI + gOF5oAW0jZB5nQnnH6Usnzjrg0rW2/8AeISD1x2pWR5VySNo60AQBX2EzHIXpSQJ5kjOOFpLgrtI + iLFvWi2Y3CFYuoNAEt4myTBBQ46Gq6OyHKjGTzSyyyXUm+/cnHc0+PY42RtuDcDigDS03UzdQlHG + WHFSw3/2CX99lo+hA64NUorOeyG9FJA68VJFaLqNu0hkIlXkgelAF3VtEjvNMF1pKOctyPTFc/bw + tGVeMfMRzW54f119M8yJ2IjlGzk9B/k1p6f4fsmi2xXsUmeP88U7gYV5Et3aQlWCsox+NR2eUnWG + 7bdvrZ1TRY7FXjuQsatzHJ7VkyeXbxnz38xl6NmkBFfiXR3MDKQjHI9xUMV0ijMnNdBZWbeJbUcC + SZU+U454rFu/DF7byNJcW0qxqeeOtAE0EcbI+4nax49qnKNY7CCG46Vjw3DRHO1gtaNrqPnBRKu1 + R0Y80AXYDHPAzlPmzzTWG2Evn8KafMMWIsFfamKxcAyjAHbNAFSeRJpOBg0xrXykVjyp6VLqFv5b + AqwTI6dal02ZZ5VjuMNGentQBJZxXFtFuUZDcitDSPFrwOYrkFkfj6Vl30l7p87RpKRDn92eoIqG + 31gRxk3qMzqRnmgC/wCJtIa2uzLYfMjgEj2rNs70woyIMjPLHtW7Y3y38gkUnGBke1R6p4dS/mNx + obeZgfvIVH3Pf3oAz7W3EmGzgrSSRqszF13+4/hqOOLdGSrk5HO0d6WCUxYaUMYhw4HegCM6TLcy + Ztkd0wckd6jtZZbPiI+aqnlem2tTStXNvcbYZyiSA4QcdMf41Y8Taf8A2dZieGMR7sAkc7s8H+dA + GVJqTT3AKtjIxtrStNVy/kyLuUj1rAlhG4NtKqOc/wB+l+2SpP8AcKMn3s07gdJdeHPtLRS2zpCr + csD171laro72bGSFWZRwzHpQdUe8hTDEMg5xU0N7Pcx7GVpIf4lzSAwlk2yAoevUDpWpa2hvYeTg + 0mo2UM8w8lPs4HUDvRpsFz9oYW6NKB07U0BbjvptGhkgJDRMu01VLRyyIYQSgA3HstVdVMiSlZyx + bPKiksbyS1hdWUmKQ5K0gJpt8UgAw69iKn0/UyJdrdOmKIPIvW/cyLEqj7p4zUEUIEr+blHXJBx1 + oAk1O28q6VoSFVhk1GbZQ25TzUlvcfakIucKAcAnqaWK1cyFkQlB70AJvJdNq5I4+tBcbCnCjv71 + LIVcAowVhxj0qO2t9zkXHKt0bsKAIpbPIHlKWUjk06wgaNiqIBzViF/kKKwBHA9aguI5oX3REk9j + TQErWypGPOGc/pTLTy47gMFyob5fetB7EmcG3G6N8hSTjNWRpgsws/y7ouWB70gKd5dGSRcfKnIP + HFXrHSYL61e4kfyVVcYA61lC7OrxurAKxbIHtUtxfC2sTDA/A49KAEazRmkEw+TqG9as+H7YSTeX + bvu7ccYrIt7qRdobPLc59K6jw9pf2KUXcJBVjuI/z9aALF88MsJh1AiRoPl54Iqt5GmXUG3ABx1x + 0/WneMbGfTryO8VB5d2N6qfTJHP5VBoNtFqUb/b28uU/d2d6AJLPV4dGtP8AQyokHGKgu/Fwu9wl + PXgj0pmpaSmnOxmYEdu5rOht2knZ4FX3oAimiju3AtlAznrVWSAW7OC2HQ/d7VdNjLaMjurbSeMC + s+4WS41BjyEB5zQBcgnk2ARnJbqKZcydmZt3fFVxB+9DRkjHfNWLh/KKGTp/6FQBGLg3C5PzFeBT + LeT5yEzlB0p1zb7wGtzt9RTNhWVQOHPWgDc0iUajbPbTgM5GE9aydTtPKk8sKcDrk9adZX5+0FLc + FZM/K1dPpmgReJLR2nOyZDhQT1z60AYWgXYtrvy5cFXBXA9+OtGpLceH9YIsZ3BwGI4+YHsaNR09 + 9C1ERTFTMjBgE6YyO9S+IoDqHlag5++RGPfGKALelpb+IbtA+Ldk+ZkXofxqHxFpn2Vpv7OXdGOW + 56Vk3GpCBQB8pB429a0bHXN8kX2gKY1ILju1AGakfmFfJXLN0/z+VdZYQG503yda5xyPp/8AqqXw + 2LKJJvsqbjIdwDL936Viarq8u9nhA8sNg88/TFAGrdeFbeWBHscSL/AM9DWRqnhObyS7KUYdfetH + wkx1Gdnm3rECAB6Vu674psYbIRxeZuHBJHWgDzZw2nybQMluDVnT9T2PsJK56Ve1OS1vJ/OhOfXj + pWVdWctu/mJhgTxQBeYrOS0xAxTojJHKHspCQ3GPSqaXCTuqpnf+lTQIJ5XRXwy0AaN7YxzWzT3I + /fSHp6VnS2LI8Yt13kj5ucAU17me4hYbvkHXJ5qvJfDMYDNlevqeaAJTAVJGBuHPFSWuoMN32iNW + UgjOelVo5vNUvg8HGKVollOIG4HNAGhb6dHewhrVy8gPK4qaFTZZRssT1GKzLWd7C5zDlS1a9rq5 + vU2uFAIznuaAK93po2GSIEjqefu1C8QZApc+uBxWnbQpeyCG1OB1cnjmi5sUuTlxgpTQFBAYCWEQ + bjrmmsHvDypH0qYqYGPlk56DPSnWFuz3BN2MCkB0niGK10bw/ExCyMxwhVskH8K5O98SPfWixqPm + AxkjBNEkkz2iQSzgqn3U54rPm4RkY4YEfhQBd0gPBMGnwc8fSpvElpFBIGU5Y4Ix0qjcanIkKBG5 + 7VGzPdIHvF3P9aAHpGtymc4Ira0fU5YYUG7KA5P0rAEgjOFjfHtVqzndD8ilFkGKAPTri4h1fRrW + DVAojmjwjdwPY/XNcJK6aTfubdjhDgc9a19PnbUYLW2upsRJ8o61S8WeH1sryKJ2AeRSUb1oApTX + TXpaQMWJGcdal8PSf6UTcj5WOKz5YW0zgTKZG44Bq4THLpSqj7LhWJdsdfSgDo9e16OGFba0ji3p + wZCBzXOoYZp2N2u0Mecd6Zp12cIbkfIBzTbwRG53W4wp5oAbeWVmgY2ZYeuTVC4SWFAzjdGO5qws + HmK28jaTVi1vhaR+XfRGeJhtVR69jz6dfwpgZEcrPcAp92pl2IzMxLuRwamfSJZCXtnRhnLgcFR6 + VWc7J9mNpbtikAW9w0MheQj5ea3NG1Y2sPmWhCvjuf5Vk7UadY48RseW960rDS11C3b7EMzL3oAt + 6hpn9pZu4GzGq7djH5g2PzpPDsMV/Y3Fveg/uVZl+vNJYRy2KhXfcB972q5aRw310/2eZLbcuCWH + X8qaA4yTeT845B4qaEqjZlVtzflV+80qY31z/Z8T3ENqMs8ZAAGcd6zoZMncEwH6H0pAdDpusLZQ + 7Rjc3ApkFoZJHmY4iAPXpms8R7oh/Gc5HtXQaALbUtGMN6ApPHrzQA/TvEdsdOWD92rRk8gcmud8 + QXkl1cZzlfapr3QP7NujGjfKTlSKzr2Jmdgx/wBX096AIkn8ucBQQjdat/bWMLZKOOnOOKzdjL0P + BoiXe2Cu7vQBpxC0KAyK2488Hiql3LskbaDtbpjrV+3tlubYC2TExGBVe+tJNOAF4PmHNAFO0meG + R1bI9jU0iK23zcbsdagWYO+xOH7mrkMWYcNgkUAQwKGA4JC5pzyFmPlEADt61asYIgSJWA3dOKv6 + zosFpdxPaBGVlG445BwKAMwuWADAbqs6eI/3hl++Pu1cj8NFyrRncAdxb0psElpY37NMhljD4YKe + poAsWmm/aIjKknlsvUnoalhtHLcbiueucA1Uu9UMs8wt4SsOfkUnkCrOmXcotj9rkV0HSLnmgDoD + 4JSXSzPNNFJhdwCkZX9a5+K9gD+XPgDdjNTpez6ZZywwPskcZbk/KK5qZ2llPmvvYnrQATr8zE5D + N1zxRbou7951anhZNYuUVFw7dvSp59IltXdZ1IZKAGvpLNGfLAfufaqDCSKUEkgdMkVd07VWs7oG + XLL0x60+7ePUjyCpByMUAV3bBGxsk1ZikV4gAMkHOKpzW5SUmN849qjjnlil3KODxj0oA6KykW7t + yJW8pk4BFdxrGhwax4TS5JWWaEBEY9QDn/CvNrPUfJmBcZDHLV0s2vsfDMwt2ZYy4z7cGgDHv9NK + yjfD+8bgYFUNRtTps4S6HlkjIBPU/wCcVeN86xKZmJlyMc5p/ifU5L/RYVmto9wJUyZ5oAy01Dfb + qZV2xnoKbfX6NEv2ZcHHWmPLFJYQx2ZLTL1U1EIJA+2bAJ6Y5oAIboyDb0PU1c8xLkBJLna4Hy44 + 5x06VAbZbdcyZ3elNBXeCRjnOaAG2808N5syYmJ7fx+5q7tW5QCZQso/iqsULT7rXLr6k4xVi0dX + +9kmgBlxpbI7SxqZAoGWz0p+i3txZ3AezJAHXjrWlZ26mFyzEnPC+vStzTLO3vZ1M8Yjwp6Hr0oA + 5/xFqyrIggQKrLlsdc96xpQZ5wySbu2DVnVYQ9/MJCSitxVOQFW4G1aAOm+H3iGPSbie1upBDBqC + CKRugwOfwrI8VWsenazNHZtvs0fEb/3h6j171Elg02N65x6Gt200i18VwwwXcjQ3Fou2NQMiTvye + 3WgDn4riKEhkfKf3h6+9aFlGLeyS8eT5DIMoDnv3FXZ9I0iwhJFxJLMpwY2ACg1TvvISzMs77S5w + EUcUAW9dH9qW6y6ZKBgcgdawoNOu7iWMmNiWOMDtT4Jxb5e1bKuMEHsfWpNM1ZrG4WWFmct0BHSg + CprWivp0u193mMeR6VHa2jmQbVH0zV3WNRkv5mkn5YnjFRJGBMjRMScdKANvR7OO1u4pS+SGGV68 + d61/GnhSHUYReQyqsZXiPI64rK0S5hRNzfePXvWr5w1KIwwucAccUAefW1q8kqiT+WK0RpdzFFuE + bFT0bHBqxrFj/Z87LjDZ/Km2ctw7Kgk3KO3SgDPQPuHmqNynv2rRs7hrhjDIcDqD6VPeafDfWbbC + UnUjav8AeHfn8qsaL4bl2pLcYWJT85PYdzQBq6dfjRtKX7QnmC4JQH07f1rIl0SztbsSrcoQnJQH + qaseJ7mBVT7PIXtDwrYwQ3esOO4RrxvLZmjI+90P5UAXrm881T9lHOeAOareXPH+8BKOB19Kb9rF + pcq0ILDPc8mp7m+S6k3fdKj7vWgB8Gtj7Oq3AZ3fCs7DmorqxQTbl+oAqJJlu4gJMKwIxT3kNq+H + G5/7o7D1zTA7Pwpd6NBrk5vQwMv3Pl+7UnjAwwXX7tFe3l5UjBbHvXP3GnCOxhuo2IL1G+qPcFYX + cknoT/n2pbgVZtGFxZvNbH5VOBk+vt+FZ8lrPakrcqyHGcEYzWidWS3lCxAlVPUdDWxf6pa6nLH/ + AGlH99QoI4wTwKbA45pHEirjk1asbxYZCsoDYH1rV17wyumSKVbeGG4Y6gVk/wBn7UdgCpPc0gLw + aEwtLKMDtWhoNykVwHdd8JGCjDIrDkSW1g2zOhVhkVLo+puSVlKlccYoA6Dxf4PbSLRb21wto7DG + W7ntj61mpKdXtxaOQvlfMCSBuJrqLfWIfEvhg2muKzQoN4CnBJHT9cVyU5hEjNbB0CHABPNAGTPa + fZriQONjqcZ6flUtqqB1SRmMr/dJzWlDaLrEUh1Qbnx+628ZNZE1s9nfctxEccjpQBO9tLcy7Zjw + vfNQ31q9oee3A75qe2Yyzby5OKiutRMsjKQDg4FG4EVvEyfM5xnsD1q5bbzKHBAB9KrCJN4YMd3p + V+wt8szRZUCnYDXsWSGPz7jGI+SMVVuvErXKEWuRk9QMYqXVyLXTUyRmRcmsSC4EAO8D2pAXxbma + IMR8w7+tVdRtkUAT9ew71as7wsF2nFGsKodDOMzHo/YU0rgULe7j098qW545Gaki1FIbwzeYyzfw + EdvyqkyGSfaw+bvRcQLayqyEnAyaQHR6gi6/pXnBER0IGFHzN15rnmlXyTGRuQHByeQau2GrS20G + 9OhO3H1//VWhf6RprXbXmnrMtuYsOjNk78DkfiDQBi2rpHIVQjb1otHPnBZAMAdRVUQiW6Bgyis2 + Buq29q2nXJjn/eDsycUAOLCG8yg9zkcVCzeVIZY+cenekN0LqYRSHAHA9aLMCOTy5BlTyPegCxa6 + ltkL2+ORzxjFWbTXpLSV3Y84+XFVJvLilKjgVFMpAyBxQBq6prEF7bQSzA+ZJ97jpVRGjDbUJAB+ + U+tUywlJUdE6VteHLK3kuoDqQZ0zyAcYFAG3feVo+io90u2d13R/LyR35rm77VZNSmzC5SEj5hnH + 14/Otu+hv/FN3gTWywW4KRqQM4/OsUeFZp5miaVAc9R0oAaXWa0EUWCIjuA9PeqEMbCYM3G77oAr + bi8Gz2YDmeLc3ygev61X1CxnnuTE8TvPb9fKXigDMuIJFlBdtzHnAPSrEF0IwDCm5hw2VNRzxTWt + 0BeKVMnTIxj8KZ/ahtgY49uT7UAX7VH1K63oERVOTxiuu0ex0nS7L7chJkm+R1kwwyPQZrh4JJDw + zbVbk4/OrNpefLsnyyg5UUAf/9k= +END:VCARD diff --git a/vendor/sabre/vobject/tests/VObject/issue64.vcf b/vendor/sabre/vobject/tests/VObject/issue64.vcf new file mode 100644 index 000000000..611052907 --- /dev/null +++ b/vendor/sabre/vobject/tests/VObject/issue64.vcf @@ -0,0 +1,351 @@ +BEGIN:VCARD +VERSION:2.1 +PHOTO;ENCODING=BASE64;JPEG: + /9j/4AAQSkZJRgABAQAAAQABAAD/4QBYRXhpZgAATU0AKgAAAAgAAgESAAMAAAABAAEAAIdpAAQA + AAABAAAAJgAAAAAAA6ABAAMAAAABAAEAAKACAAQAAAABAAABQKADAAQAAAABAAABQAAAAAD/2wBD + AAIBAQIBAQICAQICAgICAwUDAwMDAwYEBAMFBwYHBwcGBgYHCAsJBwgKCAYGCQ0JCgsLDAwMBwkN + Dg0MDgsMDAv/2wBDAQICAgMCAwUDAwULCAYICwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsL + CwsLCwsLCwsLCwsLCwsLCwsLCwv/wAARCAFAAUADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAA + AAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKB + kaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZn + aGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT + 1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcI + CQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAV + YnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6 + goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk + 5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD8J7JbO8tYo1tIFCDLOVG5qfdaVZRwmSOFWzyA + F4H1rLt5WViMhdp6HgmtKK8O3B+4Rhx6fSgBI9FtjaNN5aErwRjilSys7lFAt41xyTtqc2yJCVlY + 7eqgGqv2jyLcebjZnGPWncdzT0+w0u5eQXtrGiBcIyoPmNMXwpb/AGMTSRRbH6YAyPwqK21GKdfL + BAVfu+1SQX4jnjKFsp03dPypCKN9oEaKSkC7R0bGKpnSlSPdHErZOORXV3Ouy337sCLB6kpx+FY0 + t+VfyrgcbuCB1oAfoMemrcImq2sZX+I7ATXS618PdK1DRlvvDEaMq5LoV2nisx4LVrUfu5BOePau + m8EQS6PY3HmFXjljKhTzjOf1oA4mz8OxvMrLbW5RD8wbByKg1LRrRriRYY408w/KAMba1pRaWt/H + a6a7CVm2u7N8lUPEujzaRekzSK6tgqVNAGNBZJauY5Yon92GTRJp0ROY0Un0A4q3c2odkaYOMjii + KL7NIDGcj1NDAZBplmmWv1xnoFHStfS/DFpewqYoYm3DutZ8lv8AapdyOqk8EVteEbSe3KBSrDrQ + BT8S+HbawiiWGCAPjsuMnPesqHS4JSFlSMP7DitbXbvfrkkM2eGw3p+FMfTh5X+hr8w7t3oAhOhW + u8MkMZUY3fL0Heo9UsrN5FFrbxKmMBgoG41fWFra0Acjpzg9aoXjtgRoo29vagCoun27kbY059qn + bwykskYjRArdTT7GEl2UqMr2q/JtVU27iR15NADdK8DC/wBPle2iicxNg5ALH6Umm6FZ/a3ttQt4 + g2Cqnb0PbJ+tamn3j6ZCW0nILfeBORWVfO4dhLw7fMW7560AZuqeHf7MuTFcRpv6qVGVx70q2Eci + QwyW0SsPvOqjJrUtb6S9tHQKGeMZYuM8VUs7gRxbrncy9mWgB1x4QtTHvsQWkHJVhhax3tkhugHh + UkfeAXIFdPZ3v2uxkQ9G4jI6/j+tYun3r2Fy6yxeb2Py5IoAqXenJ5xaGNNvXH/1qcLSGeBdkSg9 + CcdaswC3be0pfexOMnpn2qaS1KQkQASKoydvLCgDNi09RKTNCuO2BxVjSobc6gqXMERQHkleDUsc + u9VADbG6qOWAp11bLbptkjlCkZRsde9AFi5sbO3kKfZYTnkHaOlVbuO2F5thtYcADjaKXUpHj8ku + Co2VDFL5wLeg696YFwQ2z7Qtlb8HJO0c1Zsr7T7a9kL6XazZ4CmMFRWfHdkEgjGRjPpU9raP5LSP + j5h2pAWdQ0+z1KdG+y21qvcRqBn8qXSvC+iTu63ssqyE/IAuR+NQwSrGm1g+c8E9qiSQW9wPNYYP + OR2oAW68GNa28k3lwGNHwvzDJGfSqM9nHBgm3j59QMVdmma4zIjsUBHy5OKp6o8s2BJjZjjAoAro + /nysbgYY9zWmLPCR+WQQwyaz4k2F/Pbft/GtKxvUeFN+B2x+NAEptsWpZSdo9etZe8su2X7pPFdU + LeOazKqVwevNYt7pw5EA5HIxQBQA8tAIeGz1NWIJvJlhW5OQBzjrUMR/eN9pwoXjB4qQ3ERJeYcy + 9P8AZoA0jf8AmybVxsHAFS6jp63ixmwjIwOfrWfaou12GcDpmt/w5qJhXc6hh2GM0AZkHiRpblVl + G0RjGMdxXQ+H/E0Rm+bjdw1crqEHm3EksY4Y9PTmq0cskc42qUOfpmgDovHOhLBOZ9O+aEnIUdRW + QZft1sgum/1Ywua3fDfiFDL5WoEPEwxzzirPizwTFPZC60kYUjcAp4NAHPSq91EoRS3061DHD9nb + 94Mkfw020v57GbcCRt4IIqzNcedIH2jc3JyOaAIYrRZmJxtNdB4fkGn2hluBgBR+NZ2n2X9ozAQD + 5qvaxGbKIRXkuFU4C96AMDxBKZdQkuEUkStuUegpNM1eWScAkqpHTHNPlwbjMzExZ4Pal1PS/s6+ + dY/6vuwPSgC9G8c0A+1xEknrnpUVxaeXNm2dVUfjVazvEZAEkMrccZzV1YYyBIhJP8SZ6fhQBSmV + 4JfMVT+96UJdSQdcMO4A6fjVmTUoJiqTOMJ/q+elRyQs0TtaxF0PVhzmgCzpd55r7YI2HHPTmrV0 + sDTF7gnJXGO4OKyNKgn80NbFhjoBzWjqdg6SISPmIBOaAKVnI1leyhsMJOD7CqOqRtZqotjiFulW + rhsSMshKH1ogsZbmF475TKifdf0oApabevHIAhCYOdxp0t59luS0I+995uxqpdRyWsrqmXGeCR/K + rVlZfaogqv8AvD/CaAIY42kV3K5zzn1p9jNLp6u/A80YPNWWsJNPAVpC4JAZT2HfFWJoVmVVjhVk + HTPrQBPoi2wsoo4APtBHL+tP1mS5uVEFxgJGNqH15plp5WmyBriMRsowM8UybXTNdbrpd6A/KKAD + xbJAGs44FIPlnd9c/wD16ynt/LiDW2SR2qa5vP7RnMs6BNuQMd6jhkAUb2K8+tADYp0fhj8w6itC + yQ3CFYeAOoqi8Uew+UMuf4u9T2NwIW+UgMetO4FmS6RJ1ik6HqxHAqC+gimUiA8DvjrU0kcE8ieY + itu+8c0+bShaWxksSZoM4b0SkBTgha0cq33Cuc1SvrrLFV6jpWqbuGe1HnnDdAKy7i3WSY7OT2NN + AMulWSV8ZDNzxV7SlbaFjClx69Kpww7W3ct7jpUtnNJHd5UjZnt1NIDdt7h7NQ7qGfpt7VR1XVEh + dhEpP94/4VpafexTy7ZlbBGDVHxFbQh1j04HaOTkdKAM5ZVlYso3E+tVp4w8gx0Bqd7QxNu+6D6V + DIoVySxAx2NAFyNmli2pjYBz61paW3lWrFS3BwP8/hWJbTBFJy2D6HgfWtiTWPsqxraBHyOeBg0A + RSoLSTdIepzz0606exTWyQGMXljORTNT1B7+ECZR5fHzDqapfbHjbFkTsIwSTQA43ptyyS44Paun + 8N64Z7Bre4YlZBtU5+7XLTQbjwN4Pb+IfWn2lw9uyrIw2Z5HpQBv3GirHc7LxWVZOVI71FNp7WDg + QYlIIGD6VvaPdi+tljb5yeAzcn8DT9YtbPSpVhDM87jJ3Htjnn6UAUIrJreD7Si7MDoKhv8AUxqt + pGt5GqIOr9zRfLM8ZFgZGtex2nGe4zWKN8rsDhYx2JpJ3Atx+HxcRSzWcpcL/CRwaj0zW1sQy3cS + nsFPSoYJpbIl7dm8tT8wzV7+0hqEO1Y4lQ9cqMn9KoCp9kW7kaaxU+Yx+5j5etWrb/RGxfr5bkdu + lW7KFILpfspDbVyc1fjNnrLtHqOYWP8AFjGfxpAc/e6Ql/GzW4AfqBWfpupS6Xer5vPlHmMjg10V + 5pp0u4JhYNGvAYHrUn2WLWrVo41AvSMRZAC/8CPr1oAvafdWOuNG+lqDekY+zg8MPXPX/wDXWZrF + tcWNw0erKElB4Rf4R6c1BpqyaBdbrnEcwyAc4x06H0rQS9a9jUTgOXPzMwycexoAw7u1jYb3zkU3 + Srtgdk54PFamv2C2pDQbWjcfKCeSa56aJld23YA6ZOKFqBrXGjjULuOKxKuZOTn+H/OKwr/ztOvs + uCrg7RgVLYapPbXAEW4EkHJNdBNBH4gtgyhFmXuw60AVpbT7VpiPJ94jLetQWsDRSIYz8mec1c0+ + 1nexdrw7GjJXk/epsFtDPG0bOdw+b5SaAKWsXA+14Y71FQi5S4RvlAC8A0y5hHmHarhvQ9BVGSQx + sUXPHX3oAmDCJ8rzgHg96gQ+ZGWbg9vahNRG7EnalkkF6hEXyD270MCWF3aEhdue1OsmNnMAih/r + VaBgAUY8561PaubdnMxJXseuKANhIY5Assp2v12itZtAgubEi2nb5xuKYHWubstQaO6SVzujTqpP + X8K2rXWLRF8xZJPMfjAzgUAcxcNiaRSpUocc96sW+yNgZCMVF4lvJdRvTOYkj52jbgZ98D6VWmlY + 2qCUnJOKaVwCzviibANwYc8Utkdl7tbKhjxmpUspvm8tgn16ipigSEG4G4pxu9TSA27GeFbRlGGm + P3cdhUN8GEP2hV3JjafrWfpU/wBmuAcZLA4/Sr1trkarJHcRmSEZO3uTQBmrcbZCLoDZ2x1qOHSi + yebJIAPQipp4kmbzI1EQJ6GtCxsoHP8Ap91GB2yDQBlSWO+M/ZsBHHzZ71XkfMIWNgGU9vSt3U9N + t9m21uonz0Iz/hVCfRkjg82FhtHDGgCuZ8EMjDZjBzSZ8pAwU7XbGT0pWtEjjAZgV4PFOml2QKqk + OoOcU1qBNYRSrdkrhw3BIrah8KwXoV/m3PyVzyDWNp999kccgZq/ea7PFAGgZlJ6EUgN23thpdi4 + V1Eucr7ev9K53V/ER1a/MkuWdBtG04zioLrXJ5wDK2XAxmqVqmZ2YPtHJ/GgDsvC3i0ppr2d2ish + yFAHIz706bRLNdOPnErKw4y3NcvZ3pjA8o4kB61o3OpSX9nbx3QIkU/MwoAj/sGaPzFjlWSJjk46 + ioYYwqssjIHHAHpWm4ESN9nYDIFZV+I7uVI1wrY5b1oAtafcvb3W4MM9Nx6U/VZpNRys54ToU4zW + KXaDKrJuC8cVdtpi1gzs43HNAD9N195bdYtRIUR4wD1NX2KuA9uThuSQelcsZwzq9xyzfezV/SdX + e3m8pXJhkPKkUAdYZk8RywjVVJES7U2cE/WtA+HDHohuY3Uxg7RF/GeaPBlxaawMW6rHKnAU9SOO + lX/FFv8A2bpzTQk+cpAAz93nrQBx+r4c5CODEOA3Y+wrKu5V1C1GFKznkk9K6Wzv49fs8Xf7y7DY + MhGNgrmtX0s2t66WknnKvUp0/WgCnbrJFdot0NwJxkDFdDYp86oMjjIArJivxbR7LuMyEjKitS21 + MW8auuW44H93/PFAG15aXdr5Uv7uULkA/wCFc+Yvstw0at8+eoq/p+rm6vRJMNwIx9KranYySXSy + WEZZHOCw7UARXFyj5STAk7ntWVf2gALLyfUVoataLbfLO2SO/Ws2c+VwhLK3QDpQBmz2xAyCG56d + 6uWPlnCkFcjoTzUBkMc/3cZpwn8oZkDFs8HsKALN1apDIHOeaiLkRkMOtSXE6yxAsRUcdxldswIJ + HANMCuJW8xQgOP51oacWPPGAeRUUOIZQzDhecd6mbIcbPusM0gLmq6bHPohlhDeZuH4c1zzF1+Rs + HByDXTae0s0IhjjZg3GPWqOs+HpLCTbNGyb+cHrQBZitjPEzW/LL97vinw2v2m2aORec9AKXQbsw + ygBBiX72TWxfaS8kiGFQAwz8vWkncDlbqNraT5cjb/n+lMGckx8kjOa1tU2TxkPkMpxyKyrhJ4Wa + KIDbTAkgvIp7URzgBwe/BpZYrd4vmZWNZ81x5cgBXDdzVlIvtUOGIBHpQA2aEROpR8DsB2q3bvG9 + iySzEsTkLnrVMqViCZzt7nrT7GBVuQRnODQA6Q+Sx80A4HApEJB3BAR9K19EmhkvCJ0ZsKe3tUc8 + Mc1yy7cpn6YoAzoUiclnYYY8AHpUl8zRxqpPy9qtC2tULgSMAvQ460lzIl9b7YiDt4GaAKMMQlJ5 + z9Kj8gIW5yKnS3Crlzhh6d6k0mbyZT565Q5z60ANtrRpPmhzWhbwy7DJcDhhwMdKlt7aK+gb+z33 + yKdxVuMCqaz5cqGYfWgB6yu8rBB8o6Gs/UpjGQXBGPTvVmSfyImyepqrqjbIw3WgCDz1ib9yOTg4 + NbVlNBJYvlVBHt1rBaPzQWU4IHSn2FwRJslJxQA6e3M0O4oAzdB6VXR2iKGQENGOK0ms1eAkFjF/ + BjrVGaAo371smgC7pety2kwl06Vo5AOWXmuwm+Itv4g8Ota30aWlySAJQfmkP/1zXIeG4Y5SVBB3 + evamXGly2tydwG0nKkHpQBZ86fRbpBLI252y4PGRWhO8Ml1IbJhHn+BTnNU9O1oRwvDqqhB2lHJP + 4U6awb+z4JdKbzdh5ZurDHtQBat5LaRHiaOP7QejEZKD/Oauy+FI7W3Bsroyhxkq3QH8q5a7ujM8 + nWOQnBqTR9burCT98xdR60AbbaHc6ZG3ymJsZC/3hVnw/fNIXt7hygHzZp2oeIBqCxzqfmCgEe3+ + RVdrmLVAEtf3bxfOW/ve36UAV7+7DXMu5Q4/Os2e3eRWkiAGOijtWrPodxfQmeNVAPOPWsppJIpi + JxsKcY9aAMwRyTSbpflx68VOYvOXb97OKtXAiZdzkqT0AGc037BIIRLHjsR60AVprZrZwGj4qTY0 + xyRj3PUVMJDduFfqvFRzxJCzrCzEr60ALEu+YI53c4qeGB7lGCnBU4FUopTBLvfk1at9R2sAMjNA + GtaXsnhy2FzPHvC46jgnNQ33imTXrkz3oVFAwo9Kfrtq03hAzEfJ5gyc81hWM5hhKrhgT0NPcByS + P5g2uVI98Vp6X4uuNGlyzCQIQR0bI7/1rNQxqW+05J7Y4qK5ZYUP2ZCW9TSA7SR9M8V30X9nMFZw + WfcNi5qPWPDtjo0pE7O03U/Mf055rmtFmN9E0DEox+atPWbiW7lSO8Ja4jQbcDC4A9PXFADYtM0+ + 6nc3u7aOm3IP6Vnak9tYt/xL/M445zTIbieOdmWNsE46cip42EkyC4hYx469KAFsrT7XEJgFPOT6 + 1s+H9PD3XlzxnL/MDtqn9pghgb7GjL/eJORWqfEnmrA9oFRoxjJ5BoAp6NqDW2pzRXtuyIAw3FMf + rVS4iF08pydmeCDxWvqeuC+Ro9qglcMw71mwReXD5aAlFJPPU0AZ0cEsbkSZKH15FD2xJJiJVj6c + VfnzLGEXAA71PFpDPaebE6/KOh60AYVws8TBgrFe57CmHUG25RVJA7AVozzSLbNvX5T1AHNY/m/Z + nPlqwDetAEtvqzJNu3FZBwQBjI96vPqkd3mRtokH31UYx+VZqWruxaFl+frkZxT1tvs1ujJgEH5m + PR/pQAXl2S371XAHI+Wkaf7VD8hGR2arKySylRccQ98DmiS0jifdsdgeODQBQd9x3IBx1xTYlBm3 + En86sXUAwPswKg9QeaBErIEj6nrQC0NHRtUjt0K3AHzDABGcVW1fTzJL51jyOpz0NVooispebBI4 + wK2YFEthk8qR07igDAgJil+TKtnnHFaP2h5yI3ZsgdSfaqd2P3im3BGM9aktsjmRgCOaAJZrMwR7 + 3A5PT0pdMvZtOning+byzuVDyh/A8VHczSzDPy7RwOKgiuHEewjKeoFAzp7TUNM8XXEw8RhYNQmP + 7ny18uNeOM7cCtMfDiS8uY0tDEYghyynjPbn864htP8ANhLIehzWzovxDvtFsDB9+PI4I/rQI0r3 + wNc6DO0N2VaQqW2q24YxmqFhYRgE/vkkDfMGBBP4GrSeJ7tZd6SxvIfmK4yQP84p0XiyC71gS65G + 00zAKGX5Qv4UAbFpd28WnIsBLsDzmub1+AXt1LJEoQqfu4xu+lbWsWgs4/NsCXjPIbqK5+5kklmE + rDD54BFAGb5cjybCrAnnB6ipEvXil2sM4GMVpFY7m4UNmNyOWJ4qteaM0BISVZe+RQBFHC2/zISg + B69KlIVhIHA3HuR70lqotlBulY5P4Vcls44k3u6N5oyoHb60wM6O1SRir5LemOKv2vhuW4iLg7VA + 6k4FTR2ax4aaVIwR3HWqGua5PcQm1WRBH6jqaQFzWbE2nhzynuIi+8HaHyKweJSEQEN6jpVcKyOw + cMVznOeKmtZvOPDKuOKAJbi0JYFf4eue9IW8sncfvdqnlvVFyFyu09abI0bysMZx0oArC4eCTcgb + juK2dNvE1N1M0ohljGQzc5A7cfSs6aweWAk7kTuapQysIT9mOSvG49aAOkvzLMxk06QNuG1l7j3r + PlnnJAuGJij+nNQ6XqT7wEYqyn5v9utLULaW7j321uiEjLqMkKKAIotbghb/AI8hKGPIBHNXLG6t + 7uzk3RLbKG/iP+Fc+8f2d1eFztzyD2q5p2oCFWRoxOX52nPFAGgLyC2lyZFKdB70r69buxRJBHjr + nvWVdeXLE7xE8fwnoPpVKZUnQPkBhwRmgDq7a9tLyARWiiWYngL1qG4gurJ28+NowO2a5a3v3smD + aa5WUd1HNbC6zI0KSX13JO7D5lbHFAE4V7pi0b5x1GazdUtXSM7v4iPw5rQ0/XrcXX75FgUdxzuq + /qFrp+sWRe3uDkc4BFAHLRDY42ycd6uPOXiiV+RGPlWnXOg3IQvEmIB/Ft6/jUUEZmMcgydvzECg + C1G2+Ly3YAvyM9qY88kaFcmmp807uwPJ4FS3do+Fzn5ulAFVrjbgS8Z4yah2C03SMffNWZdPknVA + iluQOnHWmX9pILvyY13HHK46UAVre7LSyOCTmtjSiy7VijLeZ0IqO08OzPIUiTI74Ga6bRP7O01F + h1KYJOv3V4BoA4zU1lExMrkbOAvpVcSifhjgrzmtjxPp7pO7SggOcqfUViy25hG5fSgC8rrLAojb + d7d6SexlEgwpRfTNV7e5LFBbKAwPNWHeX7TguxI7GmBPBExhaNVIJ6egqOVknO1fkx1J61aj1gLC + UEKlk4LVWvozC67kCFxkD1pAQ24e3uDLC3z9CR3H/wCqrczJdOGiOxvYc5/CocMYhtUBj3xU8Qjk + XbKPIZOjqclvzoAu2HiO60xPKvd7wY/1fGBWnJo8WuW6y6XIPMYZEAzuH9KxISonAuzuRzgk9qtR + 79KmMuhTt5cRyxznFADLzS2tMw6pAY5OoDEZ/Sm20TQQ74YwVQckGtMatB4kUpqreVIRw5+8aqXF + jc6bAsbD9yThWz94UAOmmjvrRCMJjOQRVS0sD9pLyABM5Of6Vdtrdn+RUGcZqO6uRBG0MuFI79KA + MfV7r7ZqDI7kohAVT6U2eJNimJQOuTnpSXFussrMvBz1pJov3YUsR9O9ABblRncQ3bAqY2EUwIiA + Vqr20ojfYqZx3q9bSKAGcYJPIoAoq7OCEQBffrRDGEcleM8nNPjuGkhHmbB74ApvmxltsuTnuDQA + +SFEjDwu5buD0qpLL5vMg2kEdOlXECMAyZGOMMePyprQRI5N0rt3BXO326UAV4b0Wt0pC5HrXS2W + qq9zE7jcO+OhFc81kbg7iMqeAFHSpLa8eymaNOUIwD6UAavjPQYYybq1bBmXcF9O39Kw4iXdDKcE + DAxW3q7NdWELISdiYIz71kz6ZNZNHI0cjqQfujIFAEtzAtu/7vODzmqlyzNyAo9vWp7uWSWJd+AM + jjGGqOWCSWRVVW2+uKAKskpWU5TP0p8c+ExsPPNTmCVD+5U/QrzRJHJGymeOQc45HFAFczh497KR + jirWlEsAudvII9znitEeBp7yAPZvEVPJUsP5ZqCO3j0yYDUNwliI6dOPpQBt/wDCR3Wj6eHFujvI + do3DIX9KoHXoL6J11CJYZAONlaWueIYtY8Nwx6ZHu2MdxVeTXKG0eaXKRuCeuBQB0mn+HRe2Yeze + MqRkFmwfyra0rwsIrRmvZICcgDLVw7xXFuFd2uEQfeAJAxUkkjSxh4J7gjPAErf40Abvjq1i0y4S + KByCdrfL+FUI7SR4Wc+WzMOCW5qhf3Mt9cCV2ZiihRk5qpdTSBgRI+R2DnFAFw2k6AqJZMjuD1qn + cxzyyAkPuiP3ieT/AJzV+01R7a2RpMZPVmGQ1WVuTqLDCptcfMBwRQBEkst/YMCSTH8vJqtJaoYQ + JPv1o+ZDZKAo+UnBpmrCBpRNp4/0crgZ9f8A9dAzCdGgkOynxSus2xjkj+L1qW5/fxYj+8D+NRWz + R4fzCd2O9Ai0lzI6mPaMOcZqW4uI7rbtJ3IMc1XScKqncQT0olPlKWfBz6UATKjSDcmdoFWtPCyR + kzckHiqUV0623lKVIPzHHWp7Ic/vSRz0zQBcCqdyT4J7YqC3uZdKv1a2UupO7B6H2NMglMUsmcnd + 0Lc4q3BmaMBiDjr60AWJRBfyb9P2RueWJ6KfQVLHqMdtcEysxJXayN0x0yKyWihWQBdwTOSdxHNb + zWEF5ErXhX7QQAMNge2f0oAnhs4rq2kksHwirkg9SfauXnJnmL3AbL9jXSRWh0N28x1cEfMqtnA/ + Cs+70+O9/fWRIb+76fhSTuBimbyyyKDgnipLk7AML1pZbCWO7Hnjn26U6ZykRL+veqAryuvm/Jwf + Sk3mo2AyHyCT6Ux5pLU5Gwg88gGkBPNAILUO3KmooyjL8ueegzTvPMsRjG4qBwKrW1sxJZzsIPGa + AJbmfp5q7MZx71NZawEi8qZSyHg4NRGLzCPtB3eme1R3Nutocodyd8UAaVtqEUDlI8/N3PaqV2Ht + X2x4lIOSwHFSWkEFyo+cD1BpbmNbNdkh20AMh1UiJ1c9RzWj/wAJa1vYiK1RmRvvetY5gDENxgnp + UlhN5TiI4O4845oAmu51lXzFDGQ8jnpTra4uJkBAOQavXvhG8tIhPawvJAfmY9gKE1COwgIiAZiO + 3rQBV866T52Qsw6YrXguZNTs0WSJ8IPnHr9KwZNamNumZSpPU4pbPxBeRy/uJjtXqfWgDodMtnXK + QjYeo3VnalpiXjMzXMKS9O9VV1ydCXkmLY/SorWwTVJTmQEt81AHTeCY49Mik+0SJKmOg71W1bxH + HLdgaXaSRNnjdzWapGlBBG2ec4GKtQ6yZD5hjLMvbIzQBfutWC2ajV4ywwN2OM/Sql/JY2kKGzU/ + McnBBqlf3Lam5e8lKMv3Yz2FU4VjgzsGQ3WgDa0ya0u7kxzgqCCcn1q43hizkEjRkOoXcAOua5Ka + 6Mc3ygEVb0nW57ac/ZC4Xuo5zQBBeZjcwuMxRn5fUUmnySx6kv2cgg98deK1LjT31pTLpymSVuWi + Xqv17U2GzFgFBUCVOo7igCTT7cnTp/ty5ZnyCvGOKz2uwimOY7geQB0FWY7tzu8xiqk8A96qOvmy + MSowOc0AVpkkgk3uAiP39KkjtonYtnO4cKOP1q1Z3K+X5V2N6OeM8gfWiewaxiKhDsAyJB2oAk0u + 1juAwniYshwoB61FLZfaJDv/AHWexpulXRNwpjkP7s8nu1Wd4uC7zfezxQBTjxZTHzlMigbdy8Up + YXEv7nPvk1aNqbhDhgARnFZMCvbzuWZgc/nQBo2l6qs63AJA6VIsiG4DI4jXP8XeqcbrK5JH3xkH + 0pWhWVR52CF6UAa8kUd7H8rD5f1p5txHAfNPasWRCjgh8D0BrV0a+DgCdfM3DaB9RigCml/JFPyB + 159xV+C/wfNHAbtUN9orxO3k5dhycfw1XmT7JarIjb1k6U2BcuNSVGDSAPu6be1QTXcO0CVSwbPA + 7VRtpftEmxW2Mx6HvUv2V1J2jkdaQBFJB5jBVYemetRyW6SqTKCfTFNllCHBX5vWkLBPvk4NADTG + 0ePKB5qdLN5NjycqvNQIpZAFVj71LsaJQBuGaAH3aCVwycKODUMsZgJjxv8AXIzUs0DpHhmBycjm + gOd37wdRjNAFETeTcARAbSeTViApfrhjufHXNJNCsUu18Z61Xit3Q5JxQBdW0MYKyn5hSf2BPIjS + 24I29T6f5xUMMrs5HOF71ooVmtMyu3ynAAzQBqeCfG7aaPsmuYkiYFG3HseKq67YQW2rSNpLCS0l + GQ5GSh74xWZc2SyxK4OZl5x7d/0rV0K+j+xPFOu4Pwpx0oAo3OnFreM7AR9Kp/2eYpxtyCx6VoXd + g2nSlQzMh6UxJdjqSpKgfN6mgCOLSZGkKyYw/wCn+c1YltRodoWA+Y8Z+taPhWz866DQqxLdmq34 + x0ZbS23yY3NgkUAcZcSyrjcc7zw3YU62meOeTazdOhrZ07TYLkYvSFVfmqveQWkDj7CW9zg0AZs9 + 8wbO3L8ZpvmGRsyZQDsO9WLu0EwZojwMc1DJCrsA5we1AFmGVZLc7Y1bA6nvU1gIyNzgxtnoKr7I + NgHO8dx0pJ3AYG3UnHegDRS+NpL5lsxh3dQverj38OtL/pKCKSPhWU/f+tYEt98xMnC9qgludrrJ + GzFl7DvQBq6pYNGdzHGO3aqS33kEBhlSME0+01z7OcXGXRupJ5H0q5fafFqNuJLLnofmGDRsBmJe + DzMEZGevpW7o8sN/bzLqTBML8oB71k/2YYh83FQRqbdtr7sDv60AX7jSo4ZsiVo067hj9anuNHey + jVizMj8gkdaqQyi+UxjO7O0A96tXDz6rEFucp5HygUANGEQKjDJGaqzWbzgyn5QOPY1p2xZtOaGN + VMo5BPoKqxa1NHHtmij+Q4xkUAUraZFiYScMOgNMf76CIZHf2q5KRq8arEjK4OTsGaki0oKwAEhP + uDmgCohEsqq/O6rrMNMj3AEdgfQmn3tqUgEcaYz1JFMtLdn0wpFGxYHhjQBa026M0XM2WQ/NnHzU + 6Yw6tCPt6rbpH0CdvzrPtrZ45ceU4cHk9qtzW6XLOjqwY9+1AEa+HWun8zR28xU5LAZx+VLaGSV9 + jrkr145amvEY4hGkjKMg5XoPY/571vaHFDr95HHqDMkoU4C9G+uKAOevoo5iSBjBxVYwLdRkL1Xt + XSeK/CdzpkjRMqyJ95SjbsD3rmJbUwoeuGOCfSgC9eWc9rcbbdA0KHPmhcq39Ka8e9DkBS5zk1X0 + /wAR3dvEtuTm3AwVzW/D4w0xIEivbOaSTAVWBAH40AYMu6CZDkFcHcTz6UrtkYlwVHIwOtb91olr + qtuRZSL5h5EX8VY97pc1jKAqZ2jB/wA/nQBRJhubjE4YOOnNMC+S+DzmrMkIA819wPTbjmqwfzcM + 4w3vQA9mbYwgIz/ENvSm2t+6jZsYKeTkVYjn/eqwGAOp9aeW+2sdkgVf5UAQLKY5MHGferNv+6IM + XT07CmyaeZIS1vtmkUdQKbZ+akOZoyqMe45oAvRzjUJPLLgSds8/zqyPDzwETagy4U8YwARWMbcw + NuDDePenPrbXEfkTn5hwrdqAO709LPSbbzlZdvqD0Ncnr/iufX793uWQrGdmFGBjpmstdQeFRHKx + 2Nn5f73+f61E7iLCxDnrjvQBaubtNypAxyRzg0q263DMsJIzzyc1mwyDeSD82e9XIGUIrSyBNw+X + 2+tAD3tSpcFvufrVZbdL2XbnDdjnGKnhs2nkYtcIEJ6461HMiJIApBVe5HWgB8mmtpzDzSrrkZYU + 65mRGYoBgirEkCStiJlC7c5IqjLNsYhtu0d6AKkshbAZcAdc81Gdwb5SD6cVZjYy5WXBVu/pWppn + h63urfdLdxR47MDk0AYjnhehxntVq11OVANuTj8q2/8AhBZ7mwkm00CYKQBtHXrWe+kTWS7J4zE+ + OQ1ACQX/ANrkC3DD0wODV280KQwM0jxheueKdZWcCrvkjYYHUHvRe6jFLapHtLKeDjg0AVrDQ5xd + xuhIUEMHx8pH1roZtH+2W+dPIbHDMOcms+81YNoqWltlFKhQD1HNP0e5udHsHFkcyMRkDoaALUPh + aa1n8yUgqRgjPOO/eq+reDkvHzoQYIB85JzzW5HBLqWmCSWQJM3UEdB3/Sk0S3uNPmIkBlgJyXAw + o/Ci4EHh3QYfDsfm3mHklGGLdFqS91HSYpvMw0jjkhTx/KqXjLUg8hihYiMn746H6Vg+QYxuV9vH + 1oA3xrem38TNe28rqp+VUyD+gpbTU7O6ylvEYoEBPzjDAjp2HeuUk1aeyfNqMH+8BTrvVhqEAMuP + O7n1oA3X1Q3U0klp5S7OGHFZt7rj4DwxlTJ6riqMTiDZsHTn6/WpbfU5EP8AxMVMqdFIOMfWgCZb + lpEO/GDgn9K6bwZpktjcC7lUsAMYPvj/AArBi0lrpc2sqbZsHbjkV20SvDp8UUZBcDp60AY+ueIZ + dIu3Frh0lbD+YNxAPXBPSqLrpuunyNPBSSM7mZyQpJ/KtWQ2uqvNDcjypQjAFjnJx0rhNYhntbvy + 7jcucgIe9AEUMOy5ImYgg4xViVVa4UFSoToc9a6DxZoEdqv2rTsHzDlx/dFcujFpG27vlPGe9AEi + anPpV359o7b143jqo/yP0rWs/FSavF9l1JltlB3tOerd+axl3XGfMXC9896iu7UbtyYIxg0AdTc2 + Vrqe3+zZxIF4Uj+I1S1Hwpexu0kts8aL7Vg2t9JZ8REjJ+UD+Guh0TxjeaW3/EwAuFAxh260AY8y + ujfLkBOCOuabHcqgCxYAbrz0rsbSysfHdzks1rO33Y0AwTWd4h+D2r6M5mmt0ER5D85P1oAxLfWZ + LSYrbnAb5eKnudVnyELFkHOcCqUmjzRzBWyD9K6W38JtLo6TtkLzmgDHtryGZiZUDZqDU1Vl3wp8 + g+9jsf8AOKmGnw2cpE8jFR1I7VdGjRXMQa0kdoSPmHrQBn6bYnWz5NydjgZVgORWeztBK8ZBJQld + x6nFdZ4ZtoNI1QPI7O+OB7VX8faO9rdC7ESrC4BJHqaAOcgUTtuORiraW0M9yiXLAIeoPc+1RWar + u6Haxq7e6ekEZkBGzGVz1ptgVprUw3ku3iJDgDPUYFEzAwZRN2CDgUw3JEkezD7+xolvytwn2pVV + RkADv060gLVlMk4aLIDHp7+1Vbu1+yzgThiHOOelElyIZl8v5CDkVtxWkGtaYs0bMblCcr/KgDCe + 3LzsN20L2HepUQJnHI9KsX+gT29pHKCd79qWw0u4aPcwU4796AL+meIr2G1aDSbiWHOMhR1qxZXz + xXBl1n/iYBBlg/FR6VZW1nciS9mdJADgYGO1Q3pIOOu5hz60AO1vxLDqluP7Pt47eJSQ2KzvtiSg + eWuPpU89gsfzH5cc+1ZaSpbXRZT8tAGjjz237gNuPwrc0O48uUPOM4GBXORXC3HmJD1bB/QVZivZ + fLwp+71oA6fVfEiwXC+UBGjfKTj14qZbi7gtJWjkY2zx5C9s4rnbCRdZiaOUkFQTke3P9KbYa1c6 + XcBARLEWxhzwBU2AotqzH5Ls5YdFPOKmiu1KgxfvCOqHrXTL4EXxLbl9MO6bGRkYzXPal4TuNLu2 + ju/3csfUD9KoDO19yChhO3OcqO1VoZEUbHVckZL9x3q09s8a5uDkZxUDWX2i4OzgHvQBLCwkwyEF + c4z6VNDZm7utkROCfwqCzAhuGRhhV/WtR5okjjkQ7ST2oAlSRtMdUjHzR1p2OuOI2Ly4kHQViS3K + iYBMsW5zSNF9klEjPnPSgC1dzm4uVKSMZd4JP41oeJPD8+r6ZHLbwmW5H3yCMqvr/Os6xu/tDfvU + CqSOfWuj0yf7OxLO2CAG9x6UAZs6vcIqSiVw3GQMisR7RVvpFkGFU46e1dN4c1hYmCXm0quDIO9c + 54quVl16drdDHGzZX6UAV5bTzWIi4Ws6/DQEoQSpI5q9BfywxkS7WU9OOlMa3F8hG7bj5sn86AKc + ErggKVA96lFwLcYHX3NQPAHnYD5e26pAnluA/JoAu6JevFqsEqs4YN0HQV39p8aL+CJVnWKWOP5c + OAf6VwCzrbxAIMMefpT48zEFD9RQB6hZ+PNE8YqsfiJFt5GOC0abcH6ioPF+i2/hiGK50xmuLOQ4 + AjO9s/T8a8wlzLIdxKkHIwcc1s6R43vdJi2xurxsdriQbto9RnpQBal1C1urtzcIVjfqu3FRMNM8 + zbpplViehyAKnuU0/X4N+ixtFdR/67e2fN+g4xzWPcWzWFyDL8gP3Qw+9+NAGhqulSWzpJHt/wBn + Bzj2NejeHLG28f8Ahox6/HsmA2DHBGO9eTrrksUTKSOD0Par+n/EnVdMRVsZYgpHIK9u9KwEvjn4 + eTeF9UY2Jie3HI+bJFc6b6eMkt909j2rsrTxpYa7bGHWYpXlc8Ord/yrOu/B8gEjQul3Ao6RjLL9 + cGhaAcu0skr7mK8HtTjEAcMMk881Zm0l7JXxg7uQBywqqzysygDBPr1qgHSWqzANL6UunXjWBOxW + KsaZcggbu4HSlindrf5ANxNIDqblPteiWrESNC2fujJ7Vd0bRY7KLfZswWYZYSdT2/pWJ4Q8ST21 + 1b2krIYj8pBFdd4k024ht0nsdpjA4AHNAHO6npkSs2SwPase6ieJcSYdenB+atGbWykgF9G2cHvi + qGqMxiWW0GFyCSRnFAFeSN4yGiLE9we1QXYEhzMo+bnAqaC9YzbpSGY8CoL/ACwDQ80AV1mxdJwQ + q9h1qd71WHU/QdqgDO0gJAyevFE4WI8dW60AafhzUHt5v3ZAzxVzXNFku/38Odg9KwbK4ELA4z+N + ddourgQKJsMv92gCr4Y8Qy6VGUmkdLcDjn5/8a6vS5tM8SWTG3kkaZeP3xIyfxrmPEuk/ZXF9akG + CY/LHj7tZy38tvcxSwnYw7DpQB0viLwrIigwhcHqAeKxDpbmcgJtKjOfStXRPHgjlEeuAzZ6bf4e + lajX+navE4gZIyQcFmxQBxd5ZPG+9iuDxmqitHGR5oO09M+tdDqmjNsDl90YPBHSsJ4N7uH7dOOt + MByxj+EkE/d5qwYGkUNu+VetUgxVz6gVNAryx7Y84J5PpSAeZWjG8A/Lg1sabqn2hF8wnniqPkK6 + qk/z/TilaEWo/cgqKANPSbRba8zM6MXGDzVPxHYPPOzOOVPy471R03XmSRXlQEHv6VstqaakgJKh + h0X1oA5jBjYrP8uTkA9TQ0qoxLHqPyrQ1+z6TMu104x65/8A1ViSsVc5GdwoAseWbkDyQWC01QVv + S+5WGcbe9OguTFZqIjhxnPHWnWTCO6LyKjPnpQBDfs4n3sMc8Y7VPBKWT922498U7X0RCjRnJmAL + KP4aq2rtA/ycBu5HXFAGkYg0GT8rY5J5qIw5jyMORxU28zwAou5jxj1pnktAzCUlT1xQBHFP/Z8w + dpNsg6ccj8a6jQPFNjqdqbfxJbvPM/yxTE/LF9c1zsNsJ1U3EYIP8VPe1iicCORsnnHTBoAtat4Z + mS92Wn79WBK7aw0ia3uXW4jdChxkjvW/Z+KLjTZFd4hKwyAc44qy+nwazpxEOPNdvMdx1UdTQBzb + AbSNyqGPf+lWvDPiW58IXDtZzOIpRiVVON4qS/0ePcG04/aYV4Z8YwaoPGJrgq2AqnAPY0AdVdww + eJLX7XoxSKfbnyRwzn61zGooyMzsreYpwQTyn+P/ANap9NvX0S4DQtzu7dhW/rel2viWzWfRiPtC + L88a/wAfuaAOQEvyDepIOOamtbFJZWKzrH7Gpk02QRBLgYYHkDtSTaf5LBgM7u1AEVxbS2aiSNfm + xw3St7RfiTLFZi2vUe4VRt44xWJDczTzoLoFgvO096bMomlkaJfI5ztFAG7Jqdlrcm2WNYHA+82C + KidbiCAoVLWzfKoHOawo1dyGO4bQcc9frWppOvSwQLDcDzQSOvbmgCjcWBQsqDYwOTmo44BdAZfG + OeuK1NYdZLjzCdu8dAKzpLYQt+6OKAK88ciXREQ3AY5/Ckmt3dlMoznPSrMU2zJxgD2zSSRmX5kY + gdiO9AFWO3KSDgqMjrXQ6fYuUAjG3HO7rWRawNeSDLYKnHPeunVG0bR4ruTnc20g96AHxn7ZbNA7 + qzgcVzup2s2mzOl0CAT8jYzvrb1TxpZ3tgr6fBFFL/EUqpp+pJqpxeqJAPulucfSgDDfcjgxAqSP + mB60xXXlZFBPXpV2+tms5W2oTnpk1nht0uZCAfTFAG9oOvCJBb6jueJj8qj+Grer6XFCqvHMvHTA + zmuajlMUmWHznoKvQ6tLDEPtKeZnsT0oAkaBVLGX7x54qOG6NvkEEA/rV2dYLi08y3fMhH3e4rMR + mkDLOMkHg9KALcN7vXI4Iq9ZyG5jw7An1rFuWMWMAopxTzqMkIxZAuOpINAD7ZAcg9F6VqaXdRFg + pX5h92sPzRbfKQdvr61c0+4MjDyxsYHkkUAdA2lvdQ+ZcDIPGOuawNY0wWNywjwVbocdK2E1ubTF + +T5gw5yM1Lc2kOqaX5kXMxG4nPT8KAOSUSKu5VGM03aZmRo22k9Tird26Fgp+6hwcVAZfNmCnBVu + mKAJp7N71FDcuOI8d6pJlLlt+d44PoK0dTZLKCI2HmCZQCd33c+1R6iqXKpJBu34+bPQGmBNpzND + bgH7zHjPapLiXMhEvzMRwarQXG+ILcfMP7w7VZjdHj+QgMOmaQCRF7AsVBZO2am2G5t2kIAJ9O1V + 2vzM21l+UU9Cjj5M8eh4NAAIXjUeRl8/pUa6k1hGFtWyG6n+lWYX25Y8dsUs9t5tkVkK7Tz7+tAE + 9l4hAj8q/RUf+Db0P1qZ/DUWrTO0paK9cfLGg+Qn61zc0SeYc53DgVr+HNfk0u623LgwSDaxHLY9 + QaYFa80a60G58vU1VmbqF5AFWdC1k6PqaTW6qyEbSD+FdRJd2s8IikZJbO46MTmRB7nr2/WsrxD4 + QjtohLo+9kHXPb0pAd6uh6Lrekm6hkkQSRgNtQfK/p+dc1f/AAsuGUnSWSVScgynbisHQfGFxpki + RKw8tRyD0z/nNWPFHji/1lFihkCxKMAocUAaNt8NNSt3bzYrYsnT5xTLvwZYQTIuqzlLh/vqigqP + xrk/7QuIwRHcXG4jnMpP9ary3kzhvtUkrSH7p3E0AdXqPgvT1vI47K4kfcCcYAx0/wAar2ngu2uW + ZIJX3pnjHFc3DqUikfPIGHU5PFb2ka3PDe7dPZGGzGW7/wCc0AX7LRLSzcxb3eXrhhxVG78JeVcA + bvvcVfEgudqaoyrOrbiV9Pwpmo311pMnmWmySH3w1AGRrXh6TRfLMq8yfcHGPxqxZ6fpmnmNddml + jlk5+RQRx/8ArqO51ptT3vMwWU9iOF/CsOZHnkIkYu3YnmgDo7qPTtPszcWTu5LcAr1ycVl6p4hk + 1BRbsCEXkCqEGqz20wEWGEZGAeRxVy+vRqV2JpUVJiACQMAUAZ0+mvaNuuz88hwAOmaktbt7C4Ub + c8jvW5rGkp/YUEsRM0nLSf7PFYogSWEF/lJ6CgDWcjXyuMhwOAO9Y09hLbSyKy9+pqzpM9xo90Jr + co2OMMM5ropr2PxBYGK7VVXBbIXG4jnrQByUI8xSADs6HPWpPLIjGxssvr3pxQmcqx+VGwFHenJI + gOF5oAW0jZB5nQnnH6Usnzjrg0rW2/8AeISD1x2pWR5VySNo60AQBX2EzHIXpSQJ5kjOOFpLgrtI + iLFvWi2Y3CFYuoNAEt4myTBBQ46Gq6OyHKjGTzSyyyXUm+/cnHc0+PY42RtuDcDigDS03UzdQlHG + WHFSw3/2CX99lo+hA64NUorOeyG9FJA68VJFaLqNu0hkIlXkgelAF3VtEjvNMF1pKOctyPTFc/bw + tGVeMfMRzW54f119M8yJ2IjlGzk9B/k1p6f4fsmi2xXsUmeP88U7gYV5Et3aQlWCsox+NR2eUnWG + 7bdvrZ1TRY7FXjuQsatzHJ7VkyeXbxnz38xl6NmkBFfiXR3MDKQjHI9xUMV0ijMnNdBZWbeJbUcC + SZU+U454rFu/DF7byNJcW0qxqeeOtAE0EcbI+4nax49qnKNY7CCG46Vjw3DRHO1gtaNrqPnBRKu1 + R0Y80AXYDHPAzlPmzzTWG2Evn8KafMMWIsFfamKxcAyjAHbNAFSeRJpOBg0xrXykVjyp6VLqFv5b + AqwTI6dal02ZZ5VjuMNGentQBJZxXFtFuUZDcitDSPFrwOYrkFkfj6Vl30l7p87RpKRDn92eoIqG + 31gRxk3qMzqRnmgC/wCJtIa2uzLYfMjgEj2rNs70woyIMjPLHtW7Y3y38gkUnGBke1R6p4dS/mNx + obeZgfvIVH3Pf3oAz7W3EmGzgrSSRqszF13+4/hqOOLdGSrk5HO0d6WCUxYaUMYhw4HegCM6TLcy + Ztkd0wckd6jtZZbPiI+aqnlem2tTStXNvcbYZyiSA4QcdMf41Y8Taf8A2dZieGMR7sAkc7s8H+dA + GVJqTT3AKtjIxtrStNVy/kyLuUj1rAlhG4NtKqOc/wB+l+2SpP8AcKMn3s07gdJdeHPtLRS2zpCr + csD171laro72bGSFWZRwzHpQdUe8hTDEMg5xU0N7Pcx7GVpIf4lzSAwlk2yAoevUDpWpa2hvYeTg + 0mo2UM8w8lPs4HUDvRpsFz9oYW6NKB07U0BbjvptGhkgJDRMu01VLRyyIYQSgA3HstVdVMiSlZyx + bPKiksbyS1hdWUmKQ5K0gJpt8UgAw69iKn0/UyJdrdOmKIPIvW/cyLEqj7p4zUEUIEr+blHXJBx1 + oAk1O28q6VoSFVhk1GbZQ25TzUlvcfakIucKAcAnqaWK1cyFkQlB70AJvJdNq5I4+tBcbCnCjv71 + LIVcAowVhxj0qO2t9zkXHKt0bsKAIpbPIHlKWUjk06wgaNiqIBzViF/kKKwBHA9aguI5oX3REk9j + TQErWypGPOGc/pTLTy47gMFyob5fetB7EmcG3G6N8hSTjNWRpgsws/y7ouWB70gKd5dGSRcfKnIP + HFXrHSYL61e4kfyVVcYA61lC7OrxurAKxbIHtUtxfC2sTDA/A49KAEazRmkEw+TqG9as+H7YSTeX + bvu7ccYrIt7qRdobPLc59K6jw9pf2KUXcJBVjuI/z9aALF88MsJh1AiRoPl54Iqt5GmXUG3ABx1x + 0/WneMbGfTryO8VB5d2N6qfTJHP5VBoNtFqUb/b28uU/d2d6AJLPV4dGtP8AQyokHGKgu/Fwu9wl + PXgj0pmpaSmnOxmYEdu5rOht2knZ4FX3oAimiju3AtlAznrVWSAW7OC2HQ/d7VdNjLaMjurbSeMC + s+4WS41BjyEB5zQBcgnk2ARnJbqKZcydmZt3fFVxB+9DRkjHfNWLh/KKGTp/6FQBGLg3C5PzFeBT + LeT5yEzlB0p1zb7wGtzt9RTNhWVQOHPWgDc0iUajbPbTgM5GE9aydTtPKk8sKcDrk9adZX5+0FLc + FZM/K1dPpmgReJLR2nOyZDhQT1z60AYWgXYtrvy5cFXBXA9+OtGpLceH9YIsZ3BwGI4+YHsaNR09 + 9C1ERTFTMjBgE6YyO9S+IoDqHlag5++RGPfGKALelpb+IbtA+Ldk+ZkXofxqHxFpn2Vpv7OXdGOW + 56Vk3GpCBQB8pB429a0bHXN8kX2gKY1ILju1AGakfmFfJXLN0/z+VdZYQG503yda5xyPp/8AqqXw + 2LKJJvsqbjIdwDL936Viarq8u9nhA8sNg88/TFAGrdeFbeWBHscSL/AM9DWRqnhObyS7KUYdfetH + wkx1Gdnm3rECAB6Vu674psYbIRxeZuHBJHWgDzZw2nybQMluDVnT9T2PsJK56Ve1OS1vJ/OhOfXj + pWVdWctu/mJhgTxQBeYrOS0xAxTojJHKHspCQ3GPSqaXCTuqpnf+lTQIJ5XRXwy0AaN7YxzWzT3I + /fSHp6VnS2LI8Yt13kj5ucAU17me4hYbvkHXJ5qvJfDMYDNlevqeaAJTAVJGBuHPFSWuoMN32iNW + UgjOelVo5vNUvg8HGKVollOIG4HNAGhb6dHewhrVy8gPK4qaFTZZRssT1GKzLWd7C5zDlS1a9rq5 + vU2uFAIznuaAK93po2GSIEjqefu1C8QZApc+uBxWnbQpeyCG1OB1cnjmi5sUuTlxgpTQFBAYCWEQ + bjrmmsHvDypH0qYqYGPlk56DPSnWFuz3BN2MCkB0niGK10bw/ExCyMxwhVskH8K5O98SPfWixqPm + AxkjBNEkkz2iQSzgqn3U54rPm4RkY4YEfhQBd0gPBMGnwc8fSpvElpFBIGU5Y4Ix0qjcanIkKBG5 + 7VGzPdIHvF3P9aAHpGtymc4Ira0fU5YYUG7KA5P0rAEgjOFjfHtVqzndD8ilFkGKAPTri4h1fRrW + DVAojmjwjdwPY/XNcJK6aTfubdjhDgc9a19PnbUYLW2upsRJ8o61S8WeH1sryKJ2AeRSUb1oApTX + TXpaQMWJGcdal8PSf6UTcj5WOKz5YW0zgTKZG44Bq4THLpSqj7LhWJdsdfSgDo9e16OGFba0ji3p + wZCBzXOoYZp2N2u0Mecd6Zp12cIbkfIBzTbwRG53W4wp5oAbeWVmgY2ZYeuTVC4SWFAzjdGO5qws + HmK28jaTVi1vhaR+XfRGeJhtVR69jz6dfwpgZEcrPcAp92pl2IzMxLuRwamfSJZCXtnRhnLgcFR6 + VWc7J9mNpbtikAW9w0MheQj5ea3NG1Y2sPmWhCvjuf5Vk7UadY48RseW960rDS11C3b7EMzL3oAt + 6hpn9pZu4GzGq7djH5g2PzpPDsMV/Y3Fveg/uVZl+vNJYRy2KhXfcB972q5aRw310/2eZLbcuCWH + X8qaA4yTeT845B4qaEqjZlVtzflV+80qY31z/Z8T3ENqMs8ZAAGcd6zoZMncEwH6H0pAdDpusLZQ + 7Rjc3ApkFoZJHmY4iAPXpms8R7oh/Gc5HtXQaALbUtGMN6ApPHrzQA/TvEdsdOWD92rRk8gcmud8 + QXkl1cZzlfapr3QP7NujGjfKTlSKzr2Jmdgx/wBX096AIkn8ucBQQjdat/bWMLZKOOnOOKzdjL0P + BoiXe2Cu7vQBpxC0KAyK2488Hiql3LskbaDtbpjrV+3tlubYC2TExGBVe+tJNOAF4PmHNAFO0meG + R1bI9jU0iK23zcbsdagWYO+xOH7mrkMWYcNgkUAQwKGA4JC5pzyFmPlEADt61asYIgSJWA3dOKv6 + zosFpdxPaBGVlG445BwKAMwuWADAbqs6eI/3hl++Pu1cj8NFyrRncAdxb0psElpY37NMhljD4YKe + poAsWmm/aIjKknlsvUnoalhtHLcbiueucA1Uu9UMs8wt4SsOfkUnkCrOmXcotj9rkV0HSLnmgDoD + 4JSXSzPNNFJhdwCkZX9a5+K9gD+XPgDdjNTpez6ZZywwPskcZbk/KK5qZ2llPmvvYnrQATr8zE5D + N1zxRbou7951anhZNYuUVFw7dvSp59IltXdZ1IZKAGvpLNGfLAfufaqDCSKUEkgdMkVd07VWs7oG + XLL0x60+7ePUjyCpByMUAV3bBGxsk1ZikV4gAMkHOKpzW5SUmN849qjjnlil3KODxj0oA6KykW7t + yJW8pk4BFdxrGhwax4TS5JWWaEBEY9QDn/CvNrPUfJmBcZDHLV0s2vsfDMwt2ZYy4z7cGgDHv9NK + yjfD+8bgYFUNRtTps4S6HlkjIBPU/wCcVeN86xKZmJlyMc5p/ifU5L/RYVmto9wJUyZ5oAy01Dfb + qZV2xnoKbfX6NEv2ZcHHWmPLFJYQx2ZLTL1U1EIJA+2bAJ6Y5oAIboyDb0PU1c8xLkBJLna4Hy44 + 5x06VAbZbdcyZ3elNBXeCRjnOaAG2808N5syYmJ7fx+5q7tW5QCZQso/iqsULT7rXLr6k4xVi0dX + +9kmgBlxpbI7SxqZAoGWz0p+i3txZ3AezJAHXjrWlZ26mFyzEnPC+vStzTLO3vZ1M8Yjwp6Hr0oA + 5/xFqyrIggQKrLlsdc96xpQZ5wySbu2DVnVYQ9/MJCSitxVOQFW4G1aAOm+H3iGPSbie1upBDBqC + CKRugwOfwrI8VWsenazNHZtvs0fEb/3h6j171Elg02N65x6Gt200i18VwwwXcjQ3Fou2NQMiTvye + 3WgDn4riKEhkfKf3h6+9aFlGLeyS8eT5DIMoDnv3FXZ9I0iwhJFxJLMpwY2ACg1TvvISzMs77S5w + EUcUAW9dH9qW6y6ZKBgcgdawoNOu7iWMmNiWOMDtT4Jxb5e1bKuMEHsfWpNM1ZrG4WWFmct0BHSg + CprWivp0u193mMeR6VHa2jmQbVH0zV3WNRkv5mkn5YnjFRJGBMjRMScdKANvR7OO1u4pS+SGGV68 + d61/GnhSHUYReQyqsZXiPI64rK0S5hRNzfePXvWr5w1KIwwucAccUAefW1q8kqiT+WK0RpdzFFuE + bFT0bHBqxrFj/Z87LjDZ/Km2ctw7Kgk3KO3SgDPQPuHmqNynv2rRs7hrhjDIcDqD6VPeafDfWbbC + UnUjav8AeHfn8qsaL4bl2pLcYWJT85PYdzQBq6dfjRtKX7QnmC4JQH07f1rIl0SztbsSrcoQnJQH + qaseJ7mBVT7PIXtDwrYwQ3esOO4RrxvLZmjI+90P5UAXrm881T9lHOeAOareXPH+8BKOB19Kb9rF + pcq0ILDPc8mp7m+S6k3fdKj7vWgB8Gtj7Oq3AZ3fCs7DmorqxQTbl+oAqJJlu4gJMKwIxT3kNq+H + G5/7o7D1zTA7Pwpd6NBrk5vQwMv3Pl+7UnjAwwXX7tFe3l5UjBbHvXP3GnCOxhuo2IL1G+qPcFYX + cknoT/n2pbgVZtGFxZvNbH5VOBk+vt+FZ8lrPakrcqyHGcEYzWidWS3lCxAlVPUdDWxf6pa6nLH/ + AGlH99QoI4wTwKbA45pHEirjk1asbxYZCsoDYH1rV17wyumSKVbeGG4Y6gVk/wBn7UdgCpPc0gLw + aEwtLKMDtWhoNykVwHdd8JGCjDIrDkSW1g2zOhVhkVLo+puSVlKlccYoA6Dxf4PbSLRb21wto7DG + W7ntj61mpKdXtxaOQvlfMCSBuJrqLfWIfEvhg2muKzQoN4CnBJHT9cVyU5hEjNbB0CHABPNAGTPa + fZriQONjqcZ6flUtqqB1SRmMr/dJzWlDaLrEUh1Qbnx+628ZNZE1s9nfctxEccjpQBO9tLcy7Zjw + vfNQ31q9oee3A75qe2Yyzby5OKiutRMsjKQDg4FG4EVvEyfM5xnsD1q5bbzKHBAB9KrCJN4YMd3p + V+wt8szRZUCnYDXsWSGPz7jGI+SMVVuvErXKEWuRk9QMYqXVyLXTUyRmRcmsSC4EAO8D2pAXxbma + IMR8w7+tVdRtkUAT9ew71as7wsF2nFGsKodDOMzHo/YU0rgULe7j098qW545Gaki1FIbwzeYyzfw + EdvyqkyGSfaw+bvRcQLayqyEnAyaQHR6gi6/pXnBER0IGFHzN15rnmlXyTGRuQHByeQau2GrS20G + 9OhO3H1//VWhf6RprXbXmnrMtuYsOjNk78DkfiDQBi2rpHIVQjb1otHPnBZAMAdRVUQiW6Bgyis2 + Buq29q2nXJjn/eDsycUAOLCG8yg9zkcVCzeVIZY+cenekN0LqYRSHAHA9aLMCOTy5BlTyPegCxa6 + ltkL2+ORzxjFWbTXpLSV3Y84+XFVJvLilKjgVFMpAyBxQBq6prEF7bQSzA+ZJ97jpVRGjDbUJAB+ + U+tUywlJUdE6VteHLK3kuoDqQZ0zyAcYFAG3feVo+io90u2d13R/LyR35rm77VZNSmzC5SEj5hnH + 14/Otu+hv/FN3gTWywW4KRqQM4/OsUeFZp5miaVAc9R0oAaXWa0EUWCIjuA9PeqEMbCYM3G77oAr + bi8Gz2YDmeLc3ygev61X1CxnnuTE8TvPb9fKXigDMuIJFlBdtzHnAPSrEF0IwDCm5hw2VNRzxTWt + 0BeKVMnTIxj8KZ/ahtgY49uT7UAX7VH1K63oERVOTxiuu0ex0nS7L7chJkm+R1kwwyPQZrh4JJDw + zbVbk4/OrNpefLsnyyg5UUAf/9k= + +END:VCARD diff --git a/vendor/sabre/vobject/tests/bootstrap.php b/vendor/sabre/vobject/tests/bootstrap.php new file mode 100644 index 000000000..590b25080 --- /dev/null +++ b/vendor/sabre/vobject/tests/bootstrap.php @@ -0,0 +1,23 @@ + + + VObject/ + + + + + ../lib/ + + ../lib/Sabre/VObject/includes.php + + + + diff --git a/vendor/sabre/xml/.gitignore b/vendor/sabre/xml/.gitignore new file mode 100644 index 000000000..accb586c7 --- /dev/null +++ b/vendor/sabre/xml/.gitignore @@ -0,0 +1,9 @@ +vendor +composer.lock +tests/cov +.*.swp + +# Composer binaries +bin/phpunit +bin/php-cs-fixer +bin/sabre-cs-fixer diff --git a/vendor/sabre/xml/.travis.yml b/vendor/sabre/xml/.travis.yml new file mode 100644 index 000000000..96396564e --- /dev/null +++ b/vendor/sabre/xml/.travis.yml @@ -0,0 +1,26 @@ +language: php +php: + - 5.5 + - 5.6 + - 7.0 + - 7.1 + +matrix: + fast_finish: true + +sudo: false + +cache: + directories: + - $HOME/.composer/cache + +before_install: + - phpenv config-rm xdebug.ini; true + +install: + - composer install + +script: + - ./bin/phpunit --configuration tests/phpunit.xml.dist + - ./bin/sabre-cs-fixer fix . --dry-run --diff + diff --git a/vendor/sabre/xml/bin/.empty b/vendor/sabre/xml/bin/.empty new file mode 100644 index 000000000..e69de29bb diff --git a/vendor/sabre/xml/composer.json b/vendor/sabre/xml/composer.json new file mode 100644 index 000000000..1b5760393 --- /dev/null +++ b/vendor/sabre/xml/composer.json @@ -0,0 +1,53 @@ +{ + "name": "sabre/xml", + "description" : "sabre/xml is an XML library that you may not hate.", + "keywords" : [ "XML", "XMLReader", "XMLWriter", "DOM" ], + "homepage" : "https://sabre.io/xml/", + "license" : "BSD-3-Clause", + "require" : { + "php" : ">=5.5.5", + "ext-xmlwriter" : "*", + "ext-xmlreader" : "*", + "ext-dom" : "*", + "lib-libxml" : ">=2.6.20", + "sabre/uri" : ">=1.0,<3.0.0" + }, + "authors" : [ + { + "name" : "Evert Pot", + "email" : "me@evertpot.com", + "homepage" : "http://evertpot.com/", + "role" : "Developer" + }, + { + "name": "Markus Staab", + "email": "markus.staab@redaxo.de", + "role" : "Developer" + } + ], + "support" : { + "forum" : "https://groups.google.com/group/sabredav-discuss", + "source" : "https://github.com/fruux/sabre-xml" + }, + "autoload" : { + "psr-4" : { + "Sabre\\Xml\\" : "lib/" + }, + "files": [ + "lib/Deserializer/functions.php", + "lib/Serializer/functions.php" + ] + }, + "autoload-dev" : { + "psr-4" : { + "Sabre\\Xml\\" : "tests/Sabre/Xml/" + } + }, + "require-dev": { + "sabre/cs": "~1.0.0", + "phpunit/phpunit" : "~4.8|~5.7" + }, + "config" : { + "bin-dir" : "bin/" + } +} diff --git a/vendor/sabre/xml/tests/Sabre/Xml/ContextStackTest.php b/vendor/sabre/xml/tests/Sabre/Xml/ContextStackTest.php new file mode 100644 index 000000000..71dfd3f5c --- /dev/null +++ b/vendor/sabre/xml/tests/Sabre/Xml/ContextStackTest.php @@ -0,0 +1,44 @@ +stack = $this->getMockForTrait('Sabre\\Xml\\ContextStackTrait'); + + } + + function testPushAndPull() { + + $this->stack->contextUri = '/foo/bar'; + $this->stack->elementMap['{DAV:}foo'] = 'Bar'; + $this->stack->namespaceMap['DAV:'] = 'd'; + + $this->stack->pushContext(); + + $this->assertEquals('/foo/bar', $this->stack->contextUri); + $this->assertEquals('Bar', $this->stack->elementMap['{DAV:}foo']); + $this->assertEquals('d', $this->stack->namespaceMap['DAV:']); + + $this->stack->contextUri = '/gir/zim'; + $this->stack->elementMap['{DAV:}foo'] = 'newBar'; + $this->stack->namespaceMap['DAV:'] = 'dd'; + + $this->stack->popContext(); + + $this->assertEquals('/foo/bar', $this->stack->contextUri); + $this->assertEquals('Bar', $this->stack->elementMap['{DAV:}foo']); + $this->assertEquals('d', $this->stack->namespaceMap['DAV:']); + + } + +} diff --git a/vendor/sabre/xml/tests/Sabre/Xml/Deserializer/EnumTest.php b/vendor/sabre/xml/tests/Sabre/Xml/Deserializer/EnumTest.php new file mode 100644 index 000000000..4e32544fa --- /dev/null +++ b/vendor/sabre/xml/tests/Sabre/Xml/Deserializer/EnumTest.php @@ -0,0 +1,88 @@ +elementMap['{urn:test}root'] = 'Sabre\Xml\Deserializer\enum'; + + $xml = << + + + + +XML; + + $result = $service->parse($xml); + + $expected = [ + '{urn:test}foo1', + '{urn:test}foo2', + ]; + + + $this->assertEquals($expected, $result); + + + } + + function testDeserializeDefaultNamespace() { + + $service = new Service(); + $service->elementMap['{urn:test}root'] = function($reader) { + return enum($reader, 'urn:test'); + }; + + $xml = << + + + + +XML; + + $result = $service->parse($xml); + + $expected = [ + 'foo1', + 'foo2', + ]; + + + $this->assertEquals($expected, $result); + + } + + function testEmptyEnum() + { + $service = new Service(); + $service->elementMap['{urn:test}enum'] = 'Sabre\Xml\Deserializer\enum'; + + $xml = << + + + + + +XML; + + $result = $service->parse($xml); + + $this->assertEquals([[ + 'name' => '{urn:test}inner', + 'value' => [[ + 'name' => '{urn:test}enum', + 'value' => [], + 'attributes' => [], + ]], + 'attributes' => [], + ]], $result); + } +} diff --git a/vendor/sabre/xml/tests/Sabre/Xml/Deserializer/KeyValueTest.php b/vendor/sabre/xml/tests/Sabre/Xml/Deserializer/KeyValueTest.php new file mode 100644 index 000000000..2f0eda317 --- /dev/null +++ b/vendor/sabre/xml/tests/Sabre/Xml/Deserializer/KeyValueTest.php @@ -0,0 +1,153 @@ + + + + + hi + + foo + foo & bar + + + + +BLA; + + $reader = new Reader(); + $reader->elementMap = [ + '{http://sabredav.org/ns}struct' => function(Reader $reader) { + return keyValue($reader, 'http://sabredav.org/ns'); + } + ]; + $reader->xml($input); + $output = $reader->parse(); + + $this->assertEquals([ + 'name' => '{http://sabredav.org/ns}root', + 'value' => [ + [ + 'name' => '{http://sabredav.org/ns}struct', + 'value' => [ + 'elem1' => null, + 'elem2' => 'hi', + '{http://sabredav.org/another-ns}elem3' => [ + [ + 'name' => '{http://sabredav.org/another-ns}elem4', + 'value' => 'foo', + 'attributes' => [], + ], + [ + 'name' => '{http://sabredav.org/another-ns}elem5', + 'value' => 'foo & bar', + 'attributes' => [], + ], + ], + 'elem6' => null, + ], + 'attributes' => [], + ] + ], + 'attributes' => [], + ], $output); + } + + /** + * @expectedException \Sabre\Xml\LibXMLException + */ + function testKeyValueLoop() { + + /** + * This bug is a weird one, because it triggers an infinite loop, but + * only if the XML document is a certain size (in bytes). Removing one + * or two characters from the xml body here cause the infinite loop to + * *not* get triggered, so to properly test this bug (Issue #94), don't + * change the XML body. + */ + $invalid_xml = ' + + + NONE + ENVELOPE + 1 + DC + + NONE + ENVELOPE + 1 + DC/FleetType> + + '; + $reader = new Reader(); + + $reader->xml($invalid_xml); + $reader->elementMap = [ + + '{}Package' => function($reader) { + $recipient = []; + // Borrowing a parser from the KeyValue class. + $keyValue = keyValue($reader); + + if (isset($keyValue['{}WeightOz'])){ + $recipient['referenceId'] = $keyValue['{}WeightOz']; + } + + return $recipient; + }, + ]; + + $reader->parse(); + + + } + + function testEmptyKeyValue() + { + // the nested structure below is necessary to detect if one of the deserialization functions eats to much elements + $input = << + + + + + +BLA; + + $reader = new Reader(); + $reader->elementMap = [ + '{http://sabredav.org/ns}struct' => function(Reader $reader) { + return keyValue($reader, 'http://sabredav.org/ns'); + }, + ]; + $reader->xml($input); + $output = $reader->parse(); + + $this->assertEquals([ + 'name' => '{http://sabredav.org/ns}root', + 'value' => [ + [ + 'name' => '{http://sabredav.org/ns}inner', + 'value' => [ + [ + 'name' => '{http://sabredav.org/ns}struct', + 'value' => [], + 'attributes' => [], + ], + ], + 'attributes' => [], + ], + ], + 'attributes' => [], + ], $output); + } +} diff --git a/vendor/sabre/xml/tests/Sabre/Xml/Deserializer/RepeatingElementsTest.php b/vendor/sabre/xml/tests/Sabre/Xml/Deserializer/RepeatingElementsTest.php new file mode 100644 index 000000000..025d997fe --- /dev/null +++ b/vendor/sabre/xml/tests/Sabre/Xml/Deserializer/RepeatingElementsTest.php @@ -0,0 +1,35 @@ +elementMap['{urn:test}collection'] = function($reader) { + return repeatingElements($reader, '{urn:test}item'); + }; + + $xml = << + + foo + bar + +XML; + + $result = $service->parse($xml); + + $expected = [ + 'foo', + 'bar', + ]; + + $this->assertEquals($expected, $result); + + } + +} diff --git a/vendor/sabre/xml/tests/Sabre/Xml/Deserializer/ValueObjectTest.php b/vendor/sabre/xml/tests/Sabre/Xml/Deserializer/ValueObjectTest.php new file mode 100644 index 000000000..2d6ce98ce --- /dev/null +++ b/vendor/sabre/xml/tests/Sabre/Xml/Deserializer/ValueObjectTest.php @@ -0,0 +1,169 @@ + + + Harry + Turtle + +XML; + + $reader = new Reader(); + $reader->xml($input); + $reader->elementMap = [ + '{urn:foo}foo' => function(Reader $reader) { + return valueObject($reader, 'Sabre\\Xml\\Deserializer\\TestVo', 'urn:foo'); + } + ]; + + $output = $reader->parse(); + + $vo = new TestVo(); + $vo->firstName = 'Harry'; + $vo->lastName = 'Turtle'; + + $expected = [ + 'name' => '{urn:foo}foo', + 'value' => $vo, + 'attributes' => [] + ]; + + $this->assertEquals( + $expected, + $output + ); + + } + + function testDeserializeValueObjectIgnoredElement() { + + $input = << + + Harry + Turtle + harry@example.org + +XML; + + $reader = new Reader(); + $reader->xml($input); + $reader->elementMap = [ + '{urn:foo}foo' => function(Reader $reader) { + return valueObject($reader, 'Sabre\\Xml\\Deserializer\\TestVo', 'urn:foo'); + } + ]; + + $output = $reader->parse(); + + $vo = new TestVo(); + $vo->firstName = 'Harry'; + $vo->lastName = 'Turtle'; + + $expected = [ + 'name' => '{urn:foo}foo', + 'value' => $vo, + 'attributes' => [] + ]; + + $this->assertEquals( + $expected, + $output + ); + + } + + function testDeserializeValueObjectAutoArray() { + + $input = << + + Harry + Turtle + http://example.org/ + http://example.net/ + +XML; + + $reader = new Reader(); + $reader->xml($input); + $reader->elementMap = [ + '{urn:foo}foo' => function(Reader $reader) { + return valueObject($reader, 'Sabre\\Xml\\Deserializer\\TestVo', 'urn:foo'); + } + ]; + + $output = $reader->parse(); + + $vo = new TestVo(); + $vo->firstName = 'Harry'; + $vo->lastName = 'Turtle'; + $vo->link = [ + 'http://example.org/', + 'http://example.net/', + ]; + + + $expected = [ + 'name' => '{urn:foo}foo', + 'value' => $vo, + 'attributes' => [] + ]; + + $this->assertEquals( + $expected, + $output + ); + + } + function testDeserializeValueObjectEmpty() { + + $input = << + +XML; + + $reader = new Reader(); + $reader->xml($input); + $reader->elementMap = [ + '{urn:foo}foo' => function(Reader $reader) { + return valueObject($reader, 'Sabre\\Xml\\Deserializer\\TestVo', 'urn:foo'); + } + ]; + + $output = $reader->parse(); + + $vo = new TestVo(); + + $expected = [ + 'name' => '{urn:foo}foo', + 'value' => $vo, + 'attributes' => [] + ]; + + $this->assertEquals( + $expected, + $output + ); + + } + +} + +class TestVo { + + public $firstName; + public $lastName; + + public $link = []; + +} diff --git a/vendor/sabre/xml/tests/Sabre/Xml/Element/CDataTest.php b/vendor/sabre/xml/tests/Sabre/Xml/Element/CDataTest.php new file mode 100644 index 000000000..2d12d7b21 --- /dev/null +++ b/vendor/sabre/xml/tests/Sabre/Xml/Element/CDataTest.php @@ -0,0 +1,58 @@ + + + + +BLA; + + $reader = new Reader(); + $reader->elementMap = [ + '{http://sabredav.org/ns}blabla' => 'Sabre\\Xml\\Element\\Cdata', + ]; + $reader->xml($input); + + $output = $reader->parse(); + + } + + function testSerialize() { + + $writer = new Writer(); + $writer->namespaceMap = [ + 'http://sabredav.org/ns' => null + ]; + $writer->openMemory(); + $writer->startDocument('1.0'); + $writer->setIndent(true); + $writer->write([ + '{http://sabredav.org/ns}root' => new Cdata(''), + ]); + + $output = $writer->outputMemory(); + + $expected = << +]]> + +XML; + + $this->assertEquals($expected, $output); + + + } + +} diff --git a/vendor/sabre/xml/tests/Sabre/Xml/Element/Eater.php b/vendor/sabre/xml/tests/Sabre/Xml/Element/Eater.php new file mode 100644 index 000000000..aaba2a01f --- /dev/null +++ b/vendor/sabre/xml/tests/Sabre/Xml/Element/Eater.php @@ -0,0 +1,78 @@ +startElement('{http://sabredav.org/ns}elem1'); + $writer->write('hiiii!'); + $writer->endElement(); + + } + + /** + * The deserialize method is called during xml parsing. + * + * This method is called statictly, this is because in theory this method + * may be used as a type of constructor, or factory method. + * + * Often you want to return an instance of the current class, but you are + * free to return other data as well. + * + * Important note 2: You are responsible for advancing the reader to the + * next element. Not doing anything will result in a never-ending loop. + * + * If you just want to skip parsing for this element altogether, you can + * just call $reader->next(); + * + * $reader->parseSubTree() will parse the entire sub-tree, and advance to + * the next element. + * + * @param Xml\Reader $reader + * @return mixed + */ + static function xmlDeserialize(Xml\Reader $reader) { + + $reader->next(); + + $count = 1; + while ($count) { + + $reader->read(); + if ($reader->nodeType === $reader::END_ELEMENT) { + $count--; + } + + } + $reader->read(); + + } + +} diff --git a/vendor/sabre/xml/tests/Sabre/Xml/Element/ElementsTest.php b/vendor/sabre/xml/tests/Sabre/Xml/Element/ElementsTest.php new file mode 100644 index 000000000..f17f2094b --- /dev/null +++ b/vendor/sabre/xml/tests/Sabre/Xml/Element/ElementsTest.php @@ -0,0 +1,129 @@ + + + + + + + + content + + + + + + + + + +BLA; + + $reader = new Reader(); + $reader->elementMap = [ + '{http://sabredav.org/ns}listThingy' => 'Sabre\\Xml\\Element\\Elements', + ]; + $reader->xml($input); + + $output = $reader->parse(); + + $this->assertEquals([ + 'name' => '{http://sabredav.org/ns}root', + 'value' => [ + [ + 'name' => '{http://sabredav.org/ns}listThingy', + 'value' => [ + '{http://sabredav.org/ns}elem1', + '{http://sabredav.org/ns}elem2', + '{http://sabredav.org/ns}elem3', + '{http://sabredav.org/ns}elem4', + '{http://sabredav.org/ns}elem5', + '{http://sabredav.org/ns}elem6', + ], + 'attributes' => [], + ], + [ + 'name' => '{http://sabredav.org/ns}listThingy', + 'value' => [], + 'attributes' => [], + ], + [ + 'name' => '{http://sabredav.org/ns}otherThing', + 'value' => [ + [ + 'name' => '{http://sabredav.org/ns}elem1', + 'value' => null, + 'attributes' => [], + ], + [ + 'name' => '{http://sabredav.org/ns}elem2', + 'value' => null, + 'attributes' => [], + ], + [ + 'name' => '{http://sabredav.org/ns}elem3', + 'value' => null, + 'attributes' => [], + ], + ], + 'attributes' => [], + ], + ], + 'attributes' => [], + ], $output); + + } + + function testSerialize() { + + $value = [ + '{http://sabredav.org/ns}elem1', + '{http://sabredav.org/ns}elem2', + '{http://sabredav.org/ns}elem3', + '{http://sabredav.org/ns}elem4', + '{http://sabredav.org/ns}elem5', + '{http://sabredav.org/ns}elem6', + ]; + + $writer = new Writer(); + $writer->namespaceMap = [ + 'http://sabredav.org/ns' => null + ]; + $writer->openMemory(); + $writer->startDocument('1.0'); + $writer->setIndent(true); + $writer->write([ + '{http://sabredav.org/ns}root' => new Elements($value), + ]); + + $output = $writer->outputMemory(); + + $expected = << + + + + + + + + + +XML; + + $this->assertEquals($expected, $output); + + + } + +} diff --git a/vendor/sabre/xml/tests/Sabre/Xml/Element/KeyValueTest.php b/vendor/sabre/xml/tests/Sabre/Xml/Element/KeyValueTest.php new file mode 100644 index 000000000..51c87b520 --- /dev/null +++ b/vendor/sabre/xml/tests/Sabre/Xml/Element/KeyValueTest.php @@ -0,0 +1,210 @@ + + + + + hi + + foo + foo & bar + + Hithere + + + + + + +BLA; + + $reader = new Reader(); + $reader->elementMap = [ + '{http://sabredav.org/ns}struct' => 'Sabre\\Xml\\Element\\KeyValue', + ]; + $reader->xml($input); + + $output = $reader->parse(); + + $this->assertEquals([ + 'name' => '{http://sabredav.org/ns}root', + 'value' => [ + [ + 'name' => '{http://sabredav.org/ns}struct', + 'value' => [ + '{http://sabredav.org/ns}elem1' => null, + '{http://sabredav.org/ns}elem2' => 'hi', + '{http://sabredav.org/ns}elem3' => [ + [ + 'name' => '{http://sabredav.org/ns}elem4', + 'value' => 'foo', + 'attributes' => [], + ], + [ + 'name' => '{http://sabredav.org/ns}elem5', + 'value' => 'foo & bar', + 'attributes' => [], + ], + ], + '{http://sabredav.org/ns}elem6' => 'Hithere', + ], + 'attributes' => [], + ], + [ + 'name' => '{http://sabredav.org/ns}struct', + 'value' => [], + 'attributes' => [], + ], + [ + 'name' => '{http://sabredav.org/ns}otherThing', + 'value' => [ + [ + 'name' => '{http://sabredav.org/ns}elem1', + 'value' => null, + 'attributes' => [], + ], + ], + 'attributes' => [], + ], + ], + 'attributes' => [], + ], $output); + + } + + /** + * This test was added to find out why an element gets eaten by the + * SabreDAV MKCOL parser. + */ + function testElementEater() { + + $input = << + + + + + bla + + + +BLA; + + $reader = new Reader(); + $reader->elementMap = [ + '{DAV:}set' => 'Sabre\\Xml\\Element\\KeyValue', + '{DAV:}prop' => 'Sabre\\Xml\\Element\\KeyValue', + '{DAV:}resourcetype' => 'Sabre\\Xml\\Element\\Elements', + ]; + $reader->xml($input); + + $expected = [ + 'name' => '{DAV:}mkcol', + 'value' => [ + [ + 'name' => '{DAV:}set', + 'value' => [ + '{DAV:}prop' => [ + '{DAV:}resourcetype' => [ + '{DAV:}collection', + ], + '{DAV:}displayname' => 'bla', + ], + ], + 'attributes' => [], + ], + ], + 'attributes' => [], + ]; + + $this->assertEquals($expected, $reader->parse()); + + } + + + function testSerialize() { + + $value = [ + '{http://sabredav.org/ns}elem1' => null, + '{http://sabredav.org/ns}elem2' => 'textValue', + '{http://sabredav.org/ns}elem3' => [ + '{http://sabredav.org/ns}elem4' => 'text2', + '{http://sabredav.org/ns}elem5' => null, + ], + '{http://sabredav.org/ns}elem6' => 'text3', + ]; + + $writer = new Writer(); + $writer->namespaceMap = [ + 'http://sabredav.org/ns' => null + ]; + $writer->openMemory(); + $writer->startDocument('1.0'); + $writer->setIndent(true); + $writer->write([ + '{http://sabredav.org/ns}root' => new KeyValue($value), + ]); + + $output = $writer->outputMemory(); + + $expected = << + + + textValue + + text2 + + + text3 + + +XML; + + $this->assertEquals($expected, $output); + + } + + /** + * I discovered that when there's no whitespace between elements, elements + * can get skipped. + */ + function testElementSkipProblem() { + + $input = << + +val3val4val5 +BLA; + + $reader = new Reader(); + $reader->elementMap = [ + '{http://sabredav.org/ns}root' => 'Sabre\\Xml\\Element\\KeyValue', + ]; + $reader->xml($input); + + $output = $reader->parse(); + + $this->assertEquals([ + 'name' => '{http://sabredav.org/ns}root', + 'value' => [ + '{http://sabredav.org/ns}elem3' => 'val3', + '{http://sabredav.org/ns}elem4' => 'val4', + '{http://sabredav.org/ns}elem5' => 'val5', + ], + 'attributes' => [], + ], $output); + + } + +} diff --git a/vendor/sabre/xml/tests/Sabre/Xml/Element/Mock.php b/vendor/sabre/xml/tests/Sabre/Xml/Element/Mock.php new file mode 100644 index 000000000..f96684cb5 --- /dev/null +++ b/vendor/sabre/xml/tests/Sabre/Xml/Element/Mock.php @@ -0,0 +1,60 @@ +startElement('{http://sabredav.org/ns}elem1'); + $writer->write('hiiii!'); + $writer->endElement(); + + } + + /** + * The deserialize method is called during xml parsing. + * + * This method is called statictly, this is because in theory this method + * may be used as a type of constructor, or factory method. + * + * Often you want to return an instance of the current class, but you are + * free to return other data as well. + * + * Important note 2: You are responsible for advancing the reader to the + * next element. Not doing anything will result in a never-ending loop. + * + * If you just want to skip parsing for this element altogether, you can + * just call $reader->next(); + * + * $reader->parseSubTree() will parse the entire sub-tree, and advance to + * the next element. + * + * @param Xml\Reader $reader + * @return mixed + */ + static function xmlDeserialize(Xml\Reader $reader) { + + $reader->next(); + return 'foobar'; + + } + +} diff --git a/vendor/sabre/xml/tests/Sabre/Xml/Element/UriTest.php b/vendor/sabre/xml/tests/Sabre/Xml/Element/UriTest.php new file mode 100644 index 000000000..53f89ed7a --- /dev/null +++ b/vendor/sabre/xml/tests/Sabre/Xml/Element/UriTest.php @@ -0,0 +1,76 @@ + + + /foo/bar + +BLA; + + $reader = new Reader(); + $reader->contextUri = 'http://example.org/'; + $reader->elementMap = [ + '{http://sabredav.org/ns}uri' => 'Sabre\\Xml\\Element\\Uri', + ]; + $reader->xml($input); + + $output = $reader->parse(); + + $this->assertEquals( + [ + 'name' => '{http://sabredav.org/ns}root', + 'value' => [ + [ + 'name' => '{http://sabredav.org/ns}uri', + 'value' => new Uri('http://example.org/foo/bar'), + 'attributes' => [], + ] + ], + 'attributes' => [], + ], + $output + ); + + } + + function testSerialize() { + + $writer = new Writer(); + $writer->namespaceMap = [ + 'http://sabredav.org/ns' => null + ]; + $writer->openMemory(); + $writer->startDocument('1.0'); + $writer->setIndent(true); + $writer->contextUri = 'http://example.org/'; + $writer->write([ + '{http://sabredav.org/ns}root' => [ + '{http://sabredav.org/ns}uri' => new Uri('/foo/bar'), + ] + ]); + + $output = $writer->outputMemory(); + + $expected = << + + http://example.org/foo/bar + + +XML; + + $this->assertEquals($expected, $output); + + + } + +} diff --git a/vendor/sabre/xml/tests/Sabre/Xml/Element/XmlFragmentTest.php b/vendor/sabre/xml/tests/Sabre/Xml/Element/XmlFragmentTest.php new file mode 100644 index 000000000..461cc155c --- /dev/null +++ b/vendor/sabre/xml/tests/Sabre/Xml/Element/XmlFragmentTest.php @@ -0,0 +1,143 @@ + + + $input + +BLA; + + $reader = new Reader(); + $reader->elementMap = [ + '{http://sabredav.org/ns}fragment' => 'Sabre\\Xml\\Element\\XmlFragment', + ]; + $reader->xml($input); + + $output = $reader->parse(); + + $this->assertEquals([ + 'name' => '{http://sabredav.org/ns}root', + 'value' => [ + [ + 'name' => '{http://sabredav.org/ns}fragment', + 'value' => new XmlFragment($expected), + 'attributes' => [], + ], + ], + 'attributes' => [], + ], $output); + + } + + /** + * Data provider for serialize and deserialize tests. + * + * Returns three items per test: + * + * 1. Input data for the reader. + * 2. Expected output for XmlFragment deserializer + * 3. Expected output after serializing that value again. + * + * If 3 is not set, use 1 for 3. + * + * @return void + */ + function xmlProvider() { + + return [ + [ + 'hello', + 'hello', + ], + [ + 'hello', + 'hello' + ], + [ + 'hello', + 'hello' + ], + [ + 'hello', + 'hello' + ], + [ + 'hello', + 'hello', + 'hello', + ], + [ + 'hello', + 'hello', + 'hello', + ], + [ + 'hello', + 'hello', + 'hello', + ], + [ + 'hello', + 'hello', + 'hello', + ], + [ + '', + '', + '', + ], + [ + '', + '', + '', + ], + ]; + + } + + /** + * @dataProvider xmlProvider + */ + function testSerialize($expectedFallback, $input, $expected = null) { + + if (is_null($expected)) { + $expected = $expectedFallback; + } + + $writer = new Writer(); + $writer->namespaceMap = [ + 'http://sabredav.org/ns' => null + ]; + $writer->openMemory(); + $writer->startDocument('1.0'); + //$writer->setIndent(true); + $writer->write([ + '{http://sabredav.org/ns}root' => [ + '{http://sabredav.org/ns}fragment' => new XmlFragment($input), + ], + ]); + + $output = $writer->outputMemory(); + + $expected = << +$expected +XML; + + $this->assertEquals($expected, $output); + + } + +} diff --git a/vendor/sabre/xml/tests/Sabre/Xml/InfiteLoopTest.php b/vendor/sabre/xml/tests/Sabre/Xml/InfiteLoopTest.php new file mode 100644 index 000000000..ec8a136d0 --- /dev/null +++ b/vendor/sabre/xml/tests/Sabre/Xml/InfiteLoopTest.php @@ -0,0 +1,50 @@ + + + + +'; + + $reader = new Reader(); + $reader->elementMap = [ + '{DAV:}set' => 'Sabre\\Xml\\Element\\KeyValue', + ]; + $reader->xml($body); + + $output = $reader->parse(); + + $this->assertEquals([ + 'name' => '{DAV:}propertyupdate', + 'value' => [ + [ + 'name' => '{DAV:}set', + 'value' => [ + '{DAV:}prop' => null, + ], + 'attributes' => [], + ], + [ + 'name' => '{DAV:}set', + 'value' => [ + '{DAV:}prop' => null, + ], + 'attributes' => [], + ], + ], + 'attributes' => [], + ], $output); + + } + +} diff --git a/vendor/sabre/xml/tests/Sabre/Xml/ReaderTest.php b/vendor/sabre/xml/tests/Sabre/Xml/ReaderTest.php new file mode 100644 index 000000000..8da81d120 --- /dev/null +++ b/vendor/sabre/xml/tests/Sabre/Xml/ReaderTest.php @@ -0,0 +1,585 @@ + + +BLA; + $reader = new Reader(); + $reader->xml($input); + + $reader->next(); + + $this->assertEquals('{http://sabredav.org/ns}root', $reader->getClark()); + + } + + function testGetClarkNoNS() { + + $input = << + +BLA; + $reader = new Reader(); + $reader->xml($input); + + $reader->next(); + + $this->assertEquals('{}root', $reader->getClark()); + + } + + function testGetClarkNotOnAnElement() { + + $input = << + +BLA; + $reader = new Reader(); + $reader->xml($input); + + $this->assertNull($reader->getClark()); + } + + function testSimple() { + + $input = << + + + + Hi! + + +BLA; + + $reader = new Reader(); + $reader->xml($input); + + $output = $reader->parse(); + + $expected = [ + 'name' => '{http://sabredav.org/ns}root', + 'value' => [ + [ + 'name' => '{http://sabredav.org/ns}elem1', + 'value' => null, + 'attributes' => [ + 'attr' => 'val', + ], + ], + [ + 'name' => '{http://sabredav.org/ns}elem2', + 'value' => [ + [ + 'name' => '{http://sabredav.org/ns}elem3', + 'value' => 'Hi!', + 'attributes' => [], + ], + ], + 'attributes' => [], + ], + + ], + 'attributes' => [], + + ]; + + $this->assertEquals($expected, $output); + + } + + function testCDATA() { + + $input = << + + + +BLA; + + $reader = new Reader(); + $reader->xml($input); + + $output = $reader->parse(); + + $expected = [ + 'name' => '{http://sabredav.org/ns}root', + 'value' => [ + [ + 'name' => '{http://sabredav.org/ns}foo', + 'value' => 'bar', + 'attributes' => [], + ], + + ], + 'attributes' => [], + + ]; + + $this->assertEquals($expected, $output); + + } + + function testSimpleNamespacedAttribute() { + + $input = << + + + +BLA; + + $reader = new Reader(); + $reader->xml($input); + + $output = $reader->parse(); + + $expected = [ + 'name' => '{http://sabredav.org/ns}root', + 'value' => [ + [ + 'name' => '{http://sabredav.org/ns}elem1', + 'value' => null, + 'attributes' => [ + '{urn:foo}attr' => 'val', + ], + ], + ], + 'attributes' => [], + ]; + + $this->assertEquals($expected, $output); + + } + + function testMappedElement() { + + $input = << + + + +BLA; + + $reader = new Reader(); + $reader->elementMap = [ + '{http://sabredav.org/ns}elem1' => 'Sabre\\Xml\\Element\\Mock' + ]; + $reader->xml($input); + + $output = $reader->parse(); + + $expected = [ + 'name' => '{http://sabredav.org/ns}root', + 'value' => [ + [ + 'name' => '{http://sabredav.org/ns}elem1', + 'value' => 'foobar', + 'attributes' => [], + ], + ], + 'attributes' => [], + + ]; + + $this->assertEquals($expected, $output); + + } + + /** + * @expectedException \LogicException + */ + function testMappedElementBadClass() { + + $input = << + + + +BLA; + + $reader = new Reader(); + $reader->elementMap = [ + '{http://sabredav.org/ns}elem1' => new \StdClass() + ]; + $reader->xml($input); + + $reader->parse(); + } + + /** + * @depends testMappedElement + */ + function testMappedElementCallBack() { + + $input = << + + + +BLA; + + $reader = new Reader(); + $reader->elementMap = [ + '{http://sabredav.org/ns}elem1' => function(Reader $reader) { + $reader->next(); + return 'foobar'; + } + ]; + $reader->xml($input); + + $output = $reader->parse(); + + $expected = [ + 'name' => '{http://sabredav.org/ns}root', + 'value' => [ + [ + 'name' => '{http://sabredav.org/ns}elem1', + 'value' => 'foobar', + 'attributes' => [], + ], + ], + 'attributes' => [], + + ]; + + $this->assertEquals($expected, $output); + + } + + /** + * @depends testMappedElementCallBack + */ + function testMappedElementCallBackNoNamespace() { + + $input = << + + + +BLA; + + $reader = new Reader(); + $reader->elementMap = [ + 'elem1' => function(Reader $reader) { + $reader->next(); + return 'foobar'; + } + ]; + $reader->xml($input); + + $output = $reader->parse(); + + $expected = [ + 'name' => '{}root', + 'value' => [ + [ + 'name' => '{}elem1', + 'value' => 'foobar', + 'attributes' => [], + ], + ], + 'attributes' => [], + + ]; + + $this->assertEquals($expected, $output); + + } + + /** + * @depends testMappedElementCallBack + */ + function testReadText() { + + $input = << + + + hello + world + + +BLA; + + $reader = new Reader(); + $reader->elementMap = [ + '{http://sabredav.org/ns}elem1' => function(Reader $reader) { + return $reader->readText(); + } + ]; + $reader->xml($input); + + $output = $reader->parse(); + + $expected = [ + 'name' => '{http://sabredav.org/ns}root', + 'value' => [ + [ + 'name' => '{http://sabredav.org/ns}elem1', + 'value' => 'hello world', + 'attributes' => [], + ], + ], + 'attributes' => [], + + ]; + + $this->assertEquals($expected, $output); + + } + + function testParseProblem() { + + $input = << + +BLA; + + $reader = new Reader(); + $reader->elementMap = [ + '{http://sabredav.org/ns}elem1' => 'Sabre\\Xml\\Element\\Mock' + ]; + $reader->xml($input); + + try { + $output = $reader->parse(); + $this->fail('We expected a ParseException to be thrown'); + } catch (LibXMLException $e) { + + $this->assertInternalType('array', $e->getErrors()); + + } + + } + + /** + * @expectedException \Sabre\Xml\ParseException + */ + function testBrokenParserClass() { + + $input = << + + + +BLA; + + $reader = new Reader(); + $reader->elementMap = [ + '{http://sabredav.org/ns}elem1' => 'Sabre\\Xml\\Element\\Eater' + ]; + $reader->xml($input); + $reader->parse(); + + + } + + /** + * Test was added for Issue #10. + * + * @expectedException Sabre\Xml\LibXMLException + */ + function testBrokenXml() { + + $input = << + + + +BLA; + + $reader = new Reader(); + $reader->xml($input); + $reader->parse(); + + } + + /** + * Test was added for Issue #45. + * + * @expectedException Sabre\Xml\LibXMLException + */ + function testBrokenXml2() { + + $input = << + + + + + + ""Administrative w"> + + + + xml($input); + $reader->parse(); + + } + + + /** + * @depends testMappedElement + */ + function testParseInnerTree() { + + $input = << + + + + + +BLA; + + $reader = new Reader(); + $reader->elementMap = [ + '{http://sabredav.org/ns}elem1' => function(Reader $reader) { + + $innerTree = $reader->parseInnerTree(['{http://sabredav.org/ns}elem1' => function(Reader $reader) { + $reader->next(); + return "foobar"; + }]); + + return $innerTree; + } + ]; + $reader->xml($input); + + $output = $reader->parse(); + + $expected = [ + 'name' => '{http://sabredav.org/ns}root', + 'value' => [ + [ + 'name' => '{http://sabredav.org/ns}elem1', + 'value' => [ + [ + 'name' => '{http://sabredav.org/ns}elem1', + 'value' => 'foobar', + 'attributes' => [], + ] + ], + 'attributes' => [], + ], + ], + 'attributes' => [], + + ]; + + $this->assertEquals($expected, $output); + + } + + /** + * @depends testParseInnerTree + */ + function testParseGetElements() { + + $input = << + + + + + +BLA; + + $reader = new Reader(); + $reader->elementMap = [ + '{http://sabredav.org/ns}elem1' => function(Reader $reader) { + + $innerTree = $reader->parseGetElements(['{http://sabredav.org/ns}elem1' => function(Reader $reader) { + $reader->next(); + return "foobar"; + }]); + + return $innerTree; + } + ]; + $reader->xml($input); + + $output = $reader->parse(); + + $expected = [ + 'name' => '{http://sabredav.org/ns}root', + 'value' => [ + [ + 'name' => '{http://sabredav.org/ns}elem1', + 'value' => [ + [ + 'name' => '{http://sabredav.org/ns}elem1', + 'value' => 'foobar', + 'attributes' => [], + ] + ], + 'attributes' => [], + ], + ], + 'attributes' => [], + + ]; + + $this->assertEquals($expected, $output); + + } + + /** + * @depends testParseInnerTree + */ + function testParseGetElementsNoElements() { + + $input = << + + + hi + + +BLA; + + $reader = new Reader(); + $reader->elementMap = [ + '{http://sabredav.org/ns}elem1' => function(Reader $reader) { + + $innerTree = $reader->parseGetElements(['{http://sabredav.org/ns}elem1' => function(Reader $reader) { + $reader->next(); + return "foobar"; + }]); + + return $innerTree; + } + ]; + $reader->xml($input); + + $output = $reader->parse(); + + $expected = [ + 'name' => '{http://sabredav.org/ns}root', + 'value' => [ + [ + 'name' => '{http://sabredav.org/ns}elem1', + 'value' => [], + 'attributes' => [], + ], + ], + 'attributes' => [], + + ]; + + $this->assertEquals($expected, $output); + + } + + +} diff --git a/vendor/sabre/xml/tests/Sabre/Xml/Serializer/EnumTest.php b/vendor/sabre/xml/tests/Sabre/Xml/Serializer/EnumTest.php new file mode 100644 index 000000000..2d26e665a --- /dev/null +++ b/vendor/sabre/xml/tests/Sabre/Xml/Serializer/EnumTest.php @@ -0,0 +1,36 @@ +namespaceMap['urn:test'] = null; + + $xml = $service->write('{urn:test}root', function($writer) { + enum($writer, [ + '{urn:test}foo1', + '{urn:test}foo2', + ]); + }); + + $expected = << + + + + +XML; + + + $this->assertXmlStringEqualsXmlString($expected, $xml); + + + } + + +} diff --git a/vendor/sabre/xml/tests/Sabre/Xml/Serializer/RepeatingElementsTest.php b/vendor/sabre/xml/tests/Sabre/Xml/Serializer/RepeatingElementsTest.php new file mode 100644 index 000000000..dbca65a57 --- /dev/null +++ b/vendor/sabre/xml/tests/Sabre/Xml/Serializer/RepeatingElementsTest.php @@ -0,0 +1,35 @@ +namespaceMap['urn:test'] = null; + $xml = $service->write('{urn:test}collection', function($writer) { + repeatingElements($writer, [ + 'foo', + 'bar', + ], '{urn:test}item'); + }); + + $expected = << + + foo + bar + +XML; + + + $this->assertXmlStringEqualsXmlString($expected, $xml); + + + } + + +} diff --git a/vendor/sabre/xml/tests/Sabre/Xml/ServiceTest.php b/vendor/sabre/xml/tests/Sabre/Xml/ServiceTest.php new file mode 100644 index 000000000..b03d680a2 --- /dev/null +++ b/vendor/sabre/xml/tests/Sabre/Xml/ServiceTest.php @@ -0,0 +1,409 @@ + 'Test!', + ]; + + $util = new Service(); + $util->elementMap = $elems; + + $reader = $util->getReader(); + $this->assertInstanceOf('Sabre\\Xml\\Reader', $reader); + $this->assertEquals($elems, $reader->elementMap); + + } + + function testGetWriter() { + + $ns = [ + 'http://sabre.io/ns' => 's', + ]; + + $util = new Service(); + $util->namespaceMap = $ns; + + $writer = $util->getWriter(); + $this->assertInstanceOf('Sabre\\Xml\\Writer', $writer); + $this->assertEquals($ns, $writer->namespaceMap); + + } + + /** + * @depends testGetReader + */ + function testParse() { + + $xml = << + value + +XML; + $util = new Service(); + $result = $util->parse($xml, null, $rootElement); + $this->assertEquals('{http://sabre.io/ns}root', $rootElement); + + $expected = [ + [ + 'name' => '{http://sabre.io/ns}child', + 'value' => 'value', + 'attributes' => [], + ] + ]; + + $this->assertEquals( + $expected, + $result + ); + + } + + /** + * @depends testGetReader + */ + function testParseStream() { + + $xml = << + value + +XML; + $stream = fopen('php://memory', 'r+'); + fwrite($stream, $xml); + rewind($stream); + + $util = new Service(); + $result = $util->parse($stream, null, $rootElement); + $this->assertEquals('{http://sabre.io/ns}root', $rootElement); + + $expected = [ + [ + 'name' => '{http://sabre.io/ns}child', + 'value' => 'value', + 'attributes' => [], + ] + ]; + + $this->assertEquals( + $expected, + $result + ); + + } + + /** + * @depends testGetReader + */ + function testExpect() { + + $xml = << + value + +XML; + $util = new Service(); + $result = $util->expect('{http://sabre.io/ns}root', $xml); + + $expected = [ + [ + 'name' => '{http://sabre.io/ns}child', + 'value' => 'value', + 'attributes' => [], + ] + ]; + + $this->assertEquals( + $expected, + $result + ); + } + + /** + * @expectedException \Sabre\Xml\LibXMLException + */ + function testInvalidNameSpace() + { + $xml = ''; + + $util = new Service(); + $util->elementMap = [ + '{DAV:}propfind' => PropFindTestAsset::class, + ]; + $util->namespaceMap = [ + 'http://sabre.io/ns' => 's', + ]; + $result = $util->expect('{DAV:}propfind', $xml); + } + + /** + * @dataProvider providesEmptyPropfinds + */ + function testEmptyPropfind($xml) + { + $util = new Service(); + $util->elementMap = [ + '{DAV:}propfind' => PropFindTestAsset::class, + ]; + $util->namespaceMap = [ + 'http://sabre.io/ns' => 's', + ]; + $result = $util->expect('{DAV:}propfind', $xml); + $this->assertEquals(false, $result->allProp); + $this->assertEquals([], $result->properties); + } + + /** + * @depends testGetReader + */ + function testExpectStream() { + + $xml = << + value + +XML; + + $stream = fopen('php://memory', 'r+'); + fwrite($stream, $xml); + rewind($stream); + + $util = new Service(); + $result = $util->expect('{http://sabre.io/ns}root', $stream); + + $expected = [ + [ + 'name' => '{http://sabre.io/ns}child', + 'value' => 'value', + 'attributes' => [], + ] + ]; + + $this->assertEquals( + $expected, + $result + ); + } + + /** + * @depends testGetReader + * @expectedException \Sabre\Xml\ParseException + */ + function testExpectWrong() { + + $xml = << + value + +XML; + $util = new Service(); + $util->expect('{http://sabre.io/ns}error', $xml); + + } + + /** + * @depends testGetWriter + */ + function testWrite() { + + $util = new Service(); + $util->namespaceMap = [ + 'http://sabre.io/ns' => 's', + ]; + $result = $util->write('{http://sabre.io/ns}root', [ + '{http://sabre.io/ns}child' => 'value', + ]); + + $expected = << + + value + + +XML; + $this->assertEquals( + $expected, + $result + ); + + } + + function testMapValueObject() { + + $input = << + + 1234 + 99.99 + black friday deal + + 5 + + + + +XML; + + $ns = 'http://sabredav.org/ns'; + $orderService = new \Sabre\Xml\Service(); + $orderService->mapValueObject('{' . $ns . '}order', 'Sabre\Xml\Order'); + $orderService->mapValueObject('{' . $ns . '}status', 'Sabre\Xml\OrderStatus'); + $orderService->namespaceMap[$ns] = null; + + $order = $orderService->parse($input); + $expected = new Order(); + $expected->id = 1234; + $expected->amount = 99.99; + $expected->description = 'black friday deal'; + $expected->status = new OrderStatus(); + $expected->status->id = 5; + $expected->status->label = 'processed'; + + $this->assertEquals($expected, $order); + + $writtenXml = $orderService->writeValueObject($order); + $this->assertEquals($input, $writtenXml); + } + + function testMapValueObjectArrayProperty() { + + $input = << + + 1234 + 99.99 + black friday deal + + 5 + + + http://example.org/ + http://example.com/ + + +XML; + + $ns = 'http://sabredav.org/ns'; + $orderService = new \Sabre\Xml\Service(); + $orderService->mapValueObject('{' . $ns . '}order', 'Sabre\Xml\Order'); + $orderService->mapValueObject('{' . $ns . '}status', 'Sabre\Xml\OrderStatus'); + $orderService->namespaceMap[$ns] = null; + + $order = $orderService->parse($input); + $expected = new Order(); + $expected->id = 1234; + $expected->amount = 99.99; + $expected->description = 'black friday deal'; + $expected->status = new OrderStatus(); + $expected->status->id = 5; + $expected->status->label = 'processed'; + $expected->link = ['http://example.org/', 'http://example.com/']; + + $this->assertEquals($expected, $order); + + $writtenXml = $orderService->writeValueObject($order); + $this->assertEquals($input, $writtenXml); + } + + /** + * @expectedException \InvalidArgumentException + */ + function testWriteVoNotFound() { + + $service = new Service(); + $service->writeValueObject(new \StdClass()); + + } + + function testParseClarkNotation() { + + $this->assertEquals([ + 'http://sabredav.org/ns', + 'elem', + ], Service::parseClarkNotation('{http://sabredav.org/ns}elem')); + + } + + /** + * @expectedException \InvalidArgumentException + */ + function testParseClarkNotationFail() { + + Service::parseClarkNotation('http://sabredav.org/ns}elem'); + + } + + function providesEmptyPropfinds() + { + return [ + [''], + [''], + [''], + [''], + [' '], + ]; + } +} + +/** + * asset for testMapValueObject() + * @internal + */ +class Order { + public $id; + public $amount; + public $description; + public $status; + public $empty; + public $link = []; +} + +/** + * asset for testMapValueObject() + * @internal + */ +class OrderStatus { + public $id; + public $label; +} + + +/** + * asset for testInvalidNameSpace. + * + * @internal + */ +class PropFindTestAsset implements XmlDeserializable +{ + public $allProp = false; + + public $properties; + + static function xmlDeserialize(Reader $reader) + { + $self = new self(); + + $reader->pushContext(); + $reader->elementMap['{DAV:}prop'] = 'Sabre\Xml\Element\Elements'; + + foreach (KeyValue::xmlDeserialize($reader) as $k => $v) { + switch ($k) { + case '{DAV:}prop': + $self->properties = $v; + break; + case '{DAV:}allprop': + $self->allProp = true; + } + } + + $reader->popContext(); + + return $self; + } +} diff --git a/vendor/sabre/xml/tests/Sabre/Xml/WriterTest.php b/vendor/sabre/xml/tests/Sabre/Xml/WriterTest.php new file mode 100644 index 000000000..574d80237 --- /dev/null +++ b/vendor/sabre/xml/tests/Sabre/Xml/WriterTest.php @@ -0,0 +1,439 @@ +writer = new Writer(); + $this->writer->namespaceMap = [ + 'http://sabredav.org/ns' => 's', + ]; + $this->writer->openMemory(); + $this->writer->setIndent(true); + $this->writer->startDocument(); + + } + + function compare($input, $output) { + + $this->writer->write($input); + $this->assertEquals($output, $this->writer->outputMemory()); + + } + + + function testSimple() { + + $this->compare([ + '{http://sabredav.org/ns}root' => 'text', + ], << +text + +HI + ); + + } + + /** + * @depends testSimple + */ + function testSimpleQuotes() { + + $this->compare([ + '{http://sabredav.org/ns}root' => '"text"', + ], << +"text" + +HI + ); + + } + + function testSimpleAttributes() { + + $this->compare([ + '{http://sabredav.org/ns}root' => [ + 'value' => 'text', + 'attributes' => [ + 'attr1' => 'attribute value', + ], + ], + ], << +text + +HI + ); + + } + function testMixedSyntax() { + $this->compare([ + '{http://sabredav.org/ns}root' => [ + '{http://sabredav.org/ns}single' => 'value', + '{http://sabredav.org/ns}multiple' => [ + [ + 'name' => '{http://sabredav.org/ns}foo', + 'value' => 'bar', + ], + [ + 'name' => '{http://sabredav.org/ns}foo', + 'value' => 'foobar', + ], + ], + [ + 'name' => '{http://sabredav.org/ns}attributes', + 'value' => null, + 'attributes' => [ + 'foo' => 'bar', + ], + ], + [ + 'name' => '{http://sabredav.org/ns}verbose', + 'value' => 'syntax', + 'attributes' => [ + 'foo' => 'bar', + ], + ], + ], + ], << + + value + + bar + foobar + + + syntax + + +HI + ); + } + + function testNull() { + + $this->compare([ + '{http://sabredav.org/ns}root' => null, + ], << + + +HI + ); + + } + + function testArrayFormat2() { + + $this->compare([ + '{http://sabredav.org/ns}root' => [ + [ + 'name' => '{http://sabredav.org/ns}elem1', + 'value' => 'text', + 'attributes' => [ + 'attr1' => 'attribute value', + ], + ], + ], + ], << + + text + + +HI + ); + + } + + function testArrayOfValues() { + + $this->compare([ + '{http://sabredav.org/ns}root' => [ + [ + 'name' => '{http://sabredav.org/ns}elem1', + 'value' => [ + 'foo', + 'bar', + 'baz', + ], + ], + ], + ], << + + foobarbaz + + +HI + ); + + } + + /** + * @depends testArrayFormat2 + */ + function testArrayFormat2NoValue() { + + $this->compare([ + '{http://sabredav.org/ns}root' => [ + [ + 'name' => '{http://sabredav.org/ns}elem1', + 'attributes' => [ + 'attr1' => 'attribute value', + ], + ], + ], + ], << + + + + +HI + ); + + } + + function testCustomNamespace() { + + $this->compare([ + '{http://sabredav.org/ns}root' => [ + '{urn:foo}elem1' => 'bar', + ], + ], << + + bar + + +HI + ); + + } + + function testEmptyNamespace() { + + // Empty namespaces are allowed, so we should support this. + $this->compare([ + '{http://sabredav.org/ns}root' => [ + '{}elem1' => 'bar', + ], + ], << + + bar + + +HI + ); + + } + + function testAttributes() { + + $this->compare([ + '{http://sabredav.org/ns}root' => [ + [ + 'name' => '{http://sabredav.org/ns}elem1', + 'value' => 'text', + 'attributes' => [ + 'attr1' => 'val1', + '{http://sabredav.org/ns}attr2' => 'val2', + '{urn:foo}attr3' => 'val3', + ], + ], + ], + ], << + + text + + +HI + ); + + } + + function testBaseElement() { + + $this->compare([ + '{http://sabredav.org/ns}root' => new Element\Base('hello') + ], << +hello + +HI + ); + + } + + function testElementObj() { + + $this->compare([ + '{http://sabredav.org/ns}root' => new Element\Mock() + ], << + + hiiii! + + +HI + ); + + } + + function testEmptyNamespacePrefix() { + + $this->writer->namespaceMap['http://sabredav.org/ns'] = null; + $this->compare([ + '{http://sabredav.org/ns}root' => new Element\Mock() + ], << + + hiiii! + + +HI + ); + + } + + function testEmptyNamespacePrefixEmptyString() { + + $this->writer->namespaceMap['http://sabredav.org/ns'] = ''; + $this->compare([ + '{http://sabredav.org/ns}root' => new Element\Mock() + ], << + + hiiii! + + +HI + ); + + } + + function testWriteElement() { + + $this->writer->writeElement("{http://sabredav.org/ns}foo", 'content'); + + $output = << +content + +HI; + + $this->assertEquals($output, $this->writer->outputMemory()); + + + } + + function testWriteElementComplex() { + + $this->writer->writeElement("{http://sabredav.org/ns}foo", new Element\KeyValue(['{http://sabredav.org/ns}bar' => 'test'])); + + $output = << + + test + + +HI; + + $this->assertEquals($output, $this->writer->outputMemory()); + + } + + /** + * @expectedException \InvalidArgumentException + */ + function testWriteBadObject() { + + $this->writer->write(new \StdClass()); + + } + + function testStartElementSimple() { + + $this->writer->startElement("foo"); + $this->writer->endElement(); + + $output = << + + +HI; + + $this->assertEquals($output, $this->writer->outputMemory()); + + } + + function testCallback() { + + $this->compare([ + '{http://sabredav.org/ns}root' => function(Writer $writer) { + $writer->text('deferred writer'); + }, + ], << +deferred writer + +HI + ); + + } + + /** + * @expectedException \InvalidArgumentException + */ + function testResource() { + + $this->compare([ + '{http://sabredav.org/ns}root' => fopen('php://memory', 'r'), + ], << +deferred writer + +HI + ); + + } + + function testClassMap() { + + $obj = (object)[ + 'key1' => 'value1', + 'key2' => 'value2', + ]; + + $this->writer->classMap['stdClass'] = function(Writer $writer, $value) { + + foreach (get_object_vars($value) as $key => $val) { + $writer->writeElement('{http://sabredav.org/ns}' . $key, $val); + } + + }; + + $this->compare([ + '{http://sabredav.org/ns}root' => $obj + ], << + + value1 + value2 + + +HI + ); + + } +} diff --git a/vendor/sabre/xml/tests/phpcs/ruleset.xml b/vendor/sabre/xml/tests/phpcs/ruleset.xml new file mode 100644 index 000000000..07acb89ee --- /dev/null +++ b/vendor/sabre/xml/tests/phpcs/ruleset.xml @@ -0,0 +1,56 @@ + + + sabre.io codesniffer ruleset + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/sabre/xml/tests/phpunit.xml.dist b/vendor/sabre/xml/tests/phpunit.xml.dist new file mode 100644 index 000000000..fe8b2359a --- /dev/null +++ b/vendor/sabre/xml/tests/phpunit.xml.dist @@ -0,0 +1,17 @@ + + + Sabre/ + + + + + ../lib/ + + + diff --git a/vendor/smarty/smarty/composer.json b/vendor/smarty/smarty/composer.json new file mode 100644 index 000000000..183f9f240 --- /dev/null +++ b/vendor/smarty/smarty/composer.json @@ -0,0 +1,46 @@ +{ + "name": "smarty/smarty", + "type": "library", + "description": "Smarty - the compiling PHP template engine", + "keywords": [ + "templating" + ], + "homepage": "http://www.smarty.net", + "license": "LGPL-3.0", + "authors": [ + { + "name": "Monte Ohrt", + "email": "monte@ohrt.com" + }, + { + "name": "Uwe Tews", + "email": "uwe.tews@googlemail.com" + }, + { + "name": "Rodney Rehm", + "email": "rodney.rehm@medialize.de" + } + ], + "support": { + "irc": "irc://irc.freenode.org/smarty", + "issues": "https://github.com/smarty-php/smarty/issues", + "forum": "http://www.smarty.net/forums/" + }, + "require": { + "php": ">=5.2" + }, + "autoload": { + "classmap": [ + "libs/" + ] + }, + "extra": { + "branch-alias": { + "dev-master": "3.1.x-dev" + } + }, + "require-dev": { + "phpunit/phpunit": "^7.5 || ^6.5 || ^5.7 || ^4.8", + "smarty/smarty-lexer": "^3.1" + } +} diff --git a/vendor/swiss-payment-slip/swiss-payment-slip-fpdf/composer.json b/vendor/swiss-payment-slip/swiss-payment-slip-fpdf/composer.json new file mode 100644 index 000000000..ebb6db0fd --- /dev/null +++ b/vendor/swiss-payment-slip/swiss-payment-slip-fpdf/composer.json @@ -0,0 +1,59 @@ +{ + "name": "swiss-payment-slip/swiss-payment-slip-fpdf", + "description": "Create Swiss payment slips with reference number (ESR) or without (ES) as PDFs with FPDF", + "license": "MIT", + "homepage": "https://github.com/ravage84/SwissPaymentSlipFpdf", + "keywords": [ + "Payment slip", + "Inpayment slip", + "Einzahlungsschein", + "ESR", + "ES", + "PDF", + "FPDF" + ], + "require": { + "php": ">=5.3.0", + "itbz/fpdf": "1.7.*", + "swiss-payment-slip/swiss-payment-slip-pdf": "0.13.*" + }, + "require-dev": { + "phpunit/phpunit": "3.7.38", + "squizlabs/php_codesniffer": "2.1.*" + }, + "authors": [ + { + "name": "Marc Würth", + "email": "ravage@bluewin.ch", + "homepage": "https://github.com/ravage84", + "role": "Lead developer" + }, + { + "name": "Manuel Reinhard", + "email": "manu@sprain.ch", + "homepage": "http://www.sprain.ch", + "role": "Developer of the original class" + }, + { + "name": "Peter Siska", + "email": "pesche@gridonic.ch", + "homepage": "http://www.gridonic.ch", + "role": "Contributor" + } + ], + "support": { + "email": "ravage@bluewin.ch", + "issues": "https://github.com/ravage84/SwissPaymentSlipFpdf/issues", + "source": "https://github.com/ravage84/SwissPaymentSlipFpdf" + }, + "autoload": { + "psr-4": { + "SwissPaymentSlip\\SwissPaymentSlipFpdf\\": "src" + } + }, + "autoload-dev": { + "psr-4": { + "SwissPaymentSlip\\SwissPaymentSlipFpdf\\Tests\\": "tests" + } + } +} diff --git a/vendor/swiss-payment-slip/swiss-payment-slip-fpdf/composer.lock b/vendor/swiss-payment-slip/swiss-payment-slip-fpdf/composer.lock new file mode 100644 index 000000000..6726adf57 --- /dev/null +++ b/vendor/swiss-payment-slip/swiss-payment-slip-fpdf/composer.lock @@ -0,0 +1,665 @@ +{ + "_readme": [ + "This file locks the dependencies of your project to a known state", + "Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", + "This file is @generated automatically" + ], + "hash": "0b94b5a6096f2297fed48eaef6b7eb86", + "packages": [ + { + "name": "itbz/fpdf", + "version": "1.7.2", + "source": { + "type": "git", + "url": "https://github.com/hanneskod/fpdf.git", + "reference": "06d02a7bf227a62d37691a4e7e9c3a35efcb41c3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/hanneskod/fpdf/zipball/06d02a7bf227a62d37691a4e7e9c3a35efcb41c3", + "reference": "06d02a7bf227a62d37691a4e7e9c3a35efcb41c3", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "autoload": { + "psr-0": { + "fpdf": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "no usage restriction" + ], + "description": "Unofficial PSR-0 compliant version of the FPDF library", + "homepage": "http://www.fpdf.org/", + "time": "2013-12-27 14:18:15" + }, + { + "name": "swiss-payment-slip/swiss-payment-slip", + "version": "0.11.1", + "source": { + "type": "git", + "url": "https://github.com/ravage84/SwissPaymentSlip.git", + "reference": "a30d5b62db1a8f7048e63302bf639f64a4e9790a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ravage84/SwissPaymentSlip/zipball/a30d5b62db1a8f7048e63302bf639f64a4e9790a", + "reference": "a30d5b62db1a8f7048e63302bf639f64a4e9790a", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "require-dev": { + "phpunit/phpunit": "3.7.38", + "squizlabs/php_codesniffer": "2.1.*" + }, + "type": "library", + "autoload": { + "psr-4": { + "SwissPaymentSlip\\SwissPaymentSlip\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Peter Siska", + "email": "pesche@gridonic.ch", + "homepage": "http://www.gridonic.ch", + "role": "Contributor" + }, + { + "name": "Manuel Reinhard", + "email": "manu@sprain.ch", + "homepage": "http://www.sprain.ch", + "role": "Developer of the original class" + }, + { + "name": "Marc Würth", + "email": "ravage@bluewin.ch", + "role": "Lead developer" + } + ], + "description": "A library for creating Swiss payment slips", + "homepage": "https://github.com/ravage84/SwissPaymentSlip", + "keywords": [ + "ESR", + "Einzahlungsschein", + "Inpayment slip", + "Payment slip", + "es" + ], + "time": "2015-02-18 19:51:56" + }, + { + "name": "swiss-payment-slip/swiss-payment-slip-pdf", + "version": "0.13.1", + "source": { + "type": "git", + "url": "https://github.com/ravage84/SwissPaymentSlipPdf.git", + "reference": "4355743b2406875e9fed2117d8df445ba6848be4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ravage84/SwissPaymentSlipPdf/zipball/4355743b2406875e9fed2117d8df445ba6848be4", + "reference": "4355743b2406875e9fed2117d8df445ba6848be4", + "shasum": "" + }, + "require": { + "php": ">=5.3.0", + "swiss-payment-slip/swiss-payment-slip": "0.11.1" + }, + "require-dev": { + "phpunit/phpunit": "3.7.38", + "squizlabs/php_codesniffer": "2.1.*" + }, + "type": "library", + "autoload": { + "psr-4": { + "SwissPaymentSlip\\SwissPaymentSlipPdf\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Peter Siska", + "email": "pesche@gridonic.ch", + "homepage": "http://www.gridonic.ch", + "role": "Contributor" + }, + { + "name": "Manuel Reinhard", + "email": "manu@sprain.ch", + "homepage": "http://www.sprain.ch", + "role": "Developer of the original class" + }, + { + "name": "Marc Würth", + "email": "ravage@bluewin.ch", + "role": "Lead developer" + } + ], + "description": "An abstract base class for creating Swiss payment slips with reference number (ESR) or without (ES) using a pdf engine", + "homepage": "https://github.com/ravage84/SwissPaymentSlipPdf", + "keywords": [ + "ESR", + "Einzahlungsschein", + "Inpayment slip", + "Payment slip", + "es", + "pdf" + ], + "time": "2015-02-18 20:04:44" + } + ], + "packages-dev": [ + { + "name": "phpunit/php-code-coverage", + "version": "1.2.18", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-code-coverage.git", + "reference": "fe2466802556d3fe4e4d1d58ffd3ccfd0a19be0b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/fe2466802556d3fe4e4d1d58ffd3ccfd0a19be0b", + "reference": "fe2466802556d3fe4e4d1d58ffd3ccfd0a19be0b", + "shasum": "" + }, + "require": { + "php": ">=5.3.3", + "phpunit/php-file-iterator": ">=1.3.0@stable", + "phpunit/php-text-template": ">=1.2.0@stable", + "phpunit/php-token-stream": ">=1.1.3,<1.3.0" + }, + "require-dev": { + "phpunit/phpunit": "3.7.*@dev" + }, + "suggest": { + "ext-dom": "*", + "ext-xdebug": ">=2.0.5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.2.x-dev" + } + }, + "autoload": { + "classmap": [ + "PHP/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "include-path": [ + "" + ], + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.", + "homepage": "https://github.com/sebastianbergmann/php-code-coverage", + "keywords": [ + "coverage", + "testing", + "xunit" + ], + "time": "2014-09-02 10:13:14" + }, + { + "name": "phpunit/php-file-iterator", + "version": "1.3.4", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-file-iterator.git", + "reference": "acd690379117b042d1c8af1fafd61bde001bf6bb" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/acd690379117b042d1c8af1fafd61bde001bf6bb", + "reference": "acd690379117b042d1c8af1fafd61bde001bf6bb", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "autoload": { + "classmap": [ + "File/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "include-path": [ + "" + ], + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "FilterIterator implementation that filters files based on a list of suffixes.", + "homepage": "https://github.com/sebastianbergmann/php-file-iterator/", + "keywords": [ + "filesystem", + "iterator" + ], + "time": "2013-10-10 15:34:57" + }, + { + "name": "phpunit/php-text-template", + "version": "1.2.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-text-template.git", + "reference": "206dfefc0ffe9cebf65c413e3d0e809c82fbf00a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/206dfefc0ffe9cebf65c413e3d0e809c82fbf00a", + "reference": "206dfefc0ffe9cebf65c413e3d0e809c82fbf00a", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "autoload": { + "classmap": [ + "Text/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "include-path": [ + "" + ], + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "Simple template engine.", + "homepage": "https://github.com/sebastianbergmann/php-text-template/", + "keywords": [ + "template" + ], + "time": "2014-01-30 17:20:04" + }, + { + "name": "phpunit/php-timer", + "version": "1.0.5", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-timer.git", + "reference": "19689d4354b295ee3d8c54b4f42c3efb69cbc17c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/19689d4354b295ee3d8c54b4f42c3efb69cbc17c", + "reference": "19689d4354b295ee3d8c54b4f42c3efb69cbc17c", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "autoload": { + "classmap": [ + "PHP/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "include-path": [ + "" + ], + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "Utility class for timing", + "homepage": "https://github.com/sebastianbergmann/php-timer/", + "keywords": [ + "timer" + ], + "time": "2013-08-02 07:42:54" + }, + { + "name": "phpunit/php-token-stream", + "version": "1.2.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-token-stream.git", + "reference": "ad4e1e23ae01b483c16f600ff1bebec184588e32" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/ad4e1e23ae01b483c16f600ff1bebec184588e32", + "reference": "ad4e1e23ae01b483c16f600ff1bebec184588e32", + "shasum": "" + }, + "require": { + "ext-tokenizer": "*", + "php": ">=5.3.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.2-dev" + } + }, + "autoload": { + "classmap": [ + "PHP/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "include-path": [ + "" + ], + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "Wrapper around PHP's tokenizer extension.", + "homepage": "https://github.com/sebastianbergmann/php-token-stream/", + "keywords": [ + "tokenizer" + ], + "time": "2014-03-03 05:10:30" + }, + { + "name": "phpunit/phpunit", + "version": "3.7.38", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/phpunit.git", + "reference": "38709dc22d519a3d1be46849868aa2ddf822bcf6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/38709dc22d519a3d1be46849868aa2ddf822bcf6", + "reference": "38709dc22d519a3d1be46849868aa2ddf822bcf6", + "shasum": "" + }, + "require": { + "ext-ctype": "*", + "ext-dom": "*", + "ext-json": "*", + "ext-pcre": "*", + "ext-reflection": "*", + "ext-spl": "*", + "php": ">=5.3.3", + "phpunit/php-code-coverage": "~1.2", + "phpunit/php-file-iterator": "~1.3", + "phpunit/php-text-template": "~1.1", + "phpunit/php-timer": "~1.0", + "phpunit/phpunit-mock-objects": "~1.2", + "symfony/yaml": "~2.0" + }, + "require-dev": { + "pear-pear.php.net/pear": "1.9.4" + }, + "suggest": { + "phpunit/php-invoker": "~1.1" + }, + "bin": [ + "composer/bin/phpunit" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.7.x-dev" + } + }, + "autoload": { + "classmap": [ + "PHPUnit/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "include-path": [ + "", + "../../symfony/yaml/" + ], + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "The PHP Unit Testing framework.", + "homepage": "http://www.phpunit.de/", + "keywords": [ + "phpunit", + "testing", + "xunit" + ], + "time": "2014-10-17 09:04:17" + }, + { + "name": "phpunit/phpunit-mock-objects", + "version": "1.2.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git", + "reference": "5794e3c5c5ba0fb037b11d8151add2a07fa82875" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/5794e3c5c5ba0fb037b11d8151add2a07fa82875", + "reference": "5794e3c5c5ba0fb037b11d8151add2a07fa82875", + "shasum": "" + }, + "require": { + "php": ">=5.3.3", + "phpunit/php-text-template": ">=1.1.1@stable" + }, + "suggest": { + "ext-soap": "*" + }, + "type": "library", + "autoload": { + "classmap": [ + "PHPUnit/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "include-path": [ + "" + ], + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "Mock Object library for PHPUnit", + "homepage": "https://github.com/sebastianbergmann/phpunit-mock-objects/", + "keywords": [ + "mock", + "xunit" + ], + "time": "2013-01-13 10:24:48" + }, + { + "name": "squizlabs/php_codesniffer", + "version": "2.1.0", + "source": { + "type": "git", + "url": "https://github.com/squizlabs/PHP_CodeSniffer.git", + "reference": "d2a1d4c58fd2bb09ba376d0d19e67c0ab649e401" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/d2a1d4c58fd2bb09ba376d0d19e67c0ab649e401", + "reference": "d2a1d4c58fd2bb09ba376d0d19e67c0ab649e401", + "shasum": "" + }, + "require": { + "ext-tokenizer": "*", + "php": ">=5.1.2" + }, + "bin": [ + "scripts/phpcs", + "scripts/phpcbf" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-phpcs-fixer": "2.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "CodeSniffer.php", + "CodeSniffer/CLI.php", + "CodeSniffer/Exception.php", + "CodeSniffer/File.php", + "CodeSniffer/Fixer.php", + "CodeSniffer/Report.php", + "CodeSniffer/Reporting.php", + "CodeSniffer/Sniff.php", + "CodeSniffer/Tokens.php", + "CodeSniffer/Reports/", + "CodeSniffer/Tokenizers/", + "CodeSniffer/DocGenerators/", + "CodeSniffer/Standards/AbstractPatternSniff.php", + "CodeSniffer/Standards/AbstractScopeSniff.php", + "CodeSniffer/Standards/AbstractVariableSniff.php", + "CodeSniffer/Standards/IncorrectPatternException.php", + "CodeSniffer/Standards/Generic/Sniffs/", + "CodeSniffer/Standards/MySource/Sniffs/", + "CodeSniffer/Standards/PEAR/Sniffs/", + "CodeSniffer/Standards/PSR1/Sniffs/", + "CodeSniffer/Standards/PSR2/Sniffs/", + "CodeSniffer/Standards/Squiz/Sniffs/", + "CodeSniffer/Standards/Zend/Sniffs/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Greg Sherwood", + "role": "lead" + } + ], + "description": "PHP_CodeSniffer tokenises PHP, JavaScript and CSS files and detects violations of a defined set of coding standards.", + "homepage": "http://www.squizlabs.com/php-codesniffer", + "keywords": [ + "phpcs", + "standards" + ], + "time": "2014-12-18 02:37:51" + }, + { + "name": "symfony/yaml", + "version": "v2.6.5", + "target-dir": "Symfony/Component/Yaml", + "source": { + "type": "git", + "url": "https://github.com/symfony/Yaml.git", + "reference": "0cd8e72071e46e15fc072270ae39ea1b66b10a9d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/Yaml/zipball/0cd8e72071e46e15fc072270ae39ea1b66b10a9d", + "reference": "0cd8e72071e46e15fc072270ae39ea1b66b10a9d", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "symfony/phpunit-bridge": "~2.7" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.6-dev" + } + }, + "autoload": { + "psr-0": { + "Symfony\\Component\\Yaml\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Symfony Community", + "homepage": "http://symfony.com/contributors" + }, + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + } + ], + "description": "Symfony Yaml Component", + "homepage": "http://symfony.com", + "time": "2015-03-12 10:28:44" + } + ], + "aliases": [], + "minimum-stability": "stable", + "stability-flags": [], + "prefer-stable": false, + "prefer-lowest": false, + "platform": { + "php": ">=5.3.0" + }, + "platform-dev": [] +} diff --git a/vendor/swiss-payment-slip/swiss-payment-slip-pdf/composer.json b/vendor/swiss-payment-slip/swiss-payment-slip-pdf/composer.json new file mode 100644 index 000000000..aeb382f30 --- /dev/null +++ b/vendor/swiss-payment-slip/swiss-payment-slip-pdf/composer.json @@ -0,0 +1,57 @@ +{ + "name": "swiss-payment-slip/swiss-payment-slip-pdf", + "description": "An abstract base class for creating Swiss payment slips with reference number (ESR) or without (ES) using a pdf engine", + "license": "MIT", + "homepage": "https://github.com/ravage84/SwissPaymentSlipPdf", + "keywords": [ + "Payment slip", + "Inpayment slip", + "Einzahlungsschein", + "ESR", + "ES", + "PDF" + ], + "minimum-stability": "dev", + "require": { + "php": ">=5.3.0", + "swiss-payment-slip/swiss-payment-slip": "0.11.1" + }, + "require-dev": { + "phpunit/phpunit": "3.7.38", + "squizlabs/php_codesniffer": "2.1.*" + }, + "authors": [ + { + "name": "Marc Würth", + "email": "ravage@bluewin.ch", + "role": "Lead developer" + }, + { + "name": "Manuel Reinhard", + "email": "manu@sprain.ch", + "homepage": "http://www.sprain.ch", + "role": "Developer of the original class" + }, + { + "name": "Peter Siska", + "email": "pesche@gridonic.ch", + "homepage": "http://www.gridonic.ch", + "role": "Contributor" + } + ], + "support": { + "email": "ravage@bluewin.ch", + "issues": "https://github.com/ravage84/SwissPaymentSlipPdf/issues", + "source": "https://github.com/ravage84/SwissPaymentSlipPdf" + }, + "autoload": { + "psr-4": { + "SwissPaymentSlip\\SwissPaymentSlipPdf\\": "src" + } + }, + "autoload-dev": { + "psr-4": { + "SwissPaymentSlip\\SwissPaymentSlipPdf\\Tests\\": "tests" + } + } +} diff --git a/vendor/swiss-payment-slip/swiss-payment-slip-pdf/composer.lock b/vendor/swiss-payment-slip/swiss-payment-slip-pdf/composer.lock new file mode 100644 index 000000000..0f363dedc --- /dev/null +++ b/vendor/swiss-payment-slip/swiss-payment-slip-pdf/composer.lock @@ -0,0 +1,576 @@ +{ + "_readme": [ + "This file locks the dependencies of your project to a known state", + "Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", + "This file is @generated automatically" + ], + "hash": "fce0786af5209d8009d1f35fcdb7806f", + "packages": [ + { + "name": "swiss-payment-slip/swiss-payment-slip", + "version": "0.11.1", + "source": { + "type": "git", + "url": "https://github.com/ravage84/SwissPaymentSlip.git", + "reference": "a30d5b62db1a8f7048e63302bf639f64a4e9790a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ravage84/SwissPaymentSlip/zipball/a30d5b62db1a8f7048e63302bf639f64a4e9790a", + "reference": "a30d5b62db1a8f7048e63302bf639f64a4e9790a", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "require-dev": { + "phpunit/phpunit": "3.7.38", + "squizlabs/php_codesniffer": "2.1.*" + }, + "type": "library", + "autoload": { + "psr-4": { + "SwissPaymentSlip\\SwissPaymentSlip\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Peter Siska", + "email": "pesche@gridonic.ch", + "homepage": "http://www.gridonic.ch", + "role": "Contributor" + }, + { + "name": "Manuel Reinhard", + "email": "manu@sprain.ch", + "homepage": "http://www.sprain.ch", + "role": "Developer of the original class" + }, + { + "name": "Marc Würth", + "email": "ravage@bluewin.ch", + "role": "Lead developer" + } + ], + "description": "A library for creating Swiss payment slips", + "homepage": "https://github.com/ravage84/SwissPaymentSlip", + "keywords": [ + "ESR", + "Einzahlungsschein", + "Inpayment slip", + "Payment slip", + "es" + ], + "time": "2015-02-18 19:51:56" + } + ], + "packages-dev": [ + { + "name": "phpunit/php-code-coverage", + "version": "1.2.x-dev", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-code-coverage.git", + "reference": "fe2466802556d3fe4e4d1d58ffd3ccfd0a19be0b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/fe2466802556d3fe4e4d1d58ffd3ccfd0a19be0b", + "reference": "fe2466802556d3fe4e4d1d58ffd3ccfd0a19be0b", + "shasum": "" + }, + "require": { + "php": ">=5.3.3", + "phpunit/php-file-iterator": ">=1.3.0@stable", + "phpunit/php-text-template": ">=1.2.0@stable", + "phpunit/php-token-stream": ">=1.1.3,<1.3.0" + }, + "require-dev": { + "phpunit/phpunit": "3.7.*@dev" + }, + "suggest": { + "ext-dom": "*", + "ext-xdebug": ">=2.0.5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.2.x-dev" + } + }, + "autoload": { + "classmap": [ + "PHP/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "include-path": [ + "" + ], + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.", + "homepage": "https://github.com/sebastianbergmann/php-code-coverage", + "keywords": [ + "coverage", + "testing", + "xunit" + ], + "time": "2014-09-02 10:13:14" + }, + { + "name": "phpunit/php-file-iterator", + "version": "1.3.4", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-file-iterator.git", + "reference": "acd690379117b042d1c8af1fafd61bde001bf6bb" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/acd690379117b042d1c8af1fafd61bde001bf6bb", + "reference": "acd690379117b042d1c8af1fafd61bde001bf6bb", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "autoload": { + "classmap": [ + "File/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "include-path": [ + "" + ], + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "FilterIterator implementation that filters files based on a list of suffixes.", + "homepage": "https://github.com/sebastianbergmann/php-file-iterator/", + "keywords": [ + "filesystem", + "iterator" + ], + "time": "2013-10-10 15:34:57" + }, + { + "name": "phpunit/php-text-template", + "version": "1.2.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-text-template.git", + "reference": "206dfefc0ffe9cebf65c413e3d0e809c82fbf00a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/206dfefc0ffe9cebf65c413e3d0e809c82fbf00a", + "reference": "206dfefc0ffe9cebf65c413e3d0e809c82fbf00a", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "autoload": { + "classmap": [ + "Text/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "include-path": [ + "" + ], + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "Simple template engine.", + "homepage": "https://github.com/sebastianbergmann/php-text-template/", + "keywords": [ + "template" + ], + "time": "2014-01-30 17:20:04" + }, + { + "name": "phpunit/php-timer", + "version": "1.0.5", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-timer.git", + "reference": "19689d4354b295ee3d8c54b4f42c3efb69cbc17c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/19689d4354b295ee3d8c54b4f42c3efb69cbc17c", + "reference": "19689d4354b295ee3d8c54b4f42c3efb69cbc17c", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "autoload": { + "classmap": [ + "PHP/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "include-path": [ + "" + ], + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "Utility class for timing", + "homepage": "https://github.com/sebastianbergmann/php-timer/", + "keywords": [ + "timer" + ], + "time": "2013-08-02 07:42:54" + }, + { + "name": "phpunit/php-token-stream", + "version": "1.2.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-token-stream.git", + "reference": "ad4e1e23ae01b483c16f600ff1bebec184588e32" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/ad4e1e23ae01b483c16f600ff1bebec184588e32", + "reference": "ad4e1e23ae01b483c16f600ff1bebec184588e32", + "shasum": "" + }, + "require": { + "ext-tokenizer": "*", + "php": ">=5.3.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.2-dev" + } + }, + "autoload": { + "classmap": [ + "PHP/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "include-path": [ + "" + ], + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "Wrapper around PHP's tokenizer extension.", + "homepage": "https://github.com/sebastianbergmann/php-token-stream/", + "keywords": [ + "tokenizer" + ], + "time": "2014-03-03 05:10:30" + }, + { + "name": "phpunit/phpunit", + "version": "3.7.38", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/phpunit.git", + "reference": "38709dc22d519a3d1be46849868aa2ddf822bcf6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/38709dc22d519a3d1be46849868aa2ddf822bcf6", + "reference": "38709dc22d519a3d1be46849868aa2ddf822bcf6", + "shasum": "" + }, + "require": { + "ext-ctype": "*", + "ext-dom": "*", + "ext-json": "*", + "ext-pcre": "*", + "ext-reflection": "*", + "ext-spl": "*", + "php": ">=5.3.3", + "phpunit/php-code-coverage": "~1.2", + "phpunit/php-file-iterator": "~1.3", + "phpunit/php-text-template": "~1.1", + "phpunit/php-timer": "~1.0", + "phpunit/phpunit-mock-objects": "~1.2", + "symfony/yaml": "~2.0" + }, + "require-dev": { + "pear-pear.php.net/pear": "1.9.4" + }, + "suggest": { + "phpunit/php-invoker": "~1.1" + }, + "bin": [ + "composer/bin/phpunit" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.7.x-dev" + } + }, + "autoload": { + "classmap": [ + "PHPUnit/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "include-path": [ + "", + "../../symfony/yaml/" + ], + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "The PHP Unit Testing framework.", + "homepage": "http://www.phpunit.de/", + "keywords": [ + "phpunit", + "testing", + "xunit" + ], + "time": "2014-10-17 09:04:17" + }, + { + "name": "phpunit/phpunit-mock-objects", + "version": "1.2.x-dev", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git", + "reference": "c39c4511c3b007539eb170c32cbc2af49a07351a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/c39c4511c3b007539eb170c32cbc2af49a07351a", + "reference": "c39c4511c3b007539eb170c32cbc2af49a07351a", + "shasum": "" + }, + "require": { + "php": ">=5.3.3", + "phpunit/php-text-template": ">=1.1.1@stable" + }, + "require-dev": { + "phpunit/phpunit": "3.7.*@dev" + }, + "suggest": { + "ext-soap": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.2.x-dev" + } + }, + "autoload": { + "classmap": [ + "PHPUnit/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "include-path": [ + "" + ], + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "Mock Object library for PHPUnit", + "homepage": "https://github.com/sebastianbergmann/phpunit-mock-objects/", + "keywords": [ + "mock", + "xunit" + ], + "time": "2014-02-16 12:43:56" + }, + { + "name": "squizlabs/php_codesniffer", + "version": "2.1.0", + "source": { + "type": "git", + "url": "https://github.com/squizlabs/PHP_CodeSniffer.git", + "reference": "d2a1d4c58fd2bb09ba376d0d19e67c0ab649e401" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/d2a1d4c58fd2bb09ba376d0d19e67c0ab649e401", + "reference": "d2a1d4c58fd2bb09ba376d0d19e67c0ab649e401", + "shasum": "" + }, + "require": { + "ext-tokenizer": "*", + "php": ">=5.1.2" + }, + "bin": [ + "scripts/phpcs", + "scripts/phpcbf" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-phpcs-fixer": "2.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "CodeSniffer.php", + "CodeSniffer/CLI.php", + "CodeSniffer/Exception.php", + "CodeSniffer/File.php", + "CodeSniffer/Fixer.php", + "CodeSniffer/Report.php", + "CodeSniffer/Reporting.php", + "CodeSniffer/Sniff.php", + "CodeSniffer/Tokens.php", + "CodeSniffer/Reports/", + "CodeSniffer/Tokenizers/", + "CodeSniffer/DocGenerators/", + "CodeSniffer/Standards/AbstractPatternSniff.php", + "CodeSniffer/Standards/AbstractScopeSniff.php", + "CodeSniffer/Standards/AbstractVariableSniff.php", + "CodeSniffer/Standards/IncorrectPatternException.php", + "CodeSniffer/Standards/Generic/Sniffs/", + "CodeSniffer/Standards/MySource/Sniffs/", + "CodeSniffer/Standards/PEAR/Sniffs/", + "CodeSniffer/Standards/PSR1/Sniffs/", + "CodeSniffer/Standards/PSR2/Sniffs/", + "CodeSniffer/Standards/Squiz/Sniffs/", + "CodeSniffer/Standards/Zend/Sniffs/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Greg Sherwood", + "role": "lead" + } + ], + "description": "PHP_CodeSniffer tokenises PHP, JavaScript and CSS files and detects violations of a defined set of coding standards.", + "homepage": "http://www.squizlabs.com/php-codesniffer", + "keywords": [ + "phpcs", + "standards" + ], + "time": "2014-12-18 02:37:51" + }, + { + "name": "symfony/yaml", + "version": "2.7.x-dev", + "target-dir": "Symfony/Component/Yaml", + "source": { + "type": "git", + "url": "https://github.com/symfony/Yaml.git", + "reference": "43aac3461a5679f486f7c96e4d7e780a59fec997" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/Yaml/zipball/43aac3461a5679f486f7c96e4d7e780a59fec997", + "reference": "43aac3461a5679f486f7c96e4d7e780a59fec997", + "shasum": "" + }, + "require": { + "php": ">=5.3.9" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.7-dev" + } + }, + "autoload": { + "psr-0": { + "Symfony\\Component\\Yaml\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Symfony Community", + "homepage": "http://symfony.com/contributors" + }, + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + } + ], + "description": "Symfony Yaml Component", + "homepage": "http://symfony.com", + "time": "2015-02-11 07:17:51" + } + ], + "aliases": [], + "minimum-stability": "dev", + "stability-flags": [], + "prefer-stable": false, + "prefer-lowest": false, + "platform": { + "php": ">=5.3.0" + }, + "platform-dev": [] +} diff --git a/vendor/symfony/polyfill-intl-idn/Idn.php b/vendor/symfony/polyfill-intl-idn/Idn.php index 334f8ee70..448f74cef 100644 --- a/vendor/symfony/polyfill-intl-idn/Idn.php +++ b/vendor/symfony/polyfill-intl-idn/Idn.php @@ -145,6 +145,10 @@ final class Idn */ public static function idn_to_ascii($domainName, $options = self::IDNA_DEFAULT, $variant = self::INTL_IDNA_VARIANT_UTS46, &$idna_info = []) { + if (\PHP_VERSION_ID > 80400 && '' === $domainName) { + throw new \ValueError('idn_to_ascii(): Argument #1 ($domain) cannot be empty'); + } + if (self::INTL_IDNA_VARIANT_2003 === $variant) { @trigger_error('idn_to_ascii(): INTL_IDNA_VARIANT_2003 is deprecated', \E_USER_DEPRECATED); } @@ -198,6 +202,10 @@ public static function idn_to_ascii($domainName, $options = self::IDNA_DEFAULT, */ public static function idn_to_utf8($domainName, $options = self::IDNA_DEFAULT, $variant = self::INTL_IDNA_VARIANT_UTS46, &$idna_info = []) { + if (\PHP_VERSION_ID > 80400 && '' === $domainName) { + throw new \ValueError('idn_to_utf8(): Argument #1 ($domain) cannot be empty'); + } + if (self::INTL_IDNA_VARIANT_2003 === $variant) { @trigger_error('idn_to_utf8(): INTL_IDNA_VARIANT_2003 is deprecated', \E_USER_DEPRECATED); } diff --git a/vendor/symfony/polyfill-mbstring/Mbstring.php b/vendor/symfony/polyfill-mbstring/Mbstring.php index 3d45c9d9a..31e36a368 100644 --- a/vendor/symfony/polyfill-mbstring/Mbstring.php +++ b/vendor/symfony/polyfill-mbstring/Mbstring.php @@ -983,7 +983,7 @@ public static function mb_ltrim(string $string, ?string $characters = null, ?str public static function mb_rtrim(string $string, ?string $characters = null, ?string $encoding = null): string { - return self::mb_internal_trim('{[%s]+$}D', $string, $characters, $encoding, __FUNCTION__); + return self::mb_internal_trim('{[%s]+$}Du', $string, $characters, $encoding, __FUNCTION__); } private static function mb_internal_trim(string $regex, string $string, ?string $characters, ?string $encoding, string $function): string diff --git a/vendor/symfony/polyfill-mbstring/bootstrap80.php b/vendor/symfony/polyfill-mbstring/bootstrap80.php index 5be7d2018..5236e6dcc 100644 --- a/vendor/symfony/polyfill-mbstring/bootstrap80.php +++ b/vendor/symfony/polyfill-mbstring/bootstrap80.php @@ -133,11 +133,11 @@ function mb_str_pad(string $string, int $length, string $pad_string = ' ', int $ } if (!function_exists('mb_ucfirst')) { - function mb_ucfirst($string, ?string $encoding = null): string { return p\Mbstring::mb_ucfirst($string, $encoding); } + function mb_ucfirst(string $string, ?string $encoding = null): string { return p\Mbstring::mb_ucfirst($string, $encoding); } } if (!function_exists('mb_lcfirst')) { - function mb_lcfirst($string, ?string $encoding = null): string { return p\Mbstring::mb_lcfirst($string, $encoding); } + function mb_lcfirst(string $string, ?string $encoding = null): string { return p\Mbstring::mb_lcfirst($string, $encoding); } } if (!function_exists('mb_trim')) { diff --git a/vendor/symfony/polyfill-mbstring/composer.json b/vendor/symfony/polyfill-mbstring/composer.json index 4ed241a33..daa07f86b 100644 --- a/vendor/symfony/polyfill-mbstring/composer.json +++ b/vendor/symfony/polyfill-mbstring/composer.json @@ -16,7 +16,8 @@ } ], "require": { - "php": ">=7.2" + "php": ">=7.2", + "ext-iconv": "*" }, "provide": { "ext-mbstring": "*" diff --git a/vendor/tecnickcom/tcpdf/.github/FUNDING.yml b/vendor/tecnickcom/tcpdf/.github/FUNDING.yml new file mode 100644 index 000000000..ca5b4292e --- /dev/null +++ b/vendor/tecnickcom/tcpdf/.github/FUNDING.yml @@ -0,0 +1 @@ +custom: ['https://www.paypal.com/cgi-bin/webscr?cmd=_donations¤cy_code=GBP&business=paypal@tecnick.com&item_name=donation%20for%20tcpdf%20project'] diff --git a/vendor/tecnickcom/tcpdf/.gitignore b/vendor/tecnickcom/tcpdf/.gitignore new file mode 100644 index 000000000..723ef36f4 --- /dev/null +++ b/vendor/tecnickcom/tcpdf/.gitignore @@ -0,0 +1 @@ +.idea \ No newline at end of file diff --git a/vendor/tecnickcom/tcpdf/composer.json b/vendor/tecnickcom/tcpdf/composer.json new file mode 100644 index 000000000..9f1cc6719 --- /dev/null +++ b/vendor/tecnickcom/tcpdf/composer.json @@ -0,0 +1,47 @@ +{ + "name": "tecnickcom/tcpdf", + "version": "6.3.5", + "homepage": "http://www.tcpdf.org/", + "type": "library", + "description": "TCPDF is a PHP class for generating PDF documents and barcodes.", + "keywords": [ + "PDF", + "tcpdf", + "PDFD32000-2008", + "qrcode", + "datamatrix", + "pdf417", + "barcodes" + ], + "license": "LGPL-3.0-only", + "authors": [ + { + "name": "Nicola Asuni", + "email": "info@tecnick.com", + "role": "lead" + } + ], + "require": { + "php": ">=5.3.0" + }, + "autoload": { + "classmap": [ + "config", + "include", + "tcpdf.php", + "tcpdf_parser.php", + "tcpdf_import.php", + "tcpdf_barcodes_1d.php", + "tcpdf_barcodes_2d.php", + "include/tcpdf_colors.php", + "include/tcpdf_filters.php", + "include/tcpdf_font_data.php", + "include/tcpdf_fonts.php", + "include/tcpdf_images.php", + "include/tcpdf_static.php", + "include/barcodes/datamatrix.php", + "include/barcodes/pdf417.php", + "include/barcodes/qrcode.php" + ] + } +} diff --git a/vendor/tecnickcom/tcpdf/tools/.htaccess b/vendor/tecnickcom/tcpdf/tools/.htaccess new file mode 100644 index 000000000..8d2f25636 --- /dev/null +++ b/vendor/tecnickcom/tcpdf/tools/.htaccess @@ -0,0 +1 @@ +deny from all diff --git a/vendor/tecnickcom/tcpdf/tools/tcpdf_addfont.php b/vendor/tecnickcom/tcpdf/tools/tcpdf_addfont.php old mode 100644 new mode 100755 diff --git a/vendor/webmozart/assert/.php-cs-fixer.php b/vendor/webmozart/assert/.php-cs-fixer.php new file mode 100644 index 000000000..f60f77690 --- /dev/null +++ b/vendor/webmozart/assert/.php-cs-fixer.php @@ -0,0 +1,27 @@ +in(__DIR__.'/src') + ->in(__DIR__.'/tests') +; + +return (new PhpCsFixer\Config()) + ->setRiskyAllowed(true) + ->setRules([ + '@PSR2' => true, + '@Symfony' => true, + 'ordered_imports' => true, + 'array_syntax' => ['syntax' => 'long'], + 'fully_qualified_strict_types' => false, + 'global_namespace_import' => true, + 'no_superfluous_phpdoc_tags' => false, + 'phpdoc_annotation_without_dot' => false, + 'phpdoc_types_order' => false, + 'phpdoc_separation' => ['skip_unlisted_annotations' => true], + 'phpdoc_summary' => false, + 'phpdoc_to_comment' => false, + 'phpdoc_align' => false, + 'yoda_style' => false, + ]) + ->setFinder($finder) +; diff --git a/vendor/webmozart/assert/CHANGELOG.md b/vendor/webmozart/assert/CHANGELOG.md index 56c8011de..d2aaca067 100644 --- a/vendor/webmozart/assert/CHANGELOG.md +++ b/vendor/webmozart/assert/CHANGELOG.md @@ -3,11 +3,26 @@ Changelog ## UNRELEASED +## 1.12.1 + +### Fixed + +- Exclude tools from export. + +## 1.12.0 + +### Fixed + +- Corrected messages and typos in various assertions. +- Document `void` return type. +- Prevent UUIDs with trailing newlines from validating. +- Assert values are strings before ctype checks. + ## 1.11.0 ### Added -* Added explicit (non magic) `allNullOr*` methods, with `@psalm-assert` annotations, for better Psalm support. +* Added explicit (non-magic) `allNullOr*` methods, with `@psalm-assert` annotations, for better Psalm support. ### Changed @@ -17,7 +32,7 @@ Changelog ### Removed -* Removed `symfony/polyfill-ctype` as a dependency, and require `ext-cytpe` instead. +* Removed `symfony/polyfill-ctype` as a dependency, and require `ext-ctype` instead. * You can still require the `symfony/polyfill-ctype` in your project if you need it, as it provides `ext-ctype` ## 1.10.0 @@ -51,7 +66,7 @@ Changelog ## Changed * the `all*` & `nullOr*` methods are now declared on an interface, instead of `@method` annotations. -This interface is linked to the `Assert` class with a `@mixin` annotation. Most IDE's have supported this +This interface is linked to the `Assert` class with a `@mixin` annotation. Most IDEs have supported this for a long time, and you should not lose any autocompletion capabilities. PHPStan has supported this since version `0.12.20`. This package is marked incompatible (with a composer conflict) with phpstan version prior to that. If you do not use PHPStan than this does not matter. diff --git a/vendor/webmozart/assert/README.md b/vendor/webmozart/assert/README.md index 3b2397a1a..766099cbd 100644 --- a/vendor/webmozart/assert/README.md +++ b/vendor/webmozart/assert/README.md @@ -91,7 +91,7 @@ Method | Description `positiveInteger($value, $message = '')` | Check that a value is a positive (non-zero) integer `float($value, $message = '')` | Check that a value is a float `numeric($value, $message = '')` | Check that a value is numeric -`natural($value, $message= ''')` | Check that a value is a non-negative integer +`natural($value, $message = '')` | Check that a value is a non-negative integer `boolean($value, $message = '')` | Check that a value is a boolean `scalar($value, $message = '')` | Check that a value is a scalar `object($value, $message = '')` | Check that a value is an object @@ -223,7 +223,7 @@ Assert::allIsInstanceOf($employees, 'Acme\Employee'); ### Nullable Assertions All of the above assertions can be prefixed with `nullOr*()` to run the -assertion only if it the value is not `null`: +assertion only if the value is not `null`: ```php Assert::nullOrString($middleName, 'The middle name must be a string or null. Got: %s'); @@ -243,7 +243,7 @@ Overriding the following methods in your assertion class allows you to change th * `protected static function valueToString($value)` * This method is used for error messages, to convert the value to a string value for displaying. You could use this for representing a value object with a `__toString` method for example. * `protected static function typeToString($value)` - * This method is used for error messages, to convert the a value to a string representing its type. + * This method is used for error messages, to convert a value to a string representing its type. * `protected static function strlen($value)` * This method is used to calculate string length for relevant methods, using the `mb_strlen` if available and useful. * `protected static function reportInvalidArgument($message)` diff --git a/vendor/webmozart/assert/composer.json b/vendor/webmozart/assert/composer.json index b340452c7..dcaf97a2a 100644 --- a/vendor/webmozart/assert/composer.json +++ b/vendor/webmozart/assert/composer.json @@ -15,14 +15,14 @@ ], "require": { "php": "^7.2 || ^8.0", - "ext-ctype": "*" + "ext-ctype": "*", + "ext-date": "*", + "ext-filter": "*" }, - "require-dev": { - "phpunit/phpunit": "^8.5.13" - }, - "conflict": { - "phpstan/phpstan": "<0.12.20", - "vimeo/psalm": "<4.6.1 || 4.6.2" + "suggest": { + "ext-intl": "", + "ext-simplexml": "", + "ext-spl": "" }, "autoload": { "psr-4": { @@ -31,13 +31,26 @@ }, "autoload-dev": { "psr-4": { - "Webmozart\\Assert\\Tests\\": "tests/", - "Webmozart\\Assert\\Bin\\": "bin/src" + "Webmozart\\Assert\\Bin\\": "bin/src", + "Webmozart\\Assert\\Tests\\": "tests/" } }, "extra": { "branch-alias": { "dev-master": "1.10-dev" } + }, + "scripts": { + "install-tools": [ + "composer --working-dir=tools/php-cs-fixer install", + "composer --working-dir=tools/phpunit install", + "composer --working-dir=tools/psalm install", + "composer --working-dir=tools/roave-bc-check install" + ], + "bc-check": "./tools/roave-bc-check/vendor/bin/roave-backward-compatibility-check", + "cs-check" : "./tools/php-cs-fixer/vendor/bin/php-cs-fixer check", + "cs-fix": "./tools/php-cs-fixer/vendor/bin/php-cs-fixer fix", + "static-analysis": "./tools/psalm/vendor/bin/psalm --threads=4 --root=$(pwd)", + "test": "./tools/phpunit/vendor/bin/phpunit" } } diff --git a/vendor/webmozart/assert/src/Assert.php b/vendor/webmozart/assert/src/Assert.php index db1f3a51a..5bf5cfa6e 100644 --- a/vendor/webmozart/assert/src/Assert.php +++ b/vendor/webmozart/assert/src/Assert.php @@ -36,11 +36,14 @@ class Assert /** * @psalm-pure + * * @psalm-assert string $value * * @param mixed $value * @param string $message * + * @return void + * * @throws InvalidArgumentException */ public static function string($value, $message = '') @@ -55,11 +58,14 @@ public static function string($value, $message = '') /** * @psalm-pure + * * @psalm-assert non-empty-string $value * * @param mixed $value * @param string $message * + * @return void + * * @throws InvalidArgumentException */ public static function stringNotEmpty($value, $message = '') @@ -70,11 +76,14 @@ public static function stringNotEmpty($value, $message = '') /** * @psalm-pure + * * @psalm-assert int $value * * @param mixed $value * @param string $message * + * @return void + * * @throws InvalidArgumentException */ public static function integer($value, $message = '') @@ -89,11 +98,14 @@ public static function integer($value, $message = '') /** * @psalm-pure + * * @psalm-assert numeric $value * * @param mixed $value * @param string $message * + * @return void + * * @throws InvalidArgumentException */ public static function integerish($value, $message = '') @@ -108,11 +120,14 @@ public static function integerish($value, $message = '') /** * @psalm-pure + * * @psalm-assert positive-int $value * * @param mixed $value * @param string $message * + * @return void + * * @throws InvalidArgumentException */ public static function positiveInteger($value, $message = '') @@ -127,11 +142,14 @@ public static function positiveInteger($value, $message = '') /** * @psalm-pure + * * @psalm-assert float $value * * @param mixed $value * @param string $message * + * @return void + * * @throws InvalidArgumentException */ public static function float($value, $message = '') @@ -146,11 +164,14 @@ public static function float($value, $message = '') /** * @psalm-pure + * * @psalm-assert numeric $value * * @param mixed $value * @param string $message * + * @return void + * * @throws InvalidArgumentException */ public static function numeric($value, $message = '') @@ -165,11 +186,14 @@ public static function numeric($value, $message = '') /** * @psalm-pure + * * @psalm-assert positive-int|0 $value * * @param mixed $value * @param string $message * + * @return void + * * @throws InvalidArgumentException */ public static function natural($value, $message = '') @@ -184,11 +208,14 @@ public static function natural($value, $message = '') /** * @psalm-pure + * * @psalm-assert bool $value * * @param mixed $value * @param string $message * + * @return void + * * @throws InvalidArgumentException */ public static function boolean($value, $message = '') @@ -203,11 +230,14 @@ public static function boolean($value, $message = '') /** * @psalm-pure + * * @psalm-assert scalar $value * * @param mixed $value * @param string $message * + * @return void + * * @throws InvalidArgumentException */ public static function scalar($value, $message = '') @@ -222,11 +252,14 @@ public static function scalar($value, $message = '') /** * @psalm-pure + * * @psalm-assert object $value * * @param mixed $value * @param string $message * + * @return void + * * @throws InvalidArgumentException */ public static function object($value, $message = '') @@ -241,12 +274,15 @@ public static function object($value, $message = '') /** * @psalm-pure + * * @psalm-assert resource $value * * @param mixed $value * @param string|null $type type of resource this should be. @see https://www.php.net/manual/en/function.get-resource-type.php * @param string $message * + * @return void + * * @throws InvalidArgumentException */ public static function resource($value, $type = null, $message = '') @@ -254,7 +290,8 @@ public static function resource($value, $type = null, $message = '') if (!\is_resource($value)) { static::reportInvalidArgument(\sprintf( $message ?: 'Expected a resource. Got: %s', - static::typeToString($value) + static::typeToString($value), + $type // User supplied message might include the second placeholder. )); } @@ -269,11 +306,14 @@ public static function resource($value, $type = null, $message = '') /** * @psalm-pure + * * @psalm-assert callable $value * * @param mixed $value * @param string $message * + * @return void + * * @throws InvalidArgumentException */ public static function isCallable($value, $message = '') @@ -288,11 +328,14 @@ public static function isCallable($value, $message = '') /** * @psalm-pure + * * @psalm-assert array $value * * @param mixed $value * @param string $message * + * @return void + * * @throws InvalidArgumentException */ public static function isArray($value, $message = '') @@ -307,6 +350,7 @@ public static function isArray($value, $message = '') /** * @psalm-pure + * * @psalm-assert iterable $value * * @deprecated use "isIterable" or "isInstanceOf" instead @@ -314,6 +358,8 @@ public static function isArray($value, $message = '') * @param mixed $value * @param string $message * + * @return void + * * @throws InvalidArgumentException */ public static function isTraversable($value, $message = '') @@ -336,11 +382,14 @@ public static function isTraversable($value, $message = '') /** * @psalm-pure + * * @psalm-assert array|ArrayAccess $value * * @param mixed $value * @param string $message * + * @return void + * * @throws InvalidArgumentException */ public static function isArrayAccessible($value, $message = '') @@ -355,11 +404,14 @@ public static function isArrayAccessible($value, $message = '') /** * @psalm-pure + * * @psalm-assert countable $value * * @param mixed $value * @param string $message * + * @return void + * * @throws InvalidArgumentException */ public static function isCountable($value, $message = '') @@ -379,11 +431,14 @@ public static function isCountable($value, $message = '') /** * @psalm-pure + * * @psalm-assert iterable $value * * @param mixed $value * @param string $message * + * @return void + * * @throws InvalidArgumentException */ public static function isIterable($value, $message = '') @@ -398,14 +453,19 @@ public static function isIterable($value, $message = '') /** * @psalm-pure + * * @psalm-template ExpectedType of object + * * @psalm-param class-string $class + * * @psalm-assert ExpectedType $value * * @param mixed $value * @param string|object $class * @param string $message * + * @return void + * * @throws InvalidArgumentException */ public static function isInstanceOf($value, $class, $message = '') @@ -421,14 +481,19 @@ public static function isInstanceOf($value, $class, $message = '') /** * @psalm-pure + * * @psalm-template ExpectedType of object + * * @psalm-param class-string $class + * * @psalm-assert !ExpectedType $value * * @param mixed $value * @param string|object $class * @param string $message * + * @return void + * * @throws InvalidArgumentException */ public static function notInstanceOf($value, $class, $message = '') @@ -444,12 +509,15 @@ public static function notInstanceOf($value, $class, $message = '') /** * @psalm-pure + * * @psalm-param array $classes * * @param mixed $value * @param array $classes * @param string $message * + * @return void + * * @throws InvalidArgumentException */ public static function isInstanceOfAny($value, array $classes, $message = '') @@ -469,14 +537,19 @@ public static function isInstanceOfAny($value, array $classes, $message = '') /** * @psalm-pure + * * @psalm-template ExpectedType of object + * * @psalm-param class-string $class + * * @psalm-assert ExpectedType|class-string $value * * @param object|string $value * @param string $class * @param string $message * + * @return void + * * @throws InvalidArgumentException */ public static function isAOf($value, $class, $message = '') @@ -494,8 +567,11 @@ public static function isAOf($value, $class, $message = '') /** * @psalm-pure + * * @psalm-template UnexpectedType of object + * * @psalm-param class-string $class + * * @psalm-assert !UnexpectedType $value * @psalm-assert !class-string $value * @@ -503,6 +579,8 @@ public static function isAOf($value, $class, $message = '') * @param string $class * @param string $message * + * @return void + * * @throws InvalidArgumentException */ public static function isNotA($value, $class, $message = '') @@ -520,12 +598,15 @@ public static function isNotA($value, $class, $message = '') /** * @psalm-pure + * * @psalm-param array $classes * * @param object|string $value * @param string[] $classes * @param string $message * + * @return void + * * @throws InvalidArgumentException */ public static function isAnyOf($value, array $classes, $message = '') @@ -547,11 +628,14 @@ public static function isAnyOf($value, array $classes, $message = '') /** * @psalm-pure + * * @psalm-assert empty $value * * @param mixed $value * @param string $message * + * @return void + * * @throws InvalidArgumentException */ public static function isEmpty($value, $message = '') @@ -566,11 +650,14 @@ public static function isEmpty($value, $message = '') /** * @psalm-pure + * * @psalm-assert !empty $value * * @param mixed $value * @param string $message * + * @return void + * * @throws InvalidArgumentException */ public static function notEmpty($value, $message = '') @@ -585,11 +672,14 @@ public static function notEmpty($value, $message = '') /** * @psalm-pure + * * @psalm-assert null $value * * @param mixed $value * @param string $message * + * @return void + * * @throws InvalidArgumentException */ public static function null($value, $message = '') @@ -604,11 +694,14 @@ public static function null($value, $message = '') /** * @psalm-pure + * * @psalm-assert !null $value * * @param mixed $value * @param string $message * + * @return void + * * @throws InvalidArgumentException */ public static function notNull($value, $message = '') @@ -622,11 +715,14 @@ public static function notNull($value, $message = '') /** * @psalm-pure + * * @psalm-assert true $value * * @param mixed $value * @param string $message * + * @return void + * * @throws InvalidArgumentException */ public static function true($value, $message = '') @@ -641,11 +737,14 @@ public static function true($value, $message = '') /** * @psalm-pure + * * @psalm-assert false $value * * @param mixed $value * @param string $message * + * @return void + * * @throws InvalidArgumentException */ public static function false($value, $message = '') @@ -660,11 +759,14 @@ public static function false($value, $message = '') /** * @psalm-pure + * * @psalm-assert !false $value * * @param mixed $value * @param string $message * + * @return void + * * @throws InvalidArgumentException */ public static function notFalse($value, $message = '') @@ -680,6 +782,8 @@ public static function notFalse($value, $message = '') * @param mixed $value * @param string $message * + * @return void + * * @throws InvalidArgumentException */ public static function ip($value, $message = '') @@ -696,6 +800,8 @@ public static function ip($value, $message = '') * @param mixed $value * @param string $message * + * @return void + * * @throws InvalidArgumentException */ public static function ipv4($value, $message = '') @@ -712,6 +818,8 @@ public static function ipv4($value, $message = '') * @param mixed $value * @param string $message * + * @return void + * * @throws InvalidArgumentException */ public static function ipv6($value, $message = '') @@ -728,6 +836,8 @@ public static function ipv6($value, $message = '') * @param mixed $value * @param string $message * + * @return void + * * @throws InvalidArgumentException */ public static function email($value, $message = '') @@ -746,6 +856,8 @@ public static function email($value, $message = '') * @param array $values * @param string $message * + * @return void + * * @throws InvalidArgumentException */ public static function uniqueValues(array $values, $message = '') @@ -759,7 +871,7 @@ public static function uniqueValues(array $values, $message = '') static::reportInvalidArgument(\sprintf( $message ?: 'Expected an array of unique values, but %s of them %s duplicated', $difference, - (1 === $difference ? 'is' : 'are') + 1 === $difference ? 'is' : 'are' )); } } @@ -769,6 +881,8 @@ public static function uniqueValues(array $values, $message = '') * @param mixed $expect * @param string $message * + * @return void + * * @throws InvalidArgumentException */ public static function eq($value, $expect, $message = '') @@ -787,6 +901,8 @@ public static function eq($value, $expect, $message = '') * @param mixed $expect * @param string $message * + * @return void + * * @throws InvalidArgumentException */ public static function notEq($value, $expect, $message = '') @@ -806,6 +922,8 @@ public static function notEq($value, $expect, $message = '') * @param mixed $expect * @param string $message * + * @return void + * * @throws InvalidArgumentException */ public static function same($value, $expect, $message = '') @@ -826,6 +944,8 @@ public static function same($value, $expect, $message = '') * @param mixed $expect * @param string $message * + * @return void + * * @throws InvalidArgumentException */ public static function notSame($value, $expect, $message = '') @@ -845,6 +965,8 @@ public static function notSame($value, $expect, $message = '') * @param mixed $limit * @param string $message * + * @return void + * * @throws InvalidArgumentException */ public static function greaterThan($value, $limit, $message = '') @@ -865,6 +987,8 @@ public static function greaterThan($value, $limit, $message = '') * @param mixed $limit * @param string $message * + * @return void + * * @throws InvalidArgumentException */ public static function greaterThanEq($value, $limit, $message = '') @@ -885,6 +1009,8 @@ public static function greaterThanEq($value, $limit, $message = '') * @param mixed $limit * @param string $message * + * @return void + * * @throws InvalidArgumentException */ public static function lessThan($value, $limit, $message = '') @@ -905,6 +1031,8 @@ public static function lessThan($value, $limit, $message = '') * @param mixed $limit * @param string $message * + * @return void + * * @throws InvalidArgumentException */ public static function lessThanEq($value, $limit, $message = '') @@ -928,6 +1056,8 @@ public static function lessThanEq($value, $limit, $message = '') * @param mixed $max * @param string $message * + * @return void + * * @throws InvalidArgumentException */ public static function range($value, $min, $max, $message = '') @@ -951,6 +1081,8 @@ public static function range($value, $min, $max, $message = '') * @param array $values * @param string $message * + * @return void + * * @throws InvalidArgumentException */ public static function oneOf($value, array $values, $message = '') @@ -967,6 +1099,8 @@ public static function oneOf($value, array $values, $message = '') * @param array $values * @param string $message * + * @return void + * * @throws InvalidArgumentException */ public static function inArray($value, array $values, $message = '') @@ -987,6 +1121,8 @@ public static function inArray($value, array $values, $message = '') * @param string $subString * @param string $message * + * @return void + * * @throws InvalidArgumentException */ public static function contains($value, $subString, $message = '') @@ -1007,6 +1143,8 @@ public static function contains($value, $subString, $message = '') * @param string $subString * @param string $message * + * @return void + * * @throws InvalidArgumentException */ public static function notContains($value, $subString, $message = '') @@ -1026,6 +1164,8 @@ public static function notContains($value, $subString, $message = '') * @param string $value * @param string $message * + * @return void + * * @throws InvalidArgumentException */ public static function notWhitespaceOnly($value, $message = '') @@ -1045,6 +1185,8 @@ public static function notWhitespaceOnly($value, $message = '') * @param string $prefix * @param string $message * + * @return void + * * @throws InvalidArgumentException */ public static function startsWith($value, $prefix, $message = '') @@ -1065,6 +1207,8 @@ public static function startsWith($value, $prefix, $message = '') * @param string $prefix * @param string $message * + * @return void + * * @throws InvalidArgumentException */ public static function notStartsWith($value, $prefix, $message = '') @@ -1084,6 +1228,8 @@ public static function notStartsWith($value, $prefix, $message = '') * @param mixed $value * @param string $message * + * @return void + * * @throws InvalidArgumentException */ public static function startsWithLetter($value, $message = '') @@ -1114,6 +1260,8 @@ public static function startsWithLetter($value, $message = '') * @param string $suffix * @param string $message * + * @return void + * * @throws InvalidArgumentException */ public static function endsWith($value, $suffix, $message = '') @@ -1134,6 +1282,8 @@ public static function endsWith($value, $suffix, $message = '') * @param string $suffix * @param string $message * + * @return void + * * @throws InvalidArgumentException */ public static function notEndsWith($value, $suffix, $message = '') @@ -1154,6 +1304,8 @@ public static function notEndsWith($value, $suffix, $message = '') * @param string $pattern * @param string $message * + * @return void + * * @throws InvalidArgumentException */ public static function regex($value, $pattern, $message = '') @@ -1173,6 +1325,8 @@ public static function regex($value, $pattern, $message = '') * @param string $pattern * @param string $message * + * @return void + * * @throws InvalidArgumentException */ public static function notRegex($value, $pattern, $message = '') @@ -1193,6 +1347,8 @@ public static function notRegex($value, $pattern, $message = '') * @param mixed $value * @param string $message * + * @return void + * * @throws InvalidArgumentException */ public static function unicodeLetters($value, $message = '') @@ -1213,6 +1369,8 @@ public static function unicodeLetters($value, $message = '') * @param mixed $value * @param string $message * + * @return void + * * @throws InvalidArgumentException */ public static function alpha($value, $message = '') @@ -1238,10 +1396,14 @@ public static function alpha($value, $message = '') * @param string $value * @param string $message * + * @return void + * * @throws InvalidArgumentException */ public static function digits($value, $message = '') { + static::string($value); + $locale = \setlocale(LC_CTYPE, 0); \setlocale(LC_CTYPE, 'C'); $valid = !\ctype_digit($value); @@ -1261,10 +1423,14 @@ public static function digits($value, $message = '') * @param string $value * @param string $message * + * @return void + * * @throws InvalidArgumentException */ public static function alnum($value, $message = '') { + static::string($value); + $locale = \setlocale(LC_CTYPE, 0); \setlocale(LC_CTYPE, 'C'); $valid = !\ctype_alnum($value); @@ -1280,15 +1446,20 @@ public static function alnum($value, $message = '') /** * @psalm-pure + * * @psalm-assert lowercase-string $value * * @param string $value * @param string $message * + * @return void + * * @throws InvalidArgumentException */ public static function lower($value, $message = '') { + static::string($value); + $locale = \setlocale(LC_CTYPE, 0); \setlocale(LC_CTYPE, 'C'); $valid = !\ctype_lower($value); @@ -1304,15 +1475,20 @@ public static function lower($value, $message = '') /** * @psalm-pure + * * @psalm-assert !lowercase-string $value * * @param string $value * @param string $message * + * @return void + * * @throws InvalidArgumentException */ public static function upper($value, $message = '') { + static::string($value); + $locale = \setlocale(LC_CTYPE, 0); \setlocale(LC_CTYPE, 'C'); $valid = !\ctype_upper($value); @@ -1333,6 +1509,8 @@ public static function upper($value, $message = '') * @param int $length * @param string $message * + * @return void + * * @throws InvalidArgumentException */ public static function length($value, $length, $message = '') @@ -1355,6 +1533,8 @@ public static function length($value, $length, $message = '') * @param int|float $min * @param string $message * + * @return void + * * @throws InvalidArgumentException */ public static function minLength($value, $min, $message = '') @@ -1377,6 +1557,8 @@ public static function minLength($value, $min, $message = '') * @param int|float $max * @param string $message * + * @return void + * * @throws InvalidArgumentException */ public static function maxLength($value, $max, $message = '') @@ -1400,6 +1582,8 @@ public static function maxLength($value, $max, $message = '') * @param int|float $max * @param string $message * + * @return void + * * @throws InvalidArgumentException */ public static function lengthBetween($value, $min, $max, $message = '') @@ -1422,15 +1606,15 @@ public static function lengthBetween($value, $min, $max, $message = '') * @param mixed $value * @param string $message * + * @return void + * * @throws InvalidArgumentException */ public static function fileExists($value, $message = '') { - static::string($value); - if (!\file_exists($value)) { static::reportInvalidArgument(\sprintf( - $message ?: 'The file %s does not exist.', + $message ?: 'The path %s does not exist.', static::valueToString($value) )); } @@ -1440,12 +1624,12 @@ public static function fileExists($value, $message = '') * @param mixed $value * @param string $message * + * @return void + * * @throws InvalidArgumentException */ public static function file($value, $message = '') { - static::fileExists($value, $message); - if (!\is_file($value)) { static::reportInvalidArgument(\sprintf( $message ?: 'The path %s is not a file.', @@ -1458,15 +1642,15 @@ public static function file($value, $message = '') * @param mixed $value * @param string $message * + * @return void + * * @throws InvalidArgumentException */ public static function directory($value, $message = '') { - static::fileExists($value, $message); - if (!\is_dir($value)) { static::reportInvalidArgument(\sprintf( - $message ?: 'The path %s is no directory.', + $message ?: 'The path %s is not a directory.', static::valueToString($value) )); } @@ -1476,6 +1660,8 @@ public static function directory($value, $message = '') * @param string $value * @param string $message * + * @return void + * * @throws InvalidArgumentException */ public static function readable($value, $message = '') @@ -1492,6 +1678,8 @@ public static function readable($value, $message = '') * @param string $value * @param string $message * + * @return void + * * @throws InvalidArgumentException */ public static function writable($value, $message = '') @@ -1510,6 +1698,8 @@ public static function writable($value, $message = '') * @param mixed $value * @param string $message * + * @return void + * * @throws InvalidArgumentException */ public static function classExists($value, $message = '') @@ -1524,14 +1714,19 @@ public static function classExists($value, $message = '') /** * @psalm-pure + * * @psalm-template ExpectedType of object + * * @psalm-param class-string $class + * * @psalm-assert class-string|ExpectedType $value * * @param mixed $value * @param string|object $class * @param string $message * + * @return void + * * @throws InvalidArgumentException */ public static function subclassOf($value, $class, $message = '') @@ -1551,6 +1746,8 @@ public static function subclassOf($value, $class, $message = '') * @param mixed $value * @param string $message * + * @return void + * * @throws InvalidArgumentException */ public static function interfaceExists($value, $message = '') @@ -1565,14 +1762,19 @@ public static function interfaceExists($value, $message = '') /** * @psalm-pure + * * @psalm-template ExpectedType of object + * * @psalm-param class-string $interface - * @psalm-assert class-string $value + * + * @psalm-assert class-string|ExpectedType $value * * @param mixed $value * @param mixed $interface * @param string $message * + * @return void + * * @throws InvalidArgumentException */ public static function implementsInterface($value, $interface, $message = '') @@ -1588,12 +1790,15 @@ public static function implementsInterface($value, $interface, $message = '') /** * @psalm-pure + * * @psalm-param class-string|object $classOrObject * * @param string|object $classOrObject * @param mixed $property * @param string $message * + * @return void + * * @throws InvalidArgumentException */ public static function propertyExists($classOrObject, $property, $message = '') @@ -1608,12 +1813,15 @@ public static function propertyExists($classOrObject, $property, $message = '') /** * @psalm-pure + * * @psalm-param class-string|object $classOrObject * * @param string|object $classOrObject * @param mixed $property * @param string $message * + * @return void + * * @throws InvalidArgumentException */ public static function propertyNotExists($classOrObject, $property, $message = '') @@ -1628,12 +1836,15 @@ public static function propertyNotExists($classOrObject, $property, $message = ' /** * @psalm-pure + * * @psalm-param class-string|object $classOrObject * * @param string|object $classOrObject * @param mixed $method * @param string $message * + * @return void + * * @throws InvalidArgumentException */ public static function methodExists($classOrObject, $method, $message = '') @@ -1648,12 +1859,15 @@ public static function methodExists($classOrObject, $method, $message = '') /** * @psalm-pure + * * @psalm-param class-string|object $classOrObject * * @param string|object $classOrObject * @param mixed $method * @param string $message * + * @return void + * * @throws InvalidArgumentException */ public static function methodNotExists($classOrObject, $method, $message = '') @@ -1673,6 +1887,8 @@ public static function methodNotExists($classOrObject, $method, $message = '') * @param string|int $key * @param string $message * + * @return void + * * @throws InvalidArgumentException */ public static function keyExists($array, $key, $message = '') @@ -1692,6 +1908,8 @@ public static function keyExists($array, $key, $message = '') * @param string|int $key * @param string $message * + * @return void + * * @throws InvalidArgumentException */ public static function keyNotExists($array, $key, $message = '') @@ -1708,11 +1926,14 @@ public static function keyNotExists($array, $key, $message = '') * Checks if a value is a valid array key (int or string). * * @psalm-pure + * * @psalm-assert array-key $value * * @param mixed $value * @param string $message * + * @return void + * * @throws InvalidArgumentException */ public static function validArrayKey($value, $message = '') @@ -1732,6 +1953,8 @@ public static function validArrayKey($value, $message = '') * @param int $number * @param string $message * + * @return void + * * @throws InvalidArgumentException */ public static function count($array, $number, $message = '') @@ -1754,6 +1977,8 @@ public static function count($array, $number, $message = '') * @param int|float $min * @param string $message * + * @return void + * * @throws InvalidArgumentException */ public static function minCount($array, $min, $message = '') @@ -1774,6 +1999,8 @@ public static function minCount($array, $min, $message = '') * @param int|float $max * @param string $message * + * @return void + * * @throws InvalidArgumentException */ public static function maxCount($array, $max, $message = '') @@ -1795,6 +2022,8 @@ public static function maxCount($array, $max, $message = '') * @param int|float $max * @param string $message * + * @return void + * * @throws InvalidArgumentException */ public static function countBetween($array, $min, $max, $message = '') @@ -1813,11 +2042,14 @@ public static function countBetween($array, $min, $max, $message = '') /** * @psalm-pure + * * @psalm-assert list $array * * @param mixed $array * @param string $message * + * @return void + * * @throws InvalidArgumentException */ public static function isList($array, $message = '') @@ -1828,27 +2060,38 @@ public static function isList($array, $message = '') ); } - if ($array === \array_values($array)) { - return; - } - - $nextKey = -1; - foreach ($array as $k => $v) { - if ($k !== ++$nextKey) { + if (\function_exists('array_is_list')) { + if (!\array_is_list($array)) { static::reportInvalidArgument( $message ?: 'Expected list - non-associative array.' ); } + + return; + } + + if (array() === $array) { + return; + } + + $keys = array_keys($array); + if (array_keys($keys) !== $keys) { + static::reportInvalidArgument( + $message ?: 'Expected list - non-associative array.' + ); } } /** * @psalm-pure + * * @psalm-assert non-empty-list $array * * @param mixed $array * @param string $message * + * @return void + * * @throws InvalidArgumentException */ public static function isNonEmptyList($array, $message = '') @@ -1859,20 +2102,25 @@ public static function isNonEmptyList($array, $message = '') /** * @psalm-pure + * * @psalm-template T + * * @psalm-param mixed|array $array + * * @psalm-assert array $array * * @param mixed $array * @param string $message * + * @return void + * * @throws InvalidArgumentException */ public static function isMap($array, $message = '') { if ( - !\is_array($array) || - \array_keys($array) !== \array_filter(\array_keys($array), '\is_string') + !\is_array($array) + || \array_keys($array) !== \array_filter(\array_keys($array), '\is_string') ) { static::reportInvalidArgument( $message ?: 'Expected map - associative array with string keys.' @@ -1882,14 +2130,19 @@ public static function isMap($array, $message = '') /** * @psalm-pure + * * @psalm-template T + * * @psalm-param mixed|array $array + * * @psalm-assert array $array * @psalm-assert !empty $array * * @param mixed $array * @param string $message * + * @return void + * * @throws InvalidArgumentException */ public static function isNonEmptyMap($array, $message = '') @@ -1904,6 +2157,8 @@ public static function isNonEmptyMap($array, $message = '') * @param string $value * @param string $message * + * @return void + * * @throws InvalidArgumentException */ public static function uuid($value, $message = '') @@ -1916,7 +2171,7 @@ public static function uuid($value, $message = '') return; } - if (!\preg_match('/^[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{12}$/', $value)) { + if (!\preg_match('/^[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{12}$/D', $value)) { static::reportInvalidArgument(\sprintf( $message ?: 'Value %s is not a valid UUID.', static::valueToString($value) @@ -1931,6 +2186,8 @@ public static function uuid($value, $message = '') * @param string $class * @param string $message * + * @return void + * * @throws InvalidArgumentException */ public static function throws(Closure $expression, $class = 'Exception', $message = '') @@ -2024,6 +2281,10 @@ protected static function valueToString($value) return \get_class($value).': '.self::valueToString($value->format('c')); } + if (\function_exists('enum_exists') && \enum_exists(\get_class($value))) { + return \get_class($value).'::'.$value->name; + } + return \get_class($value); } @@ -2039,6 +2300,8 @@ protected static function valueToString($value) } /** + * @psalm-pure + * * @param mixed $value * * @return string @@ -2067,6 +2330,7 @@ protected static function strlen($value) * @throws InvalidArgumentException * * @psalm-pure this method is not supposed to perform side-effects + * * @psalm-return never */ protected static function reportInvalidArgument($message) diff --git a/vendor/webmozart/assert/src/Mixin.php b/vendor/webmozart/assert/src/Mixin.php index 0f0a75e33..fad0d4756 100644 --- a/vendor/webmozart/assert/src/Mixin.php +++ b/vendor/webmozart/assert/src/Mixin.php @@ -8,21 +8,22 @@ use Throwable; /** - * This trait provides nurllOr*, all* and allNullOr* variants of assertion base methods. + * This trait provides nullOr*, all* and allNullOr* variants of assertion base methods. * Do not use this trait directly: it will change, and is not designed for reuse. */ trait Mixin { /** * @psalm-pure + * * @psalm-assert string|null $value * * @param mixed $value * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function nullOrString($value, $message = '') { @@ -31,14 +32,15 @@ public static function nullOrString($value, $message = '') /** * @psalm-pure + * * @psalm-assert iterable $value * * @param mixed $value * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allString($value, $message = '') { @@ -51,14 +53,15 @@ public static function allString($value, $message = '') /** * @psalm-pure + * * @psalm-assert iterable $value * * @param mixed $value * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allNullOrString($value, $message = '') { @@ -71,14 +74,15 @@ public static function allNullOrString($value, $message = '') /** * @psalm-pure + * * @psalm-assert non-empty-string|null $value * * @param mixed $value * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function nullOrStringNotEmpty($value, $message = '') { @@ -87,14 +91,15 @@ public static function nullOrStringNotEmpty($value, $message = '') /** * @psalm-pure + * * @psalm-assert iterable $value * * @param mixed $value * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allStringNotEmpty($value, $message = '') { @@ -107,14 +112,15 @@ public static function allStringNotEmpty($value, $message = '') /** * @psalm-pure + * * @psalm-assert iterable $value * * @param mixed $value * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allNullOrStringNotEmpty($value, $message = '') { @@ -127,14 +133,15 @@ public static function allNullOrStringNotEmpty($value, $message = '') /** * @psalm-pure + * * @psalm-assert int|null $value * * @param mixed $value * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function nullOrInteger($value, $message = '') { @@ -143,14 +150,15 @@ public static function nullOrInteger($value, $message = '') /** * @psalm-pure + * * @psalm-assert iterable $value * * @param mixed $value * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allInteger($value, $message = '') { @@ -163,14 +171,15 @@ public static function allInteger($value, $message = '') /** * @psalm-pure + * * @psalm-assert iterable $value * * @param mixed $value * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allNullOrInteger($value, $message = '') { @@ -183,14 +192,15 @@ public static function allNullOrInteger($value, $message = '') /** * @psalm-pure + * * @psalm-assert numeric|null $value * * @param mixed $value * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function nullOrIntegerish($value, $message = '') { @@ -199,14 +209,15 @@ public static function nullOrIntegerish($value, $message = '') /** * @psalm-pure + * * @psalm-assert iterable $value * * @param mixed $value * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allIntegerish($value, $message = '') { @@ -219,14 +230,15 @@ public static function allIntegerish($value, $message = '') /** * @psalm-pure + * * @psalm-assert iterable $value * * @param mixed $value * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allNullOrIntegerish($value, $message = '') { @@ -239,14 +251,15 @@ public static function allNullOrIntegerish($value, $message = '') /** * @psalm-pure + * * @psalm-assert positive-int|null $value * * @param mixed $value * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function nullOrPositiveInteger($value, $message = '') { @@ -255,14 +268,15 @@ public static function nullOrPositiveInteger($value, $message = '') /** * @psalm-pure + * * @psalm-assert iterable $value * * @param mixed $value * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allPositiveInteger($value, $message = '') { @@ -275,14 +289,15 @@ public static function allPositiveInteger($value, $message = '') /** * @psalm-pure + * * @psalm-assert iterable $value * * @param mixed $value * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allNullOrPositiveInteger($value, $message = '') { @@ -295,14 +310,15 @@ public static function allNullOrPositiveInteger($value, $message = '') /** * @psalm-pure + * * @psalm-assert float|null $value * * @param mixed $value * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function nullOrFloat($value, $message = '') { @@ -311,14 +327,15 @@ public static function nullOrFloat($value, $message = '') /** * @psalm-pure + * * @psalm-assert iterable $value * * @param mixed $value * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allFloat($value, $message = '') { @@ -331,14 +348,15 @@ public static function allFloat($value, $message = '') /** * @psalm-pure + * * @psalm-assert iterable $value * * @param mixed $value * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allNullOrFloat($value, $message = '') { @@ -351,14 +369,15 @@ public static function allNullOrFloat($value, $message = '') /** * @psalm-pure + * * @psalm-assert numeric|null $value * * @param mixed $value * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function nullOrNumeric($value, $message = '') { @@ -367,14 +386,15 @@ public static function nullOrNumeric($value, $message = '') /** * @psalm-pure + * * @psalm-assert iterable $value * * @param mixed $value * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allNumeric($value, $message = '') { @@ -387,14 +407,15 @@ public static function allNumeric($value, $message = '') /** * @psalm-pure + * * @psalm-assert iterable $value * * @param mixed $value * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allNullOrNumeric($value, $message = '') { @@ -407,14 +428,15 @@ public static function allNullOrNumeric($value, $message = '') /** * @psalm-pure + * * @psalm-assert positive-int|0|null $value * * @param mixed $value * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function nullOrNatural($value, $message = '') { @@ -423,14 +445,15 @@ public static function nullOrNatural($value, $message = '') /** * @psalm-pure + * * @psalm-assert iterable $value * * @param mixed $value * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allNatural($value, $message = '') { @@ -443,14 +466,15 @@ public static function allNatural($value, $message = '') /** * @psalm-pure + * * @psalm-assert iterable $value * * @param mixed $value * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allNullOrNatural($value, $message = '') { @@ -463,14 +487,15 @@ public static function allNullOrNatural($value, $message = '') /** * @psalm-pure + * * @psalm-assert bool|null $value * * @param mixed $value * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function nullOrBoolean($value, $message = '') { @@ -479,14 +504,15 @@ public static function nullOrBoolean($value, $message = '') /** * @psalm-pure + * * @psalm-assert iterable $value * * @param mixed $value * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allBoolean($value, $message = '') { @@ -499,14 +525,15 @@ public static function allBoolean($value, $message = '') /** * @psalm-pure + * * @psalm-assert iterable $value * * @param mixed $value * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allNullOrBoolean($value, $message = '') { @@ -519,14 +546,15 @@ public static function allNullOrBoolean($value, $message = '') /** * @psalm-pure + * * @psalm-assert scalar|null $value * * @param mixed $value * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function nullOrScalar($value, $message = '') { @@ -535,14 +563,15 @@ public static function nullOrScalar($value, $message = '') /** * @psalm-pure + * * @psalm-assert iterable $value * * @param mixed $value * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allScalar($value, $message = '') { @@ -555,14 +584,15 @@ public static function allScalar($value, $message = '') /** * @psalm-pure + * * @psalm-assert iterable $value * * @param mixed $value * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allNullOrScalar($value, $message = '') { @@ -575,14 +605,15 @@ public static function allNullOrScalar($value, $message = '') /** * @psalm-pure + * * @psalm-assert object|null $value * * @param mixed $value * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function nullOrObject($value, $message = '') { @@ -591,14 +622,15 @@ public static function nullOrObject($value, $message = '') /** * @psalm-pure + * * @psalm-assert iterable $value * * @param mixed $value * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allObject($value, $message = '') { @@ -611,14 +643,15 @@ public static function allObject($value, $message = '') /** * @psalm-pure + * * @psalm-assert iterable $value * * @param mixed $value * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allNullOrObject($value, $message = '') { @@ -631,15 +664,16 @@ public static function allNullOrObject($value, $message = '') /** * @psalm-pure + * * @psalm-assert resource|null $value * * @param mixed $value * @param string|null $type type of resource this should be. @see https://www.php.net/manual/en/function.get-resource-type.php * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function nullOrResource($value, $type = null, $message = '') { @@ -648,15 +682,16 @@ public static function nullOrResource($value, $type = null, $message = '') /** * @psalm-pure + * * @psalm-assert iterable $value * * @param mixed $value * @param string|null $type type of resource this should be. @see https://www.php.net/manual/en/function.get-resource-type.php * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allResource($value, $type = null, $message = '') { @@ -669,15 +704,16 @@ public static function allResource($value, $type = null, $message = '') /** * @psalm-pure + * * @psalm-assert iterable $value * * @param mixed $value * @param string|null $type type of resource this should be. @see https://www.php.net/manual/en/function.get-resource-type.php * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allNullOrResource($value, $type = null, $message = '') { @@ -690,14 +726,15 @@ public static function allNullOrResource($value, $type = null, $message = '') /** * @psalm-pure + * * @psalm-assert callable|null $value * * @param mixed $value * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function nullOrIsCallable($value, $message = '') { @@ -706,14 +743,15 @@ public static function nullOrIsCallable($value, $message = '') /** * @psalm-pure + * * @psalm-assert iterable $value * * @param mixed $value * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allIsCallable($value, $message = '') { @@ -726,14 +764,15 @@ public static function allIsCallable($value, $message = '') /** * @psalm-pure + * * @psalm-assert iterable $value * * @param mixed $value * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allNullOrIsCallable($value, $message = '') { @@ -746,14 +785,15 @@ public static function allNullOrIsCallable($value, $message = '') /** * @psalm-pure + * * @psalm-assert array|null $value * * @param mixed $value * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function nullOrIsArray($value, $message = '') { @@ -762,14 +802,15 @@ public static function nullOrIsArray($value, $message = '') /** * @psalm-pure + * * @psalm-assert iterable $value * * @param mixed $value * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allIsArray($value, $message = '') { @@ -782,14 +823,15 @@ public static function allIsArray($value, $message = '') /** * @psalm-pure + * * @psalm-assert iterable $value * * @param mixed $value * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allNullOrIsArray($value, $message = '') { @@ -802,6 +844,7 @@ public static function allNullOrIsArray($value, $message = '') /** * @psalm-pure + * * @psalm-assert iterable|null $value * * @deprecated use "isIterable" or "isInstanceOf" instead @@ -809,9 +852,9 @@ public static function allNullOrIsArray($value, $message = '') * @param mixed $value * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function nullOrIsTraversable($value, $message = '') { @@ -820,6 +863,7 @@ public static function nullOrIsTraversable($value, $message = '') /** * @psalm-pure + * * @psalm-assert iterable $value * * @deprecated use "isIterable" or "isInstanceOf" instead @@ -827,9 +871,9 @@ public static function nullOrIsTraversable($value, $message = '') * @param mixed $value * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allIsTraversable($value, $message = '') { @@ -842,6 +886,7 @@ public static function allIsTraversable($value, $message = '') /** * @psalm-pure + * * @psalm-assert iterable $value * * @deprecated use "isIterable" or "isInstanceOf" instead @@ -849,9 +894,9 @@ public static function allIsTraversable($value, $message = '') * @param mixed $value * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allNullOrIsTraversable($value, $message = '') { @@ -864,14 +909,15 @@ public static function allNullOrIsTraversable($value, $message = '') /** * @psalm-pure + * * @psalm-assert array|ArrayAccess|null $value * * @param mixed $value * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function nullOrIsArrayAccessible($value, $message = '') { @@ -880,14 +926,15 @@ public static function nullOrIsArrayAccessible($value, $message = '') /** * @psalm-pure + * * @psalm-assert iterable $value * * @param mixed $value * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allIsArrayAccessible($value, $message = '') { @@ -900,14 +947,15 @@ public static function allIsArrayAccessible($value, $message = '') /** * @psalm-pure + * * @psalm-assert iterable $value * * @param mixed $value * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allNullOrIsArrayAccessible($value, $message = '') { @@ -920,14 +968,15 @@ public static function allNullOrIsArrayAccessible($value, $message = '') /** * @psalm-pure + * * @psalm-assert countable|null $value * * @param mixed $value * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function nullOrIsCountable($value, $message = '') { @@ -936,14 +985,15 @@ public static function nullOrIsCountable($value, $message = '') /** * @psalm-pure + * * @psalm-assert iterable $value * * @param mixed $value * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allIsCountable($value, $message = '') { @@ -956,14 +1006,15 @@ public static function allIsCountable($value, $message = '') /** * @psalm-pure + * * @psalm-assert iterable $value * * @param mixed $value * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allNullOrIsCountable($value, $message = '') { @@ -976,14 +1027,15 @@ public static function allNullOrIsCountable($value, $message = '') /** * @psalm-pure + * * @psalm-assert iterable|null $value * * @param mixed $value * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function nullOrIsIterable($value, $message = '') { @@ -992,14 +1044,15 @@ public static function nullOrIsIterable($value, $message = '') /** * @psalm-pure + * * @psalm-assert iterable $value * * @param mixed $value * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allIsIterable($value, $message = '') { @@ -1012,14 +1065,15 @@ public static function allIsIterable($value, $message = '') /** * @psalm-pure + * * @psalm-assert iterable $value * * @param mixed $value * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allNullOrIsIterable($value, $message = '') { @@ -1032,6 +1086,7 @@ public static function allNullOrIsIterable($value, $message = '') /** * @psalm-pure + * * @psalm-template ExpectedType of object * @psalm-param class-string $class * @psalm-assert ExpectedType|null $value @@ -1040,9 +1095,9 @@ public static function allNullOrIsIterable($value, $message = '') * @param string|object $class * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function nullOrIsInstanceOf($value, $class, $message = '') { @@ -1051,6 +1106,7 @@ public static function nullOrIsInstanceOf($value, $class, $message = '') /** * @psalm-pure + * * @psalm-template ExpectedType of object * @psalm-param class-string $class * @psalm-assert iterable $value @@ -1059,9 +1115,9 @@ public static function nullOrIsInstanceOf($value, $class, $message = '') * @param string|object $class * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allIsInstanceOf($value, $class, $message = '') { @@ -1074,6 +1130,7 @@ public static function allIsInstanceOf($value, $class, $message = '') /** * @psalm-pure + * * @psalm-template ExpectedType of object * @psalm-param class-string $class * @psalm-assert iterable $value @@ -1082,9 +1139,9 @@ public static function allIsInstanceOf($value, $class, $message = '') * @param string|object $class * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allNullOrIsInstanceOf($value, $class, $message = '') { @@ -1097,6 +1154,7 @@ public static function allNullOrIsInstanceOf($value, $class, $message = '') /** * @psalm-pure + * * @psalm-template ExpectedType of object * @psalm-param class-string $class * @@ -1104,9 +1162,9 @@ public static function allNullOrIsInstanceOf($value, $class, $message = '') * @param string|object $class * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function nullOrNotInstanceOf($value, $class, $message = '') { @@ -1115,6 +1173,7 @@ public static function nullOrNotInstanceOf($value, $class, $message = '') /** * @psalm-pure + * * @psalm-template ExpectedType of object * @psalm-param class-string $class * @@ -1122,9 +1181,9 @@ public static function nullOrNotInstanceOf($value, $class, $message = '') * @param string|object $class * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allNotInstanceOf($value, $class, $message = '') { @@ -1137,6 +1196,7 @@ public static function allNotInstanceOf($value, $class, $message = '') /** * @psalm-pure + * * @psalm-template ExpectedType of object * @psalm-param class-string $class * @psalm-assert iterable $value @@ -1145,9 +1205,9 @@ public static function allNotInstanceOf($value, $class, $message = '') * @param string|object $class * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allNullOrNotInstanceOf($value, $class, $message = '') { @@ -1160,15 +1220,16 @@ public static function allNullOrNotInstanceOf($value, $class, $message = '') /** * @psalm-pure + * * @psalm-param array $classes * * @param mixed $value * @param array $classes * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function nullOrIsInstanceOfAny($value, $classes, $message = '') { @@ -1177,15 +1238,16 @@ public static function nullOrIsInstanceOfAny($value, $classes, $message = '') /** * @psalm-pure + * * @psalm-param array $classes * * @param mixed $value * @param array $classes * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allIsInstanceOfAny($value, $classes, $message = '') { @@ -1198,15 +1260,16 @@ public static function allIsInstanceOfAny($value, $classes, $message = '') /** * @psalm-pure + * * @psalm-param array $classes * * @param mixed $value * @param array $classes * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allNullOrIsInstanceOfAny($value, $classes, $message = '') { @@ -1219,6 +1282,7 @@ public static function allNullOrIsInstanceOfAny($value, $classes, $message = '') /** * @psalm-pure + * * @psalm-template ExpectedType of object * @psalm-param class-string $class * @psalm-assert ExpectedType|class-string|null $value @@ -1227,9 +1291,9 @@ public static function allNullOrIsInstanceOfAny($value, $classes, $message = '') * @param string $class * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function nullOrIsAOf($value, $class, $message = '') { @@ -1238,6 +1302,7 @@ public static function nullOrIsAOf($value, $class, $message = '') /** * @psalm-pure + * * @psalm-template ExpectedType of object * @psalm-param class-string $class * @psalm-assert iterable> $value @@ -1246,9 +1311,9 @@ public static function nullOrIsAOf($value, $class, $message = '') * @param string $class * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allIsAOf($value, $class, $message = '') { @@ -1261,6 +1326,7 @@ public static function allIsAOf($value, $class, $message = '') /** * @psalm-pure + * * @psalm-template ExpectedType of object * @psalm-param class-string $class * @psalm-assert iterable|null> $value @@ -1269,9 +1335,9 @@ public static function allIsAOf($value, $class, $message = '') * @param string $class * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allNullOrIsAOf($value, $class, $message = '') { @@ -1284,6 +1350,7 @@ public static function allNullOrIsAOf($value, $class, $message = '') /** * @psalm-pure + * * @psalm-template UnexpectedType of object * @psalm-param class-string $class * @@ -1291,9 +1358,9 @@ public static function allNullOrIsAOf($value, $class, $message = '') * @param string $class * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function nullOrIsNotA($value, $class, $message = '') { @@ -1302,6 +1369,7 @@ public static function nullOrIsNotA($value, $class, $message = '') /** * @psalm-pure + * * @psalm-template UnexpectedType of object * @psalm-param class-string $class * @@ -1309,9 +1377,9 @@ public static function nullOrIsNotA($value, $class, $message = '') * @param string $class * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allIsNotA($value, $class, $message = '') { @@ -1324,6 +1392,7 @@ public static function allIsNotA($value, $class, $message = '') /** * @psalm-pure + * * @psalm-template UnexpectedType of object * @psalm-param class-string $class * @psalm-assert iterable $value @@ -1333,9 +1402,9 @@ public static function allIsNotA($value, $class, $message = '') * @param string $class * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allNullOrIsNotA($value, $class, $message = '') { @@ -1348,15 +1417,16 @@ public static function allNullOrIsNotA($value, $class, $message = '') /** * @psalm-pure + * * @psalm-param array $classes * * @param object|string|null $value * @param string[] $classes * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function nullOrIsAnyOf($value, $classes, $message = '') { @@ -1365,15 +1435,16 @@ public static function nullOrIsAnyOf($value, $classes, $message = '') /** * @psalm-pure + * * @psalm-param array $classes * * @param iterable $value * @param string[] $classes * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allIsAnyOf($value, $classes, $message = '') { @@ -1386,15 +1457,16 @@ public static function allIsAnyOf($value, $classes, $message = '') /** * @psalm-pure + * * @psalm-param array $classes * * @param iterable $value * @param string[] $classes * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allNullOrIsAnyOf($value, $classes, $message = '') { @@ -1407,14 +1479,15 @@ public static function allNullOrIsAnyOf($value, $classes, $message = '') /** * @psalm-pure + * * @psalm-assert empty $value * * @param mixed $value * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function nullOrIsEmpty($value, $message = '') { @@ -1423,14 +1496,15 @@ public static function nullOrIsEmpty($value, $message = '') /** * @psalm-pure + * * @psalm-assert iterable $value * * @param mixed $value * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allIsEmpty($value, $message = '') { @@ -1443,14 +1517,15 @@ public static function allIsEmpty($value, $message = '') /** * @psalm-pure + * * @psalm-assert iterable $value * * @param mixed $value * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allNullOrIsEmpty($value, $message = '') { @@ -1467,9 +1542,9 @@ public static function allNullOrIsEmpty($value, $message = '') * @param mixed $value * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function nullOrNotEmpty($value, $message = '') { @@ -1482,9 +1557,9 @@ public static function nullOrNotEmpty($value, $message = '') * @param mixed $value * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allNotEmpty($value, $message = '') { @@ -1497,14 +1572,15 @@ public static function allNotEmpty($value, $message = '') /** * @psalm-pure + * * @psalm-assert iterable $value * * @param mixed $value * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allNullOrNotEmpty($value, $message = '') { @@ -1517,14 +1593,15 @@ public static function allNullOrNotEmpty($value, $message = '') /** * @psalm-pure + * * @psalm-assert iterable $value * * @param mixed $value * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allNull($value, $message = '') { @@ -1541,9 +1618,9 @@ public static function allNull($value, $message = '') * @param mixed $value * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allNotNull($value, $message = '') { @@ -1556,14 +1633,15 @@ public static function allNotNull($value, $message = '') /** * @psalm-pure + * * @psalm-assert true|null $value * * @param mixed $value * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function nullOrTrue($value, $message = '') { @@ -1572,14 +1650,15 @@ public static function nullOrTrue($value, $message = '') /** * @psalm-pure + * * @psalm-assert iterable $value * * @param mixed $value * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allTrue($value, $message = '') { @@ -1592,14 +1671,15 @@ public static function allTrue($value, $message = '') /** * @psalm-pure + * * @psalm-assert iterable $value * * @param mixed $value * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allNullOrTrue($value, $message = '') { @@ -1612,14 +1692,15 @@ public static function allNullOrTrue($value, $message = '') /** * @psalm-pure + * * @psalm-assert false|null $value * * @param mixed $value * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function nullOrFalse($value, $message = '') { @@ -1628,14 +1709,15 @@ public static function nullOrFalse($value, $message = '') /** * @psalm-pure + * * @psalm-assert iterable $value * * @param mixed $value * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allFalse($value, $message = '') { @@ -1648,14 +1730,15 @@ public static function allFalse($value, $message = '') /** * @psalm-pure + * * @psalm-assert iterable $value * * @param mixed $value * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allNullOrFalse($value, $message = '') { @@ -1672,9 +1755,9 @@ public static function allNullOrFalse($value, $message = '') * @param mixed $value * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function nullOrNotFalse($value, $message = '') { @@ -1687,9 +1770,9 @@ public static function nullOrNotFalse($value, $message = '') * @param mixed $value * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allNotFalse($value, $message = '') { @@ -1702,14 +1785,15 @@ public static function allNotFalse($value, $message = '') /** * @psalm-pure + * * @psalm-assert iterable $value * * @param mixed $value * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allNullOrNotFalse($value, $message = '') { @@ -1724,9 +1808,9 @@ public static function allNullOrNotFalse($value, $message = '') * @param mixed $value * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function nullOrIp($value, $message = '') { @@ -1737,9 +1821,9 @@ public static function nullOrIp($value, $message = '') * @param mixed $value * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allIp($value, $message = '') { @@ -1754,9 +1838,9 @@ public static function allIp($value, $message = '') * @param mixed $value * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allNullOrIp($value, $message = '') { @@ -1771,9 +1855,9 @@ public static function allNullOrIp($value, $message = '') * @param mixed $value * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function nullOrIpv4($value, $message = '') { @@ -1784,9 +1868,9 @@ public static function nullOrIpv4($value, $message = '') * @param mixed $value * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allIpv4($value, $message = '') { @@ -1801,9 +1885,9 @@ public static function allIpv4($value, $message = '') * @param mixed $value * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allNullOrIpv4($value, $message = '') { @@ -1818,9 +1902,9 @@ public static function allNullOrIpv4($value, $message = '') * @param mixed $value * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function nullOrIpv6($value, $message = '') { @@ -1831,9 +1915,9 @@ public static function nullOrIpv6($value, $message = '') * @param mixed $value * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allIpv6($value, $message = '') { @@ -1848,9 +1932,9 @@ public static function allIpv6($value, $message = '') * @param mixed $value * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allNullOrIpv6($value, $message = '') { @@ -1865,9 +1949,9 @@ public static function allNullOrIpv6($value, $message = '') * @param mixed $value * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function nullOrEmail($value, $message = '') { @@ -1878,9 +1962,9 @@ public static function nullOrEmail($value, $message = '') * @param mixed $value * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allEmail($value, $message = '') { @@ -1895,9 +1979,9 @@ public static function allEmail($value, $message = '') * @param mixed $value * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allNullOrEmail($value, $message = '') { @@ -1912,9 +1996,9 @@ public static function allNullOrEmail($value, $message = '') * @param array|null $values * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function nullOrUniqueValues($values, $message = '') { @@ -1925,9 +2009,9 @@ public static function nullOrUniqueValues($values, $message = '') * @param iterable $values * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allUniqueValues($values, $message = '') { @@ -1942,9 +2026,9 @@ public static function allUniqueValues($values, $message = '') * @param iterable $values * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allNullOrUniqueValues($values, $message = '') { @@ -1960,9 +2044,9 @@ public static function allNullOrUniqueValues($values, $message = '') * @param mixed $expect * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function nullOrEq($value, $expect, $message = '') { @@ -1974,9 +2058,9 @@ public static function nullOrEq($value, $expect, $message = '') * @param mixed $expect * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allEq($value, $expect, $message = '') { @@ -1992,9 +2076,9 @@ public static function allEq($value, $expect, $message = '') * @param mixed $expect * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allNullOrEq($value, $expect, $message = '') { @@ -2010,9 +2094,9 @@ public static function allNullOrEq($value, $expect, $message = '') * @param mixed $expect * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function nullOrNotEq($value, $expect, $message = '') { @@ -2024,9 +2108,9 @@ public static function nullOrNotEq($value, $expect, $message = '') * @param mixed $expect * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allNotEq($value, $expect, $message = '') { @@ -2042,9 +2126,9 @@ public static function allNotEq($value, $expect, $message = '') * @param mixed $expect * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allNullOrNotEq($value, $expect, $message = '') { @@ -2062,9 +2146,9 @@ public static function allNullOrNotEq($value, $expect, $message = '') * @param mixed $expect * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function nullOrSame($value, $expect, $message = '') { @@ -2078,9 +2162,9 @@ public static function nullOrSame($value, $expect, $message = '') * @param mixed $expect * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allSame($value, $expect, $message = '') { @@ -2098,9 +2182,9 @@ public static function allSame($value, $expect, $message = '') * @param mixed $expect * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allNullOrSame($value, $expect, $message = '') { @@ -2118,9 +2202,9 @@ public static function allNullOrSame($value, $expect, $message = '') * @param mixed $expect * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function nullOrNotSame($value, $expect, $message = '') { @@ -2134,9 +2218,9 @@ public static function nullOrNotSame($value, $expect, $message = '') * @param mixed $expect * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allNotSame($value, $expect, $message = '') { @@ -2154,9 +2238,9 @@ public static function allNotSame($value, $expect, $message = '') * @param mixed $expect * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allNullOrNotSame($value, $expect, $message = '') { @@ -2174,9 +2258,9 @@ public static function allNullOrNotSame($value, $expect, $message = '') * @param mixed $limit * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function nullOrGreaterThan($value, $limit, $message = '') { @@ -2190,9 +2274,9 @@ public static function nullOrGreaterThan($value, $limit, $message = '') * @param mixed $limit * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allGreaterThan($value, $limit, $message = '') { @@ -2210,9 +2294,9 @@ public static function allGreaterThan($value, $limit, $message = '') * @param mixed $limit * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allNullOrGreaterThan($value, $limit, $message = '') { @@ -2230,9 +2314,9 @@ public static function allNullOrGreaterThan($value, $limit, $message = '') * @param mixed $limit * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function nullOrGreaterThanEq($value, $limit, $message = '') { @@ -2246,9 +2330,9 @@ public static function nullOrGreaterThanEq($value, $limit, $message = '') * @param mixed $limit * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allGreaterThanEq($value, $limit, $message = '') { @@ -2266,9 +2350,9 @@ public static function allGreaterThanEq($value, $limit, $message = '') * @param mixed $limit * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allNullOrGreaterThanEq($value, $limit, $message = '') { @@ -2286,9 +2370,9 @@ public static function allNullOrGreaterThanEq($value, $limit, $message = '') * @param mixed $limit * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function nullOrLessThan($value, $limit, $message = '') { @@ -2302,9 +2386,9 @@ public static function nullOrLessThan($value, $limit, $message = '') * @param mixed $limit * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allLessThan($value, $limit, $message = '') { @@ -2322,9 +2406,9 @@ public static function allLessThan($value, $limit, $message = '') * @param mixed $limit * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allNullOrLessThan($value, $limit, $message = '') { @@ -2342,9 +2426,9 @@ public static function allNullOrLessThan($value, $limit, $message = '') * @param mixed $limit * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function nullOrLessThanEq($value, $limit, $message = '') { @@ -2358,9 +2442,9 @@ public static function nullOrLessThanEq($value, $limit, $message = '') * @param mixed $limit * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allLessThanEq($value, $limit, $message = '') { @@ -2378,9 +2462,9 @@ public static function allLessThanEq($value, $limit, $message = '') * @param mixed $limit * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allNullOrLessThanEq($value, $limit, $message = '') { @@ -2399,9 +2483,9 @@ public static function allNullOrLessThanEq($value, $limit, $message = '') * @param mixed $max * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function nullOrRange($value, $min, $max, $message = '') { @@ -2416,9 +2500,9 @@ public static function nullOrRange($value, $min, $max, $message = '') * @param mixed $max * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allRange($value, $min, $max, $message = '') { @@ -2437,9 +2521,9 @@ public static function allRange($value, $min, $max, $message = '') * @param mixed $max * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allNullOrRange($value, $min, $max, $message = '') { @@ -2457,9 +2541,9 @@ public static function allNullOrRange($value, $min, $max, $message = '') * @param array $values * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function nullOrOneOf($value, $values, $message = '') { @@ -2473,9 +2557,9 @@ public static function nullOrOneOf($value, $values, $message = '') * @param array $values * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allOneOf($value, $values, $message = '') { @@ -2493,9 +2577,9 @@ public static function allOneOf($value, $values, $message = '') * @param array $values * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allNullOrOneOf($value, $values, $message = '') { @@ -2513,9 +2597,9 @@ public static function allNullOrOneOf($value, $values, $message = '') * @param array $values * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function nullOrInArray($value, $values, $message = '') { @@ -2529,9 +2613,9 @@ public static function nullOrInArray($value, $values, $message = '') * @param array $values * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allInArray($value, $values, $message = '') { @@ -2549,9 +2633,9 @@ public static function allInArray($value, $values, $message = '') * @param array $values * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allNullOrInArray($value, $values, $message = '') { @@ -2569,9 +2653,9 @@ public static function allNullOrInArray($value, $values, $message = '') * @param string $subString * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function nullOrContains($value, $subString, $message = '') { @@ -2585,9 +2669,9 @@ public static function nullOrContains($value, $subString, $message = '') * @param string $subString * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allContains($value, $subString, $message = '') { @@ -2605,9 +2689,9 @@ public static function allContains($value, $subString, $message = '') * @param string $subString * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allNullOrContains($value, $subString, $message = '') { @@ -2625,9 +2709,9 @@ public static function allNullOrContains($value, $subString, $message = '') * @param string $subString * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function nullOrNotContains($value, $subString, $message = '') { @@ -2641,9 +2725,9 @@ public static function nullOrNotContains($value, $subString, $message = '') * @param string $subString * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allNotContains($value, $subString, $message = '') { @@ -2661,9 +2745,9 @@ public static function allNotContains($value, $subString, $message = '') * @param string $subString * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allNullOrNotContains($value, $subString, $message = '') { @@ -2680,9 +2764,9 @@ public static function allNullOrNotContains($value, $subString, $message = '') * @param string|null $value * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function nullOrNotWhitespaceOnly($value, $message = '') { @@ -2695,9 +2779,9 @@ public static function nullOrNotWhitespaceOnly($value, $message = '') * @param iterable $value * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allNotWhitespaceOnly($value, $message = '') { @@ -2714,9 +2798,9 @@ public static function allNotWhitespaceOnly($value, $message = '') * @param iterable $value * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allNullOrNotWhitespaceOnly($value, $message = '') { @@ -2734,9 +2818,9 @@ public static function allNullOrNotWhitespaceOnly($value, $message = '') * @param string $prefix * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function nullOrStartsWith($value, $prefix, $message = '') { @@ -2750,9 +2834,9 @@ public static function nullOrStartsWith($value, $prefix, $message = '') * @param string $prefix * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allStartsWith($value, $prefix, $message = '') { @@ -2770,9 +2854,9 @@ public static function allStartsWith($value, $prefix, $message = '') * @param string $prefix * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allNullOrStartsWith($value, $prefix, $message = '') { @@ -2790,9 +2874,9 @@ public static function allNullOrStartsWith($value, $prefix, $message = '') * @param string $prefix * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function nullOrNotStartsWith($value, $prefix, $message = '') { @@ -2806,9 +2890,9 @@ public static function nullOrNotStartsWith($value, $prefix, $message = '') * @param string $prefix * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allNotStartsWith($value, $prefix, $message = '') { @@ -2826,9 +2910,9 @@ public static function allNotStartsWith($value, $prefix, $message = '') * @param string $prefix * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allNullOrNotStartsWith($value, $prefix, $message = '') { @@ -2845,9 +2929,9 @@ public static function allNullOrNotStartsWith($value, $prefix, $message = '') * @param mixed $value * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function nullOrStartsWithLetter($value, $message = '') { @@ -2860,9 +2944,9 @@ public static function nullOrStartsWithLetter($value, $message = '') * @param mixed $value * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allStartsWithLetter($value, $message = '') { @@ -2879,9 +2963,9 @@ public static function allStartsWithLetter($value, $message = '') * @param mixed $value * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allNullOrStartsWithLetter($value, $message = '') { @@ -2899,9 +2983,9 @@ public static function allNullOrStartsWithLetter($value, $message = '') * @param string $suffix * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function nullOrEndsWith($value, $suffix, $message = '') { @@ -2915,9 +2999,9 @@ public static function nullOrEndsWith($value, $suffix, $message = '') * @param string $suffix * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allEndsWith($value, $suffix, $message = '') { @@ -2935,9 +3019,9 @@ public static function allEndsWith($value, $suffix, $message = '') * @param string $suffix * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allNullOrEndsWith($value, $suffix, $message = '') { @@ -2955,9 +3039,9 @@ public static function allNullOrEndsWith($value, $suffix, $message = '') * @param string $suffix * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function nullOrNotEndsWith($value, $suffix, $message = '') { @@ -2971,9 +3055,9 @@ public static function nullOrNotEndsWith($value, $suffix, $message = '') * @param string $suffix * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allNotEndsWith($value, $suffix, $message = '') { @@ -2991,9 +3075,9 @@ public static function allNotEndsWith($value, $suffix, $message = '') * @param string $suffix * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allNullOrNotEndsWith($value, $suffix, $message = '') { @@ -3011,9 +3095,9 @@ public static function allNullOrNotEndsWith($value, $suffix, $message = '') * @param string $pattern * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function nullOrRegex($value, $pattern, $message = '') { @@ -3027,9 +3111,9 @@ public static function nullOrRegex($value, $pattern, $message = '') * @param string $pattern * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allRegex($value, $pattern, $message = '') { @@ -3047,9 +3131,9 @@ public static function allRegex($value, $pattern, $message = '') * @param string $pattern * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allNullOrRegex($value, $pattern, $message = '') { @@ -3067,9 +3151,9 @@ public static function allNullOrRegex($value, $pattern, $message = '') * @param string $pattern * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function nullOrNotRegex($value, $pattern, $message = '') { @@ -3083,9 +3167,9 @@ public static function nullOrNotRegex($value, $pattern, $message = '') * @param string $pattern * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allNotRegex($value, $pattern, $message = '') { @@ -3103,9 +3187,9 @@ public static function allNotRegex($value, $pattern, $message = '') * @param string $pattern * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allNullOrNotRegex($value, $pattern, $message = '') { @@ -3122,9 +3206,9 @@ public static function allNullOrNotRegex($value, $pattern, $message = '') * @param mixed $value * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function nullOrUnicodeLetters($value, $message = '') { @@ -3137,9 +3221,9 @@ public static function nullOrUnicodeLetters($value, $message = '') * @param mixed $value * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allUnicodeLetters($value, $message = '') { @@ -3156,9 +3240,9 @@ public static function allUnicodeLetters($value, $message = '') * @param mixed $value * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allNullOrUnicodeLetters($value, $message = '') { @@ -3175,9 +3259,9 @@ public static function allNullOrUnicodeLetters($value, $message = '') * @param mixed $value * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function nullOrAlpha($value, $message = '') { @@ -3190,9 +3274,9 @@ public static function nullOrAlpha($value, $message = '') * @param mixed $value * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allAlpha($value, $message = '') { @@ -3209,9 +3293,9 @@ public static function allAlpha($value, $message = '') * @param mixed $value * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allNullOrAlpha($value, $message = '') { @@ -3228,9 +3312,9 @@ public static function allNullOrAlpha($value, $message = '') * @param string|null $value * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function nullOrDigits($value, $message = '') { @@ -3243,9 +3327,9 @@ public static function nullOrDigits($value, $message = '') * @param iterable $value * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allDigits($value, $message = '') { @@ -3262,9 +3346,9 @@ public static function allDigits($value, $message = '') * @param iterable $value * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allNullOrDigits($value, $message = '') { @@ -3281,9 +3365,9 @@ public static function allNullOrDigits($value, $message = '') * @param string|null $value * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function nullOrAlnum($value, $message = '') { @@ -3296,9 +3380,9 @@ public static function nullOrAlnum($value, $message = '') * @param iterable $value * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allAlnum($value, $message = '') { @@ -3315,9 +3399,9 @@ public static function allAlnum($value, $message = '') * @param iterable $value * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allNullOrAlnum($value, $message = '') { @@ -3330,14 +3414,15 @@ public static function allNullOrAlnum($value, $message = '') /** * @psalm-pure + * * @psalm-assert lowercase-string|null $value * * @param string|null $value * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function nullOrLower($value, $message = '') { @@ -3346,14 +3431,15 @@ public static function nullOrLower($value, $message = '') /** * @psalm-pure + * * @psalm-assert iterable $value * * @param iterable $value * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allLower($value, $message = '') { @@ -3366,14 +3452,15 @@ public static function allLower($value, $message = '') /** * @psalm-pure + * * @psalm-assert iterable $value * * @param iterable $value * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allNullOrLower($value, $message = '') { @@ -3390,9 +3477,9 @@ public static function allNullOrLower($value, $message = '') * @param string|null $value * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function nullOrUpper($value, $message = '') { @@ -3405,9 +3492,9 @@ public static function nullOrUpper($value, $message = '') * @param iterable $value * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allUpper($value, $message = '') { @@ -3420,14 +3507,15 @@ public static function allUpper($value, $message = '') /** * @psalm-pure + * * @psalm-assert iterable $value * * @param iterable $value * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allNullOrUpper($value, $message = '') { @@ -3445,9 +3533,9 @@ public static function allNullOrUpper($value, $message = '') * @param int $length * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function nullOrLength($value, $length, $message = '') { @@ -3461,9 +3549,9 @@ public static function nullOrLength($value, $length, $message = '') * @param int $length * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allLength($value, $length, $message = '') { @@ -3481,9 +3569,9 @@ public static function allLength($value, $length, $message = '') * @param int $length * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allNullOrLength($value, $length, $message = '') { @@ -3501,9 +3589,9 @@ public static function allNullOrLength($value, $length, $message = '') * @param int|float $min * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function nullOrMinLength($value, $min, $message = '') { @@ -3517,9 +3605,9 @@ public static function nullOrMinLength($value, $min, $message = '') * @param int|float $min * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allMinLength($value, $min, $message = '') { @@ -3537,9 +3625,9 @@ public static function allMinLength($value, $min, $message = '') * @param int|float $min * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allNullOrMinLength($value, $min, $message = '') { @@ -3557,9 +3645,9 @@ public static function allNullOrMinLength($value, $min, $message = '') * @param int|float $max * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function nullOrMaxLength($value, $max, $message = '') { @@ -3573,9 +3661,9 @@ public static function nullOrMaxLength($value, $max, $message = '') * @param int|float $max * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allMaxLength($value, $max, $message = '') { @@ -3593,9 +3681,9 @@ public static function allMaxLength($value, $max, $message = '') * @param int|float $max * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allNullOrMaxLength($value, $max, $message = '') { @@ -3614,9 +3702,9 @@ public static function allNullOrMaxLength($value, $max, $message = '') * @param int|float $max * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function nullOrLengthBetween($value, $min, $max, $message = '') { @@ -3631,9 +3719,9 @@ public static function nullOrLengthBetween($value, $min, $max, $message = '') * @param int|float $max * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allLengthBetween($value, $min, $max, $message = '') { @@ -3652,9 +3740,9 @@ public static function allLengthBetween($value, $min, $max, $message = '') * @param int|float $max * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allNullOrLengthBetween($value, $min, $max, $message = '') { @@ -3669,9 +3757,9 @@ public static function allNullOrLengthBetween($value, $min, $max, $message = '') * @param mixed $value * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function nullOrFileExists($value, $message = '') { @@ -3682,9 +3770,9 @@ public static function nullOrFileExists($value, $message = '') * @param mixed $value * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allFileExists($value, $message = '') { @@ -3699,9 +3787,9 @@ public static function allFileExists($value, $message = '') * @param mixed $value * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allNullOrFileExists($value, $message = '') { @@ -3716,9 +3804,9 @@ public static function allNullOrFileExists($value, $message = '') * @param mixed $value * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function nullOrFile($value, $message = '') { @@ -3729,9 +3817,9 @@ public static function nullOrFile($value, $message = '') * @param mixed $value * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allFile($value, $message = '') { @@ -3746,9 +3834,9 @@ public static function allFile($value, $message = '') * @param mixed $value * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allNullOrFile($value, $message = '') { @@ -3763,9 +3851,9 @@ public static function allNullOrFile($value, $message = '') * @param mixed $value * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function nullOrDirectory($value, $message = '') { @@ -3776,9 +3864,9 @@ public static function nullOrDirectory($value, $message = '') * @param mixed $value * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allDirectory($value, $message = '') { @@ -3793,9 +3881,9 @@ public static function allDirectory($value, $message = '') * @param mixed $value * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allNullOrDirectory($value, $message = '') { @@ -3810,9 +3898,9 @@ public static function allNullOrDirectory($value, $message = '') * @param string|null $value * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function nullOrReadable($value, $message = '') { @@ -3823,9 +3911,9 @@ public static function nullOrReadable($value, $message = '') * @param iterable $value * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allReadable($value, $message = '') { @@ -3840,9 +3928,9 @@ public static function allReadable($value, $message = '') * @param iterable $value * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allNullOrReadable($value, $message = '') { @@ -3857,9 +3945,9 @@ public static function allNullOrReadable($value, $message = '') * @param string|null $value * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function nullOrWritable($value, $message = '') { @@ -3870,9 +3958,9 @@ public static function nullOrWritable($value, $message = '') * @param iterable $value * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allWritable($value, $message = '') { @@ -3887,9 +3975,9 @@ public static function allWritable($value, $message = '') * @param iterable $value * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allNullOrWritable($value, $message = '') { @@ -3906,9 +3994,9 @@ public static function allNullOrWritable($value, $message = '') * @param mixed $value * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function nullOrClassExists($value, $message = '') { @@ -3921,9 +4009,9 @@ public static function nullOrClassExists($value, $message = '') * @param mixed $value * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allClassExists($value, $message = '') { @@ -3940,9 +4028,9 @@ public static function allClassExists($value, $message = '') * @param mixed $value * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allNullOrClassExists($value, $message = '') { @@ -3955,6 +4043,7 @@ public static function allNullOrClassExists($value, $message = '') /** * @psalm-pure + * * @psalm-template ExpectedType of object * @psalm-param class-string $class * @psalm-assert class-string|ExpectedType|null $value @@ -3963,9 +4052,9 @@ public static function allNullOrClassExists($value, $message = '') * @param string|object $class * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function nullOrSubclassOf($value, $class, $message = '') { @@ -3974,6 +4063,7 @@ public static function nullOrSubclassOf($value, $class, $message = '') /** * @psalm-pure + * * @psalm-template ExpectedType of object * @psalm-param class-string $class * @psalm-assert iterable|ExpectedType> $value @@ -3982,9 +4072,9 @@ public static function nullOrSubclassOf($value, $class, $message = '') * @param string|object $class * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allSubclassOf($value, $class, $message = '') { @@ -3997,6 +4087,7 @@ public static function allSubclassOf($value, $class, $message = '') /** * @psalm-pure + * * @psalm-template ExpectedType of object * @psalm-param class-string $class * @psalm-assert iterable|ExpectedType|null> $value @@ -4005,9 +4096,9 @@ public static function allSubclassOf($value, $class, $message = '') * @param string|object $class * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allNullOrSubclassOf($value, $class, $message = '') { @@ -4024,9 +4115,9 @@ public static function allNullOrSubclassOf($value, $class, $message = '') * @param mixed $value * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function nullOrInterfaceExists($value, $message = '') { @@ -4037,11 +4128,11 @@ public static function nullOrInterfaceExists($value, $message = '') * @psalm-assert iterable $value * * @param mixed $value - * @param string $message - * - * @throws InvalidArgumentException + * @param string $message * * @return void + * + * @throws InvalidArgumentException */ public static function allInterfaceExists($value, $message = '') { @@ -4058,9 +4149,9 @@ public static function allInterfaceExists($value, $message = '') * @param mixed $value * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allNullOrInterfaceExists($value, $message = '') { @@ -4073,17 +4164,18 @@ public static function allNullOrInterfaceExists($value, $message = '') /** * @psalm-pure + * * @psalm-template ExpectedType of object * @psalm-param class-string $interface - * @psalm-assert class-string|null $value + * @psalm-assert class-string|ExpectedType|null $value * * @param mixed $value * @param mixed $interface * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function nullOrImplementsInterface($value, $interface, $message = '') { @@ -4092,17 +4184,18 @@ public static function nullOrImplementsInterface($value, $interface, $message = /** * @psalm-pure + * * @psalm-template ExpectedType of object * @psalm-param class-string $interface - * @psalm-assert iterable> $value + * @psalm-assert iterable|ExpectedType> $value * * @param mixed $value * @param mixed $interface * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allImplementsInterface($value, $interface, $message = '') { @@ -4115,17 +4208,18 @@ public static function allImplementsInterface($value, $interface, $message = '') /** * @psalm-pure + * * @psalm-template ExpectedType of object * @psalm-param class-string $interface - * @psalm-assert iterable|null> $value + * @psalm-assert iterable|ExpectedType|null> $value * * @param mixed $value * @param mixed $interface * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allNullOrImplementsInterface($value, $interface, $message = '') { @@ -4138,15 +4232,16 @@ public static function allNullOrImplementsInterface($value, $interface, $message /** * @psalm-pure + * * @psalm-param class-string|object|null $classOrObject * * @param string|object|null $classOrObject * @param mixed $property * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function nullOrPropertyExists($classOrObject, $property, $message = '') { @@ -4155,15 +4250,16 @@ public static function nullOrPropertyExists($classOrObject, $property, $message /** * @psalm-pure + * * @psalm-param iterable $classOrObject * * @param iterable $classOrObject * @param mixed $property * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allPropertyExists($classOrObject, $property, $message = '') { @@ -4176,15 +4272,16 @@ public static function allPropertyExists($classOrObject, $property, $message = ' /** * @psalm-pure + * * @psalm-param iterable $classOrObject * * @param iterable $classOrObject * @param mixed $property * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allNullOrPropertyExists($classOrObject, $property, $message = '') { @@ -4197,15 +4294,16 @@ public static function allNullOrPropertyExists($classOrObject, $property, $messa /** * @psalm-pure + * * @psalm-param class-string|object|null $classOrObject * * @param string|object|null $classOrObject * @param mixed $property * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function nullOrPropertyNotExists($classOrObject, $property, $message = '') { @@ -4214,15 +4312,16 @@ public static function nullOrPropertyNotExists($classOrObject, $property, $messa /** * @psalm-pure + * * @psalm-param iterable $classOrObject * * @param iterable $classOrObject * @param mixed $property * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allPropertyNotExists($classOrObject, $property, $message = '') { @@ -4235,15 +4334,16 @@ public static function allPropertyNotExists($classOrObject, $property, $message /** * @psalm-pure + * * @psalm-param iterable $classOrObject * * @param iterable $classOrObject * @param mixed $property * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allNullOrPropertyNotExists($classOrObject, $property, $message = '') { @@ -4256,15 +4356,16 @@ public static function allNullOrPropertyNotExists($classOrObject, $property, $me /** * @psalm-pure + * * @psalm-param class-string|object|null $classOrObject * * @param string|object|null $classOrObject * @param mixed $method * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function nullOrMethodExists($classOrObject, $method, $message = '') { @@ -4273,15 +4374,16 @@ public static function nullOrMethodExists($classOrObject, $method, $message = '' /** * @psalm-pure + * * @psalm-param iterable $classOrObject * * @param iterable $classOrObject * @param mixed $method * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allMethodExists($classOrObject, $method, $message = '') { @@ -4294,15 +4396,16 @@ public static function allMethodExists($classOrObject, $method, $message = '') /** * @psalm-pure + * * @psalm-param iterable $classOrObject * * @param iterable $classOrObject * @param mixed $method * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allNullOrMethodExists($classOrObject, $method, $message = '') { @@ -4315,15 +4418,16 @@ public static function allNullOrMethodExists($classOrObject, $method, $message = /** * @psalm-pure + * * @psalm-param class-string|object|null $classOrObject * * @param string|object|null $classOrObject * @param mixed $method * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function nullOrMethodNotExists($classOrObject, $method, $message = '') { @@ -4332,15 +4436,16 @@ public static function nullOrMethodNotExists($classOrObject, $method, $message = /** * @psalm-pure + * * @psalm-param iterable $classOrObject * * @param iterable $classOrObject * @param mixed $method * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allMethodNotExists($classOrObject, $method, $message = '') { @@ -4353,15 +4458,16 @@ public static function allMethodNotExists($classOrObject, $method, $message = '' /** * @psalm-pure + * * @psalm-param iterable $classOrObject * * @param iterable $classOrObject * @param mixed $method * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allNullOrMethodNotExists($classOrObject, $method, $message = '') { @@ -4379,9 +4485,9 @@ public static function allNullOrMethodNotExists($classOrObject, $method, $messag * @param string|int $key * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function nullOrKeyExists($array, $key, $message = '') { @@ -4395,9 +4501,9 @@ public static function nullOrKeyExists($array, $key, $message = '') * @param string|int $key * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allKeyExists($array, $key, $message = '') { @@ -4415,9 +4521,9 @@ public static function allKeyExists($array, $key, $message = '') * @param string|int $key * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allNullOrKeyExists($array, $key, $message = '') { @@ -4435,9 +4541,9 @@ public static function allNullOrKeyExists($array, $key, $message = '') * @param string|int $key * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function nullOrKeyNotExists($array, $key, $message = '') { @@ -4451,9 +4557,9 @@ public static function nullOrKeyNotExists($array, $key, $message = '') * @param string|int $key * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allKeyNotExists($array, $key, $message = '') { @@ -4471,9 +4577,9 @@ public static function allKeyNotExists($array, $key, $message = '') * @param string|int $key * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allNullOrKeyNotExists($array, $key, $message = '') { @@ -4486,14 +4592,15 @@ public static function allNullOrKeyNotExists($array, $key, $message = '') /** * @psalm-pure + * * @psalm-assert array-key|null $value * * @param mixed $value * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function nullOrValidArrayKey($value, $message = '') { @@ -4502,14 +4609,15 @@ public static function nullOrValidArrayKey($value, $message = '') /** * @psalm-pure + * * @psalm-assert iterable $value * * @param mixed $value * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allValidArrayKey($value, $message = '') { @@ -4522,14 +4630,15 @@ public static function allValidArrayKey($value, $message = '') /** * @psalm-pure + * * @psalm-assert iterable $value * * @param mixed $value * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allNullOrValidArrayKey($value, $message = '') { @@ -4545,9 +4654,9 @@ public static function allNullOrValidArrayKey($value, $message = '') * @param int $number * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function nullOrCount($array, $number, $message = '') { @@ -4559,9 +4668,9 @@ public static function nullOrCount($array, $number, $message = '') * @param int $number * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allCount($array, $number, $message = '') { @@ -4577,9 +4686,9 @@ public static function allCount($array, $number, $message = '') * @param int $number * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allNullOrCount($array, $number, $message = '') { @@ -4595,9 +4704,9 @@ public static function allNullOrCount($array, $number, $message = '') * @param int|float $min * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function nullOrMinCount($array, $min, $message = '') { @@ -4609,9 +4718,9 @@ public static function nullOrMinCount($array, $min, $message = '') * @param int|float $min * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allMinCount($array, $min, $message = '') { @@ -4627,9 +4736,9 @@ public static function allMinCount($array, $min, $message = '') * @param int|float $min * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allNullOrMinCount($array, $min, $message = '') { @@ -4645,9 +4754,9 @@ public static function allNullOrMinCount($array, $min, $message = '') * @param int|float $max * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function nullOrMaxCount($array, $max, $message = '') { @@ -4659,9 +4768,9 @@ public static function nullOrMaxCount($array, $max, $message = '') * @param int|float $max * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allMaxCount($array, $max, $message = '') { @@ -4677,9 +4786,9 @@ public static function allMaxCount($array, $max, $message = '') * @param int|float $max * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allNullOrMaxCount($array, $max, $message = '') { @@ -4696,9 +4805,9 @@ public static function allNullOrMaxCount($array, $max, $message = '') * @param int|float $max * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function nullOrCountBetween($array, $min, $max, $message = '') { @@ -4711,9 +4820,9 @@ public static function nullOrCountBetween($array, $min, $max, $message = '') * @param int|float $max * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allCountBetween($array, $min, $max, $message = '') { @@ -4730,9 +4839,9 @@ public static function allCountBetween($array, $min, $max, $message = '') * @param int|float $max * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allNullOrCountBetween($array, $min, $max, $message = '') { @@ -4745,14 +4854,15 @@ public static function allNullOrCountBetween($array, $min, $max, $message = '') /** * @psalm-pure + * * @psalm-assert list|null $array * * @param mixed $array * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function nullOrIsList($array, $message = '') { @@ -4761,14 +4871,15 @@ public static function nullOrIsList($array, $message = '') /** * @psalm-pure + * * @psalm-assert iterable $array * * @param mixed $array * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allIsList($array, $message = '') { @@ -4781,14 +4892,15 @@ public static function allIsList($array, $message = '') /** * @psalm-pure + * * @psalm-assert iterable $array * * @param mixed $array * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allNullOrIsList($array, $message = '') { @@ -4801,14 +4913,15 @@ public static function allNullOrIsList($array, $message = '') /** * @psalm-pure + * * @psalm-assert non-empty-list|null $array * * @param mixed $array * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function nullOrIsNonEmptyList($array, $message = '') { @@ -4817,14 +4930,15 @@ public static function nullOrIsNonEmptyList($array, $message = '') /** * @psalm-pure + * * @psalm-assert iterable $array * * @param mixed $array * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allIsNonEmptyList($array, $message = '') { @@ -4837,14 +4951,15 @@ public static function allIsNonEmptyList($array, $message = '') /** * @psalm-pure + * * @psalm-assert iterable $array * * @param mixed $array * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allNullOrIsNonEmptyList($array, $message = '') { @@ -4857,6 +4972,7 @@ public static function allNullOrIsNonEmptyList($array, $message = '') /** * @psalm-pure + * * @psalm-template T * @psalm-param mixed|array|null $array * @psalm-assert array|null $array @@ -4864,9 +4980,9 @@ public static function allNullOrIsNonEmptyList($array, $message = '') * @param mixed $array * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function nullOrIsMap($array, $message = '') { @@ -4875,6 +4991,7 @@ public static function nullOrIsMap($array, $message = '') /** * @psalm-pure + * * @psalm-template T * @psalm-param iterable> $array * @psalm-assert iterable> $array @@ -4882,9 +4999,9 @@ public static function nullOrIsMap($array, $message = '') * @param mixed $array * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allIsMap($array, $message = '') { @@ -4897,6 +5014,7 @@ public static function allIsMap($array, $message = '') /** * @psalm-pure + * * @psalm-template T * @psalm-param iterable|null> $array * @psalm-assert iterable|null> $array @@ -4904,9 +5022,9 @@ public static function allIsMap($array, $message = '') * @param mixed $array * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allNullOrIsMap($array, $message = '') { @@ -4919,15 +5037,16 @@ public static function allNullOrIsMap($array, $message = '') /** * @psalm-pure + * * @psalm-template T * @psalm-param mixed|array|null $array * * @param mixed $array * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function nullOrIsNonEmptyMap($array, $message = '') { @@ -4936,15 +5055,16 @@ public static function nullOrIsNonEmptyMap($array, $message = '') /** * @psalm-pure + * * @psalm-template T * @psalm-param iterable> $array * * @param mixed $array * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allIsNonEmptyMap($array, $message = '') { @@ -4957,6 +5077,7 @@ public static function allIsNonEmptyMap($array, $message = '') /** * @psalm-pure + * * @psalm-template T * @psalm-param iterable|null> $array * @psalm-assert iterable|null> $array @@ -4965,9 +5086,9 @@ public static function allIsNonEmptyMap($array, $message = '') * @param mixed $array * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allNullOrIsNonEmptyMap($array, $message = '') { @@ -4984,9 +5105,9 @@ public static function allNullOrIsNonEmptyMap($array, $message = '') * @param string|null $value * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function nullOrUuid($value, $message = '') { @@ -4999,9 +5120,9 @@ public static function nullOrUuid($value, $message = '') * @param iterable $value * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allUuid($value, $message = '') { @@ -5018,9 +5139,9 @@ public static function allUuid($value, $message = '') * @param iterable $value * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allNullOrUuid($value, $message = '') { @@ -5038,9 +5159,9 @@ public static function allNullOrUuid($value, $message = '') * @param string $class * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function nullOrThrows($expression, $class = 'Exception', $message = '') { @@ -5054,9 +5175,9 @@ public static function nullOrThrows($expression, $class = 'Exception', $message * @param string $class * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allThrows($expression, $class = 'Exception', $message = '') { @@ -5074,9 +5195,9 @@ public static function allThrows($expression, $class = 'Exception', $message = ' * @param string $class * @param string $message * - * @throws InvalidArgumentException - * * @return void + * + * @throws InvalidArgumentException */ public static function allNullOrThrows($expression, $class = 'Exception', $message = '') { diff --git a/vendor/y0lk/oauth1-etsy/LICENSE.md b/vendor/y0lk/oauth1-etsy/LICENSE.md deleted file mode 100644 index a86a4053f..000000000 --- a/vendor/y0lk/oauth1-etsy/LICENSE.md +++ /dev/null @@ -1,22 +0,0 @@ - -The MIT License (MIT) - -Copyright (c) 2016 Gabriel Jean - -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. diff --git a/vendor/y0lk/oauth1-etsy/README.md b/vendor/y0lk/oauth1-etsy/README.md deleted file mode 100644 index bb306a037..000000000 --- a/vendor/y0lk/oauth1-etsy/README.md +++ /dev/null @@ -1,37 +0,0 @@ -# Etsy Provider for OAuth 1.0 Client - -[![Latest Stable Version](https://img.shields.io/packagist/v/y0lk/oauth1-etsy.svg)](https://packagist.org/packages/y0lk/oauth1-etsy) -[![Build Status](https://img.shields.io/travis/Y0lk/oauth1-etsy.svg)](https://travis-ci.org/Y0lk/oauth1-etsy) -[![License](https://img.shields.io/packagist/l/y0lk/oauth1-etsy.svg)](https://github.com/y0lk/oauth1-etsy/blob/master/LICENSE) -[![Total Downloads](https://img.shields.io/packagist/dt/y0lk/oauth1-etsy.svg?maxAge=2592000)](https://packagist.org/packages/y0lk/oauth1-etsy) - -This package provides Etsy API OAuth 1.0 support for the PHP League's [OAuth 1.0 Client](https://github.com/thephpleague/oauth1-client). - -## Installation - -Via Composer - -```shell -$ composer require y0lk/oauth1-etsy -``` - -## Usage - -Usage is the same as The League's OAuth client, using `Y0lk\OAuth1\Client\Server\Etsy` as the provider. - -```php -$server = new Y0lk\OAuth1\Client\Server\Etsy([ - 'identifier' => 'your-client-id', - 'secret' => 'your-client-secret', - 'scope' => '', //See Etsy documentation for the full list of permission scopes - 'callback_uri' => 'http://callback.url/callback' -]); -``` - -### Permission Scopes -See the Etsy documentation for [Permission Scopes](https://www.etsy.com/developers/documentation/getting_started/oauth#section_permission_scopes) - - -## License - -The MIT License (MIT). Please see [License File](https://github.com/thephpleague/oauth1-client/blob/master/LICENSE) for more information. diff --git a/vendor/y0lk/oauth1-etsy/phpunit.xml b/vendor/y0lk/oauth1-etsy/phpunit.xml deleted file mode 100644 index 340cc3d18..000000000 --- a/vendor/y0lk/oauth1-etsy/phpunit.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - - - ./tests - - - - - ./src/ - - - \ No newline at end of file diff --git a/vendor/y0lk/oauth1-etsy/src/Etsy.php b/vendor/y0lk/oauth1-etsy/src/Etsy.php deleted file mode 100644 index 1ee462147..000000000 --- a/vendor/y0lk/oauth1-etsy/src/Etsy.php +++ /dev/null @@ -1,192 +0,0 @@ -parseConfiguration($clientCredentials); - } - } - - /** - * Set the application scope. - * - * @param string $applicationScope - * - * @return Etsy - */ - public function setApplicationScope($applicationScope) - { - $this->applicationScope = $applicationScope; - return $this; - } - - /** - * Get application scope. - * - * @return string - */ - public function getApplicationScope() - { - return $this->applicationScope; - } - - /** - * {@inheritDoc} - */ - public function urlTemporaryCredentials() - { - return self::API_URL.'oauth/request_token?scope='.$this->applicationScope; - } - /** - * {@inheritDoc} - */ - public function urlAuthorization() - { - return $this->login_url; - } - /** - * {@inheritDoc} - */ - public function urlTokenCredentials() - { - return self::API_URL.'oauth/access_token'; - } - /** - * {@inheritDoc} - */ - public function urlUserDetails() - { - return self::API_URL.'users/__SELF__'; - } - - /** - * {@inheritDoc} - */ - public function userDetails($data, TokenCredentials $tokenCredentials) - { - $data = $data['results'][0]; - - $user = new User(); - $user->uid = $data['user_id']; - $user->nickname = $data['login_name']; - - $used = array('user_id', 'login_name'); - - // Save all extra data - $user->extra = array_diff_key($data, array_flip($used)); - return $user; - } - - /** - * {@inheritDoc} - */ - public function userUid($data, TokenCredentials $tokenCredentials) - { - return $data['user']['user_id']; - } - - /** - * {@inheritDoc} - */ - public function userEmail($data, TokenCredentials $tokenCredentials) - { - return; - } - - /** - * {@inheritDoc} - */ - public function userScreenName($data, TokenCredentials $tokenCredentials) - { - return $data['user']['login_name']; - } - - /** - * Parse configuration array to set attributes. - * - * @param array $configuration - */ - private function parseConfiguration(array $configuration = array()) - { - $configToPropertyMap = array( - 'scope' => 'applicationScope' - ); - foreach ($configToPropertyMap as $config => $property) { - if (isset($configuration[$config])) { - $this->$property = $configuration[$config]; - } - } - } - - /** - * {@inheritDoc} - */ - public function getTemporaryCredentials() - { - $uri = $this->urlTemporaryCredentials(); - - $client = $this->createHttpClient(); - - $header = $this->temporaryCredentialsProtocolHeader($uri); - $authorizationHeader = array('Authorization' => $header); - $headers = $this->buildHttpClientHeaders($authorizationHeader); - - try { - $response = $client->post($uri, [ - 'headers' => $headers - ]); - } catch (BadResponseException $e) { - return $this->handleTemporaryCredentialsBadResponse($e); - } - - //Catch body and retrieve Etsy login_url - $body = $response->getBody(); - parse_str($body, $data); - - $this->login_url = $data['login_url']; - - return $this->createTemporaryCredentials($response->getBody()); - } - - /** - * {@inheritDoc} - */ - public function getAuthorizationUrl($temporaryIdentifier, array $options = []) - { - // Somebody can pass through an instance of temporary - // credentials and we'll extract the identifier from there. - if ($temporaryIdentifier instanceof TemporaryCredentials) { - $temporaryIdentifier = $temporaryIdentifier->getIdentifier(); - } - - //Return the authorization url directly since it's provided by Etsy and contains all parameters - return $this->urlAuthorization(); - } -} \ No newline at end of file diff --git a/www/api/index.php b/www/api/index.php index c981d19ae..a2ed25675 100644 --- a/www/api/index.php +++ b/www/api/index.php @@ -3,7 +3,6 @@ ini_set('display_errors', false); error_reporting(E_ERROR); -require dirname(dirname(__DIR__)) . '/xentral_autoloader.php'; require dirname(dirname(__DIR__)) . '/vendor/autoload.php'; define('DEBUG_MODE', false); diff --git a/www/docscan/upload.php b/www/docscan/upload.php index 29b4f12e1..2ebe00296 100644 --- a/www/docscan/upload.php +++ b/www/docscan/upload.php @@ -6,7 +6,6 @@ use Sabre\DAV\Locks\Plugin; use Sabre\DAV\Server; -include_once dirname(dirname(__DIR__)) . '/xentral_autoloader.php'; require_once dirname(dirname(__DIR__)) . '/vendor/autoload.php'; /* diff --git a/www/eproosystem.php b/www/eproosystem.php index 0c50f5bcb..63931c6a4 100644 --- a/www/eproosystem.php +++ b/www/eproosystem.php @@ -60,18 +60,16 @@ class erpooSystem extends Application * @var Config $Conf */ - public function __construct($config,$group='') + public function __construct($config) { $this->uselaendercache = false; - parent::__construct($config, $group); + parent::__construct($config); if(WithGUI()){ $module = $this->Secure->GetGET('module'); $action = $this->Secure->GetGET('action'); $this->Tpl->Set('DASHBOARDLINK', 'index.php?module=welcome&action=start'); - $this->help = new Help($this); - $companyletter = strtoupper(substr($this->erp->Firmendaten('name'), 0, 1)); $this->Tpl->Set('COMPANYLETTER', ($companyletter != '' ? $companyletter : 'W')); @@ -112,7 +110,6 @@ public function __construct($config,$group='') $this->Tpl->Set('JSSCRIPTS', ''); } } - $this->erp->PrinterIcon(); $this->Tpl->ReadTemplatesFromPath(__DIR__ . '/widgets/templates/_gen/'); $this->Tpl->ReadTemplatesFromPath(__DIR__ . '/widgets/templates/'); $this->Tpl->ReadTemplatesFromPath(__DIR__ . '/themes/' . $this->Conf->WFconf['defaulttheme'] . '/templates/'); @@ -122,14 +119,6 @@ public function __construct($config,$group='') $this->Tpl->ReadTemplatesFromPath(__DIR__ . '/lib/versandarten/content/'); } - if(method_exists($this->erp, 'VersionsInfos')){ - $ver = $this->erp->VersionsInfos(); - if(stripos($ver['Info'], 'Beta') !== false - || stripos($ver['Info'], 'Alpha') !== false - || stripos($ver['Info'], 'DEV') !== false - ) $this->Tpl->Set('VERSIONINFO', strtoupper($ver['Info'])); - } - $this->Tpl->Set('ID', $this->Secure->GetGET('id')); $this->Tpl->Set('POPUPWIDTH', '1200'); $this->Tpl->Set('POPUPHEIGHT', '800'); @@ -170,23 +159,6 @@ public function __construct($config,$group='') $layout_iconbar = $this->erp->Firmendaten('layout_iconbar'); - if($this->erp->Version() === 'stock'){ - $this->Tpl->Set('STOCKOPEN', ''); - } - - //nur wenn leiste nicht deaktiviert ist - if($layout_iconbar != 1){ - if($this->erp->Firmendaten('iconset_dunkel') == '1'){ - $this->Tpl->Parse('ICONBAR', 'iconbar_dunkel.tpl'); - } - else{ - $this->Tpl->Parse('ICONBAR', 'iconbar.tpl'); - } - }else{ - $this->Tpl->Parse('ICONBAR', 'iconbar_empty.tpl'); - } - if($module !== 'kalender' && ($module !== 'welcome' && $action !== 'start')){ $this->Tpl->Add('YUICSS', '.ui-widget-content {}'); } @@ -218,7 +190,6 @@ public function __construct($config,$group='') $this->Tpl->Set('THEME', $this->Conf->WFconf['defaulttheme']); $doc_root = preg_replace("!{$_SERVER['SCRIPT_NAME']}$!", '', $_SERVER['SCRIPT_FILENAME']); # ex: /var/www $path = preg_replace("!^{$doc_root}!", '', __DIR__); - $this->Tpl->Set('WEBPATH', $path); if(isset($backlink) && strpos($backlink,"index.php?module=") !== false && strpos($backlink, "&action=") !== false){ $this->Tpl->Set('TABSBACK', $backlink); @@ -232,8 +203,6 @@ public function __construct($config,$group='') } $this->Tpl->Set('SAVEBUTTON', ''); - $this->help->Run(); - $this->Tpl->Set('TMPSCRIPT', ''); $msg2 = $this->Secure->GetGET('msg'); @@ -269,23 +238,6 @@ public function __construct($config,$group='') $this->Tpl->Set('LIZENZHINWEIS', '| Lizenzhinweis'); - if($this->erp->Version() === 'OSS'){ - $this->Tpl->Set('WAWIVERSION', 'Open-Source Lizenz AGPLv3.0'); - } - else if($this->erp->Version() === 'ENT'){ - $this->Tpl->Set('WAWIVERSION', 'Enterprise Version'); - } - else if($this->erp->Version() === 'PRO'){ - $this->Tpl->Set('WAWIVERSION', 'Professional Version'); - } - else if($this->erp->Version() === 'PRE'){ - $this->Tpl->Set('WAWIVERSION', 'Premium Version'); - } - else{ - $this->Tpl->Set('WAWIVERSION', 'Nutzungsbedingungen'); - } - - $this->Tpl->Set('TIMESTAMP', time()); $this->Tpl->Set('THEME', $this->Conf->WFconf['defaulttheme']); @@ -342,10 +294,6 @@ public function getSVG($path, $filename){ return file_get_contents($iconPath); } - protected function getCounterFor(string $type) - { - - } /** * creates and appends sidebar navigation */ @@ -1785,7 +1733,7 @@ public function GetLaender($sprache='deutsch') if($sprache!=='deutsch' && $sprache!=='englisch'){ $sprache = 'deutsch'; } - + if($sprache==='deutsch'){ if(empty($this->uselaendercache) || empty($this->laendercache['deutsch'])){ $tmp = $this->DB->SelectArr('SELECT bezeichnung_de,iso FROM laender ORDER by bezeichnung_de'); @@ -1817,7 +1765,7 @@ public function GetLaender($sprache='deutsch') } return $laender; } - + $laender = array( 'Afghanistan' => 'AF', 'Ägypten' => 'EG', diff --git a/www/index.php b/www/index.php index 6f9f81aa7..a0d72036a 100644 --- a/www/index.php +++ b/www/index.php @@ -20,7 +20,7 @@ if(file_exists(dirname(__DIR__).'/phpwf/plugins/class.devtools.php'))include_once(dirname(__DIR__).'/phpwf/plugins/class.devtools.php'); -include_once (dirname(__DIR__).'/xentral_autoloader.php'); +require_once (dirname(__DIR__).'/vendor/autoload.php'); if(!isset($_GET['module']) || $_GET['module'] != 'api') { @@ -37,12 +37,9 @@ $errorHandler = new ErrorHandler(); $errorHandler->register(); -include("eproosystem.php"); - if(!is_file(dirname(dirname($_SERVER['SCRIPT_FILENAME'])).DIRECTORY_SEPARATOR."conf/user.inc.php")) header('Location: ./setup/setup.php'); else { -include(dirname(dirname($_SERVER['SCRIPT_FILENAME'])).DIRECTORY_SEPARATOR."/conf/main.conf.php"); try { $config = ConfigLoader::load(); } catch (MultiDbConfigNotFoundException $exception) { @@ -53,11 +50,9 @@ $app = new erpooSystem($config); // layer 2 -> darfst du ueberhaupt? -include("../phpwf/class.session.php"); $session = new Session(); $session->Check($app); // layer 3 -> nur noch abspielen -include("../phpwf/class.player.php"); $player = new Player(); $player->Run($session); } diff --git a/www/lib/class.erpapi.php b/www/lib/class.erpapi.php index 029cc9186..4b52c57e9 100644 --- a/www/lib/class.erpapi.php +++ b/www/lib/class.erpapi.php @@ -69,11 +69,14 @@ class erpAPI /** @var array $appList */ protected $appList = []; + private \Psr\Log\LoggerInterface $logger; + /** @var ApplicationCore $app */ public function __construct($app) { $this->app=$app; + $this->logger = $app->Container->get('Logger'); if(empty($this->app->erp)){ $this->app->erp = $this; } @@ -553,7 +556,7 @@ function LogWithTime($message, $json = false) $peakmemory = number_format(memory_get_peak_usage()/1024.0/1024.0,2); $runtime = number_format($akttime - $this->logtime,3); $runtimeall = number_format($akttime - $this->firstlogtime,3); - $this->LogFile('Time all '.$runtimeall."s last: ".$runtime."s Memakt:".$aktmemory."MB peak:".$peakmemory."MB ".$this->app->DB->real_escape_string( $json?json_encode($message):$message)); + $this->logger->info('Time all '.$runtimeall."s last: ".$runtime."s Memakt:".$aktmemory."MB peak:".$peakmemory."MB ".$this->app->DB->real_escape_string( $json?json_encode($message):$message)); $this->logtime = $akttime; } } @@ -849,11 +852,11 @@ public function NavigationHooks(&$menu) if($v['sec'] !== '' || !isset($first[$v['first']])) { if($v['sec'] == '') { $menu[] = array('first'=>array($v['first'], $v['module'],$v['action'])); - $first[$v['first']] = (!empty($menu)?count($menu):0); + $first[$v['first']] = (!empty($menu)?count($menu):0)-1; } elseif($v['sec'] != '' && !isset($first[$v['first']])){ $menu[] = array('first'=>array($v['first'], '',''),'sec'=>array(array($v['sec'],$v['module'],$v['action']))); - $first[$v['first']] = (!empty($menu)?count($menu):0); + $first[$v['first']] = (!empty($menu)?count($menu):0)-1; } else{ if(isset($menu[$first[$v['first']]])) { @@ -1512,13 +1515,13 @@ function AbgleichBenutzerVorlagen($userid=0, $vorlage = 0, $module = '', $action try { $userPermission->log($grantingUserId,$grantingUserName,$receivingUserId,$receivingUserName,$module,$action,false); }catch (Exception $ex){ - $this->app->erp->LogFile('Fehler bei Zuweisung Rechtehistore',$ex->getMessage()); + $this->logger->error('Fehler bei Zuweisung Rechtehistore',[$ex->getMessage()]); } $this->app->DB->Insert("INSERT INTO userrights (user, module, action, permission) VALUES ('".$user[$i]['id']."','$module','$action','$permission')"); try { $userPermission->log($grantingUserId,$grantingUserName,$receivingUserId,$receivingUserName,$module,$action,true); }catch (Exception $ex){ - $this->app->erp->LogFile('Fehler bei Zuweisung Rechtehistore',$ex->getMessage()); + $this->logger->error('Fehler bei Zuweisung Rechtehistore',[$ex->getMessage()]); } }else{ $permissions = $this->app->DB->SelectArr("SELECT module, action,permission @@ -1527,7 +1530,7 @@ function AbgleichBenutzerVorlagen($userid=0, $vorlage = 0, $module = '', $action try { $userPermission->log($grantingUserId,$grantingUserName,$receivingUserId,$receivingUserName,$permission['module'],$permission['action'],$permission['permission']); }catch (Exception $ex){ - $this->app->erp->LogFile('Fehler bei Zuweisung Rechtehistore',$ex->getMessage()); + $this->logger->error('Fehler bei Zuweisung Rechtehistore',[$ex->getMessage()]); } } $this->app->DB->Update("REPLACE INTO userrights (user, module,action,permission) (SELECT '".$user[$i]['id']."',module, action,permission @@ -2181,7 +2184,7 @@ public function PDFArchivieren($type,$id, $force = false) unlink($tmpfile); $tmpfile = ''; } - $this->LogFile($this->app->DB->real_escape_string($e->getMessage())); + $this->logger->error($this->app->DB->real_escape_string($e->getMessage())); return false; } $this->app->erp->BriefpapierHintergrunddisable = !$this->app->erp->BriefpapierHintergrunddisable; @@ -2197,7 +2200,7 @@ public function PDFArchivieren($type,$id, $force = false) if($tmpfile !== '' && is_file($tmpfile)) { unlink($tmpfile); } - $this->LogFile($this->app->DB->real_escape_string($e->getMessage())); + $this->logger->error($this->app->DB->real_escape_string($e->getMessage())); $this->app->erp->BriefpapierHintergrunddisable = !$this->app->erp->BriefpapierHintergrunddisable; return false; } @@ -3827,35 +3830,6 @@ function ParseFormVars($fields) } } - function LoadZahlungsweiseModul($module, $moduleId) { - - $module = preg_replace('/[^a-zA-Z0-9\_]/','',$module); - - if(empty($module)) { - return null; - } - if(strpos($module,'zahlungsweise_') === 0) { - $module = substr($module, 14); - if(empty($module)) { - return null; - } - } - if(strpos($module, '.') !== false || strpos($module, '/') !== false || strpos($module, '\\')) { - return null; - } - $path = dirname(__DIR__).'/lib/zahlungsweisen/'.$module.'.php'; - if(!is_file($path)) { - return null; - } - - include_once $path ; - $classname = 'Zahlungsweise_'.$module; - if(!class_exists($classname)) { - return null; - } - return new $classname($this->app, $moduleId); - } - // @refactor Document Komponente function Zahlungsweisetext($doctype,$doctypeid) { @@ -3909,16 +3883,28 @@ function Zahlungsweisetext($doctype,$doctypeid) if($zahlungsweiseid['modul'] != '') { - $obj = $this->LoadZahlungsweiseModul($zahlungsweiseid['modul'], $zahlungsweiseid['id']); - if($obj && method_exists($obj, 'GetZahlungsweiseText')) + $zahlungsweiseid['modul'] = preg_replace('/[^a-zA-Z0-9\_]/','',$zahlungsweiseid['modul']); + $pfad = dirname(__DIR__).'/lib/zahlungsweisen/'.$zahlungsweiseid['modul'].'.php'; + if($zahlungsweiseid['modul'] && @is_file($pfad)) { - $zahlungsweisetexttmp = $obj->GetZahlungsweiseText($doctype, $doctypeid); - if($zahlungsweisetexttmp!='') { - if($zahlungsweiseid['modul'] == 'tagxmonat'){ - $zahlungsweisetext = $zahlungsweisetexttmp."\r\n"; - } - else{ - $zahlungsweisetext .= "\r\n".$zahlungsweisetexttmp."\r\n"; + $classname = 'Zahlungsweise_'.$zahlungsweiseid['modul']; + if(!class_exists($classname)){ + include_once($pfad); + } + if(class_exists($classname)) + { + $obj = new $classname($this->app, $zahlungsweiseid['id']); + if($obj && method_exists($obj, 'GetZahlungsweiseText')) + { + $zahlungsweisetexttmp = $obj->GetZahlungsweiseText($doctype, $doctypeid); + if($zahlungsweisetexttmp!='') { + if($zahlungsweiseid['modul'] == 'tagxmonat'){ + $zahlungsweisetext = $zahlungsweisetexttmp."\r\n"; + } + else{ + $zahlungsweisetext .= "\r\n".$zahlungsweisetexttmp."\r\n"; + } + } } } } @@ -6428,14 +6414,6 @@ public function isActionExistsInModule($module, $action) return in_array($action, $actions); } - function fixeUmlaute($text) { - return $this->app->String->fixeUmlaute($text); - } - - function getUmlauteArray() { - return $this->app->String->getUmlauteArray(); - } - /** * @deprecated use directly htmlentities() instead */ @@ -6463,7 +6441,7 @@ function ConvertForDB($string, $htmlentities = true, $isHtmlTransformation = fal function ConvertForTableSearch($string) { - $string = $this->unicode_decode($string); + $string = $this->app->String->unicode_decode($string); $cmd = $this->app->Secure->GetGET('cmd'); if($cmd==='kontoauszuege'){ return trim(html_entity_decode($string, ENT_QUOTES, 'UTF-8')); //uahlungseingang @@ -6478,279 +6456,6 @@ function make_clickable($text) return preg_replace('@(?])\b(?:(?:https?|ftp|file)://|[a-z]\.)[-A-Z0-9+&#/%=~_|$?!:,.]*[A-Z0-9+&#/%=~_|$]@i', '\0', $text); } - // @refactor in WawiString oder HtmlTransformer Klasse - function unicode_decode($content) { - $ISO10646XHTMLTrans = array( - "&"."#34;" => """, - "&"."#38;" => "&", - "&"."#39;" => "'", - "&"."#60;" => "<", - "&"."#62;" => ">", - "&"."#128;" => "€", - "&"."#160;" => "", - "&"."#161;" => "¡", - "&"."#162;" => "¢", - "&"."#163;" => "£", - "&"."#164;" => "¤", - "&"."#165;" => "¥", - "&"."#166;" => "¦", - "&"."#167;" => "§", - "&"."#168;" => "¨", - "&"."#169;" => "©", - "&"."#170;" => "ª", - "&"."#171;" => "«", - "&"."#172;" => "¬", - "&"."#173;" => "­", - "&"."#174;" => "®", - "&"."#175;" => "¯", - "&"."#176;" => "°", - "&"."#177;" => "±", - "&"."#178;" => "²", - "&"."#179;" => "³", - "&"."#180;" => "´", - "&"."#181;" => "µ", - "&"."#182;" => "¶", - "&"."#183;" => "·", - "&"."#184;" => "¸", - "&"."#185;" => "¹", - "&"."#186;" => "º", - "&"."#187;" => "»", - "&"."#188;" => "¼", - "&"."#189;" => "½", - "&"."#190;" => "¾", - "&"."#191;" => "¿", - "&"."#192;" => "À", - "&"."#193;" => "Á", - "&"."#194;" => "Â", - "&"."#195;" => "Ã", - "&"."#196;" => "Ä", - "&"."#197;" => "Å", - "&"."#198;" => "Æ", - "&"."#199;" => "Ç", - "&"."#200;" => "È", - "&"."#201;" => "É", - "&"."#202;" => "Ê", - "&"."#203;" => "Ë", - "&"."#204;" => "Ì", - "&"."#205;" => "Í", - "&"."#206;" => "Î", - "&"."#207;" => "Ï", - "&"."#208;" => "Ð", - "&"."#209;" => "Ñ", - "&"."#210;" => "Ò", - "&"."#211;" => "Ó", - "&"."#212;" => "Ô", - "&"."#213;" => "Õ", - "&"."#214;" => "Ö", - "&"."#215;" => "×", - "&"."#216;" => "Ø", - "&"."#217;" => "Ù", - "&"."#218;" => "Ú", - "&"."#219;" => "Û", - "&"."#220;" => "Ü", - "&"."#221;" => "Ý", - "&"."#222;" => "Þ", - "&"."#223;" => "ß", - "&"."#224;" => "à", - "&"."#225;" => "á", - "&"."#226;" => "â", - "&"."#227;" => "ã", - "&"."#228;" => "ä", - "&"."#229;" => "å", - "&"."#230;" => "æ", - "&"."#231;" => "ç", - "&"."#232;" => "è", - "&"."#233;" => "é", - "&"."#234;" => "ê", - "&"."#235;" => "ë", - "&"."#236;" => "ì", - "&"."#237;" => "í", - "&"."#238;" => "î", - "&"."#239;" => "ï", - "&"."#240;" => "ð", - "&"."#241;" => "ñ", - "&"."#242;" => "ò", - "&"."#243;" => "ó", - "&"."#244;" => "ô", - "&"."#245;" => "õ", - "&"."#246;" => "ö", - "&"."#247;" => "÷", - "&"."#248;" => "ø", - "&"."#249;" => "ù", - "&"."#250;" => "ú", - "&"."#251;" => "û", - "&"."#252;" => "ü", - "&"."#253;" => "ý", - "&"."#254;" => "þ", - "&"."#255;" => "ÿ", - "&"."#338;" => "Œ", - "&"."#339;" => "œ", - "&"."#352;" => "Š", - "&"."#353;" => "š", - "&"."#376;" => "Ÿ", - "&"."#402;" => "ƒ", - "&"."#710;" => "ˆ", - "&"."#732;" => "˜", - "&"."#913;" => "Α", - "&"."#914;" => "Β", - "&"."#915;" => "Γ", - "&"."#916;" => "Δ", - "&"."#917;" => "Ε", - "&"."#918;" => "Ζ", - "&"."#919;" => "Η", - "&"."#920;" => "Θ", - "&"."#921;" => "Ι", - "&"."#922;" => "Κ", - "&"."#923;" => "Λ", - "&"."#924;" => "Μ", - "&"."#925;" => "Ν", - "&"."#926;" => "Ξ", - "&"."#927;" => "Ο", - "&"."#928;" => "Π", - "&"."#929;" => "Ρ", - "&"."#931;" => "Σ", - "&"."#932;" => "Τ", - "&"."#933;" => "Υ", - "&"."#934;" => "Φ", - "&"."#935;" => "Χ", - "&"."#936;" => "Ψ", - "&"."#937;" => "Ω", - "&"."#945;" => "α", - "&"."#946;" => "β", - "&"."#947;" => "γ", - "&"."#948;" => "δ", - "&"."#949;" => "ε", - "&"."#950;" => "ζ", - "&"."#951;" => "η", - "&"."#952;" => "θ", - "&"."#953;" => "ι", - "&"."#954;" => "κ", - "&"."#955;" => "λ", - "&"."#956;" => "μ", - "&"."#957;" => "ν", - "&"."#958;" => "ξ", - "&"."#959;" => "ο", - "&"."#960;" => "π", - "&"."#961;" => "ρ", - "&"."#962;" => "ς", - "&"."#963;" => "σ", - "&"."#964;" => "τ", - "&"."#965;" => "υ", - "&"."#966;" => "φ", - "&"."#967;" => "χ", - "&"."#968;" => "ψ", - "&"."#969;" => "ω", - "&"."#977;" => "ϑ", - "&"."#978;" => "ϒ", - "&"."#982;" => "ϖ", - "&"."#8194;" => " ", - "&"."#8195;" => " ", - "&"."#8201;" => " ", - "&"."#8204;" => "‌", - "&"."#8205;" => "‍", - "&"."#8206;" => "‎", - "&"."#8207;" => "‏", - "&"."#8211;" => "–", - "&"."#8212;" => "—", - "&"."#8216;" => "‘", - "&"."#8217;" => "’", - "&"."#8218;" => "‚", - "&"."#8220;" => "“", - "&"."#8221;" => "”", - "&"."#8222;" => "„", - "&"."#8224;" => "†", - "&"."#8225;" => "‡", - "&"."#8226;" => "•", - "&"."#8230;" => "…", - "&"."#8240;" => "‰", - "&"."#8242;" => "′", - "&"."#8243;" => "″", - "&"."#8249;" => "‹", - "&"."#8250;" => "›", - "&"."#8254;" => "‾", - "&"."#8260;" => "⁄", - "&"."#8364;" => "€", - "&"."#8465;" => "ℑ", - "&"."#8472;" => "℘", - "&"."#8476;" => "ℜ", - "&"."#8482;" => "™", - "&"."#8501;" => "ℵ", - "&"."#8592;" => "←", - "&"."#8593;" => "↑", - "&"."#8594;" => "→", - "&"."#8595;" => "↓", - "&"."#8596;" => "↔", - "&"."#8629;" => "↵", - "&"."#8656;" => "⇐", - "&"."#8657;" => "⇑", - "&"."#8658;" => "⇒", - "&"."#8659;" => "⇓", - "&"."#8660;" => "⇔", - "&"."#8704;" => "∀", - "&"."#8706;" => "∂", - "&"."#8707;" => "∃", - "&"."#8709;" => "∅", - "&"."#8711;" => "∇", - "&"."#8712;" => "∈", - "&"."#8713;" => "∉", - "&"."#8715;" => "∋", - "&"."#8719;" => "∏", - "&"."#8721;" => "∑", - "&"."#8722;" => "−", - "&"."#8727;" => "∗", - "&"."#8730;" => "√", - "&"."#8733;" => "∝", - "&"."#8734;" => "∞", - "&"."#8736;" => "∠", - "&"."#8743;" => "∧", - "&"."#8744;" => "∨", - "&"."#8745;" => "∩", - "&"."#8746;" => "∪", - "&"."#8747;" => "∫", - "&"."#8756;" => "∴", - "&"."#8764;" => "∼", - "&"."#8773;" => "≅", - "&"."#8776;" => "≈", - "&"."#8800;" => "≠", - "&"."#8801;" => "≡", - "&"."#8804;" => "≤", - "&"."#8805;" => "≥", - "&"."#8834;" => "⊂", - "&"."#8835;" => "⊃", - "&"."#8836;" => "⊄", - "&"."#8838;" => "⊆", - "&"."#8839;" => "⊇", - "&"."#8853;" => "⊕", - "&"."#8855;" => "⊗", - "&"."#8869;" => "⊥", - "&"."#8901;" => "⋅", - "&"."#8968;" => "⌈", - "&"."#8969;" => "⌉", - "&"."#8970;" => "⌊", - "&"."#8971;" => "⌋", - "&"."#9001;" => "⟨", - "&"."#9002;" => "⟩", - "&"."#9674;" => "◊", - "&"."#9824;" => "♠", - "&"."#9827;" => "♣", - "&"."#9829;" => "♥", - "&"."#9830;" => "♦" - ); - - - reset($ISO10646XHTMLTrans); -// while(list($UnicodeChar, $XHTMLEquiv) = each($ISO10646XHTMLTrans)) { - foreach($ISO10646XHTMLTrans as $UniccideChar => $XHTMLEquiv) - { - $content = str_replace($UnicodeChar, $XHTMLEquiv, $content); - } - - // $content = html_entity_decode($content, ENT_COMPAT, 'UTF-8'); - - // return translated - return($content); - } - /** @deprecated */ function html_entity_decode_utf8($string) { @@ -15934,7 +15639,23 @@ public function sendPaymentStatus( LIMIT 1 ")){ foreach ($zahlungsweisenmodule as $zahlungsweisenmodul) { - $obj = $this->LoadZahlungsweiseModul($zahlungsweisenmodul['modul'], $zahlungsweisenmodul['id']); + $_zahlungsweisenmodul = preg_replace('/[^a-zA-Z0-9\_]/', '', $zahlungsweisenmodul['modul']); + if(!$_zahlungsweisenmodul){ + continue; + } + if(!file_exists(__DIR__ . '/zahlungsweisen/' . $_zahlungsweisenmodul . '.php')){ + continue; + } + + $class = 'Zahlungsweise_' . $_zahlungsweisenmodul; + if(!class_exists($class)){ + include_once __DIR__ . '/zahlungsweisen/' . $_zahlungsweisenmodul . '.php'; + } + if(!class_exists($class)){ + continue; + } + + $obj = new $class($this->app, $zahlungsweisenmodul['id']); if($obj && method_exists($obj, 'ZahlungFreigeben')){ $obj->ZahlungFreigeben($auftrag, $id); } @@ -16364,24 +16085,6 @@ function VarAsString($variable) return $result; } - function ImportvorlageImport($id = 0, $importvorlage = '', string $file_contents) { - $obj = $this->LoadModul('importvorlage'); - if(!empty($obj) && method_exists($obj, 'ImportvorlageDo')) - { - if (empty($id)) { - $id = $this->app->DB->Select("SELECT id FROM importvorlage WHERE bezeichnung = '".$importvorlage."' LIMIT 1"); - if (empty($id)) { - return(array('success' => false, 'message' => 'Importvorlage nicht gefunden')); - } - } - $tmpdatei = $this->app->erp->GetTMP().'importvorlageimport'.microtime(true); - file_put_contents($tmpdatei, $file_contents); - $result = $obj->ImportvorlageDo(parameter: array('id' => $id, 'stueckliste_csv' => $tmpdatei)); - return($result); - } - return 0; - } - function ImportvorlageLog($importvorlage,$zeitstempel,$tabelle,$datensatz,$ersterdatensatz="0") { $this->app->DB->Insert("INSERT INTO importvorlage_log (id,importvorlage,zeitstempel,user,tabelle,datensatz,ersterdatensatz) @@ -16533,22 +16236,11 @@ function LogRamAndTime($meldung) { if(self::$lasttime == 0)self::$lasttime = microtime(true); $akttime = microtime(true); - $this->LogFile( addslashes((memory_get_peak_usage(true) >> 20). " MB ".(round($akttime - self::$lasttime ,3) )." sek ".$meldung)); + $this->logger->info( addslashes((memory_get_peak_usage(true) >> 20). " MB ".(round($akttime - self::$lasttime ,3) )." sek ".$meldung)); } - function LogFile($meldung,$dump="",$module="",$action="",$functionname="") - { - - $obj = $this->LoadModul('logfile'); - if(!empty($obj) && method_exists($obj,'addLogFile')) { - return $obj->addLogFile($meldung,$dump,$module,$action,$functionname); - } - return null; - } - - function KundeUpdate($adresse,$typ,$name,$abteilung,$unterabteilung,$ansprechpartner,$adresszusatz,$strasse,$land,$plz,$ort,$email,$telefon,$telefax,$ustid,$partner,$projekt) { //echo "Upate"; @@ -16562,8 +16254,8 @@ function KundeUpdate($adresse,$typ,$name,$abteilung,$unterabteilung,$ansprechpar { $val = $this->app->DB->real_escape_string(${$key}); $this->app->DB->Update("UPDATE adresse SET $key='$val' WHERE id='$adresse' LIMIT 1"); - $check = $this->app->DB->real_escape_string($check); - $this->app->DB->Update("UPDATE adresse SET `logfile`=CONCAT(logfile, ' Update Feld $key alt:$check neu:".$val.";') WHERE id='$adresse' LIMIT 1"); + $logfile = $this->app->DB->Select("SELECT `logfile` FROM adresse WHERE id='$adresse' LIMIT 1"); + $this->app->DB->Update("UPDATE adresse SET `logfile`='".$logfile." Update Feld $key alt:$check neu:".$val.";' WHERE id='$adresse' LIMIT 1"); } } @@ -18385,7 +18077,7 @@ function ImportAuftrag($adresse,$warenkorb,$projekt,$shop="",$auftrag=0) : array $rabattpositionen[$ap] = $value['rabatt']; } if(empty($ap)){ - $this->LogFile('Fehler '.$value['articleid']); + $this->logger->error('Fehler '.$value['articleid']); } if(isset($artap)){ unset($artap); @@ -18663,7 +18355,7 @@ function ImportAuftrag($adresse,$warenkorb,$projekt,$shop="",$auftrag=0) : array } } else { $error_msg = 'Importauftrag Shop '.$shop.' Fehler: Kein Portoartikel vorhanden'; - $this->LogFile($error_msg,['Onlinebestellnummer' => $warenkorb['onlinebestellnummer']]); + $this->logger->error($error_msg,['Onlinebestellnummer' => $warenkorb['onlinebestellnummer']]); return(array("status" => false, "message" => $error_msg, "onlinebestellnummer" => $warenkorb['onlinebestellnummer'])); } } @@ -21013,7 +20705,7 @@ public function LagerSync($artikelid, $print_echo=false, $shopByIds = []) $result = $this->app->remote->RemoteSendArticleList($shop, array($lagerartikel[$ij]['id']), array($nummer['nummer']), true); } catch(Exception $e) { - $this->app->erp->LogFile($this->app->DB->real_escape_string('Lagersync Fehler '.$shop.' '.$nummer['nummer'].' '.$e->getMessage())); + $this->logger->error($this->app->DB->real_escape_string('Lagersync Fehler '.$shop.' '.$nummer['nummer'].' '.$e->getMessage())); $anzfehler++; } } @@ -21024,7 +20716,7 @@ public function LagerSync($artikelid, $print_echo=false, $shopByIds = []) $result = $this->app->remote->RemoteSendArticleList($shop,array($lagerartikel[$ij]['id']),!empty($extnummer)? array($extnummer):'',true); } catch(Exception $e) { - $this->app->erp->LogFile($this->app->DB->real_escape_string('Lagersync Fehler '.$shop.' '.(!empty($extnummer)? array($extnummer):$lagerartikel[$ij]['nummer']).' '.$e->getMessage())); + $this->logger->error($this->app->DB->real_escape_string('Lagersync Fehler '.$shop.' '.(!empty($extnummer)? array($extnummer):$lagerartikel[$ij]['nummer']).' '.$e->getMessage())); $anzfehler++; } } @@ -21035,7 +20727,7 @@ public function LagerSync($artikelid, $print_echo=false, $shopByIds = []) } - $this->LogFile('*** UPDATE '.$lagerartikel[$ij]['nummer'].' '.$lagerartikel[$ij]['name_de'].' Shop: '.$shop.' Lagernd: '.$verkaufbare_menge.' Korrektur: '.round((float) ($verkaufbare_menge_korrektur - $verkaufbare_menge),7).' Pseudolager: '.round((float) $pseudolager,8).' Result: '.(is_array($result)?$result['status']:$result), $result); + $this->logger->info('*** UPDATE '.$lagerartikel[$ij]['nummer'].' '.$lagerartikel[$ij]['name_de'].' Shop: '.$shop.' Lagernd: '.$verkaufbare_menge.' Korrektur: '.round((float) ($verkaufbare_menge_korrektur - $verkaufbare_menge),7).' Pseudolager: '.round((float) $pseudolager,8).' Result: '.(is_array($result)?$result['status']:$result), $result); if ((is_array($result) && $result instanceof ArticleExportResult ? $result->success : false) || $result === 1) { $cacheQuantity = (int) $verkaufbare_menge_korrektur + (int) $pseudolager; @@ -25549,7 +25241,7 @@ function MailSendFinal($from,$from_name,$to,$to_name,$betreff,$text,$files="",$p new EmailRecipient($from, $from_name) ); } else { - $this->app->erp->LogFile("Mailer Error: Email could not be composed!"); + $this->logger->error("Mailer Error: Email could not be composed!"); } // Load the mail to IMAP using laminas @@ -25562,7 +25254,7 @@ function MailSendFinal($from,$from_name,$to,$to_name,$betreff,$text,$files="",$p $client->connect(); $client->appendMessage($imapCopyMessage, $account->getImapOutgoingFolder()); } catch (Exception $e) { - $this->app->erp->LogFile("Mailer IMAP Error: " . (string) $e); + $this->logger->error("Mailer IMAP Error: " . (string) $e); if(isset($this->app->User) && $this->app->User && method_exists($this->app->User, 'GetID')) { $this->app->erp->InternesEvent($this->app->User->GetID(),"IMAP-Fehler","alert",1); @@ -30834,7 +30526,7 @@ function AddAuftragPositionNummer($auftrag,$nummer,$menge,$projekt,$nullpreis="" $sprache = $this->app->DB->Select("SELECT sprache FROM $doctype WHERE id='$auftrag' LIMIT 1"); $this->RunHook('AARLGPositionenSprache', 6, $doctype, $auftrag, $artikel, $sprache, $bezeichnunglieferant, $beschreibung); - $this->app->erp->LogFile("Add $nummer,$menge $artikel $sprache Name: $bezeichnunglieferant"); + $this->logger->info("Add $nummer,$menge $artikel $sprache Name: $bezeichnunglieferant"); $verkaufspreisarr = $this->GetVerkaufspreis($artikel, $menge,0,'', $returnwaehrung,true); if($verkaufspreisarr) @@ -37309,20 +37001,6 @@ function GetDateiDatum($id) // MYSQL format $date = $this->app->DB->Select("SELECT datum FROM datei_version WHERE datei='$id' AND version='$version' LIMIT 1"); return ($date); } - - function GetDateiDatumFormat($id) - { - $version = $this->app->DB->Select("SELECT MAX(version) FROM datei_version WHERE datei='$id'"); - $date = $this->app->DB->Select("SELECT ".$this->app->erp->FormatDate("datum")." FROM datei_version WHERE datei='$id' AND version='$version' LIMIT 1"); - return ($date); - } - - function GetDateiDatumZeitFormat($id) - { - $version = $this->app->DB->Select("SELECT MAX(version) FROM datei_version WHERE datei='$id'"); - $date = $this->app->DB->Select("SELECT ".$this->app->erp->FormatDateTime("datum")." FROM datei_version WHERE datei='$id' AND version='$version' LIMIT 1"); - return ($date); - } /* * Retrieve files from stichwoerter and provide them in tmp for access @@ -39604,7 +39282,7 @@ function OpenstreetmapGetLangLat($apikey,$query) $result = curl_exec($ch); if(strpos($result,"404 page not")===false) break; if($timeout > 10) { - $this->app->erp->LogFile("Openstreetmap GetLangLat Timeout: $url"); + $this->logger->warning("Openstreetmap GetLangLat Timeout: $url"); break; } } @@ -39632,7 +39310,7 @@ function OpenstreetmapGetDistance($apikey,$coord1,$coord2) $result = curl_exec($ch); if(strpos($result,"404 page not")===false) break; if($timeout > 10) { - $this->app->erp->LogFile("Openstreetmap Distance Timeout: $url"); + $this->logger->warning("Openstreetmap Distance Timeout: $url"); break; } diff --git a/www/lib/class.help.php b/www/lib/class.help.php deleted file mode 100644 index 1a8ff202f..000000000 --- a/www/lib/class.help.php +++ /dev/null @@ -1,55 +0,0 @@ - -app=$app; - } - - - function Run() - { - $module = ucfirst($this->app->Secure->GetGET("module")); - $action = ucfirst($this->app->Secure->GetGET("action")); - - $methodname = $module.$action; - - if(method_exists($this,$methodname)) - { - $this->app->Tpl->Add('HELP',call_user_func( array( &$this, $methodname ), $this, null )); - } else { - $this->app->Tpl->Set('HELPDISABLEOPEN',""); - } - } - -/* - function AngebotCreate() - { - return "angebot anlegen"; - } - - function AngebotList() - { - return "angebot list"; - } -*/ - - -} - diff --git a/www/lib/dokumente/class.anfrage.php b/www/lib/dokumente/class.anfrage.php index 590cd156f..b0f37404f 100644 --- a/www/lib/dokumente/class.anfrage.php +++ b/www/lib/dokumente/class.anfrage.php @@ -1,4 +1,4 @@ - - - -filename = $this->app->erp->Dateinamen($this->filename); $dir = rtrim($this->app->Conf->WFuserdata, '/') . '/pdfarchiv/' . $this->app->Conf->WFdbname . '/' . $this->table; if(!is_dir($dir) && !mkdir($dir, 0700,true) && !is_dir($dir)){ - $this->app->erp->LogFile('Fehler beim erstellen von '.$dir); + $this->app->Container->get('Logger')->error('Fehler beim erstellen von '.$dir); return; } diff --git a/www/lib/dokumente/class.briefpapier_custom.php b/www/lib/dokumente/class.briefpapier_custom.php new file mode 100644 index 000000000..b2823b99b --- /dev/null +++ b/www/lib/dokumente/class.briefpapier_custom.php @@ -0,0 +1,5 @@ +filename = $this->app->erp->Dateinamen($this->filename); $dir = $this->app->Conf->WFuserdata."/pdfarchiv/".$this->app->Conf->WFdbname; if(!is_dir($dir)){ - if(!mkdir($dir, 0700,true))$this->app->erp->LogFile('Fehler beim erstellen von '.$dir); + if(!mkdir($dir, 0700,true))$this->app->Container->get('Logger')->error('Fehler beim erstellen von '.$dir); // echo "fehlt"; } if(!is_dir($dir))return false; if(!is_dir($dir."/".$this->table)) - if(!mkdir ($dir."/".$this->table,0700,true))$this->app->erp->LogFile('Fehler beim erstellen von '.$dir."/".$this->table); + if(!mkdir ($dir."/".$this->table,0700,true))$this->app->Container->get('Logger')->error('Fehler beim erstellen von '.$dir."/".$this->table); if(!is_dir($dir."/".$this->table))return; $md5alt = false; $altesdokument = $this->app->DB->SelectArr("SELECT * from pdfarchiv where table_id = '".$this->id."' and table_name = '".$this->table."' AND doctype = '".$this->app->DB->real_escape_string($this->doctype)."' AND doctypeorig = '".$this->app->DB->real_escape_string($this->doctypeOrig)."' ORDER BY zeitstempel DESC LIMIT 1"); diff --git a/www/lib/dokumente/class.gutschrift.php b/www/lib/dokumente/class.gutschrift.php index ba321e3d2..a99ec0583 100644 --- a/www/lib/dokumente/class.gutschrift.php +++ b/www/lib/dokumente/class.gutschrift.php @@ -11,15 +11,6 @@ * **** END OF COPYRIGHT & LICENSE NOTICE *** DO NOT REMOVE **** */ -?> - - +*/ +?> filename = $this->app->erp->Dateinamen($this->filename); $dir = $this->app->Conf->WFuserdata."/pdfarchiv/".$this->app->Conf->WFdbname; if(!is_dir($dir)){ - if(!mkdir($dir, 0700,true))$this->app->erp->LogFile('Fehler beim erstellen von '.$dir); + if(!mkdir($dir, 0700,true))$this->app->Container->get('Logger')->error('Fehler beim erstellen von '.$dir); // echo "fehlt"; } if(!is_dir($dir))return false; if(!is_dir($dir."/".$this->table)) - if(!mkdir ($dir."/".$this->table,0700,true))$this->app->erp->LogFile('Fehler beim erstellen von '.$dir."/".$this->table); + if(!mkdir ($dir."/".$this->table,0700,true))$this->app->Container->get('Logger')->error('Fehler beim erstellen von '.$dir."/".$this->table); if(!is_dir($dir."/".$this->table))return; $md5alt = false; $altesdokument = $this->app->DB->SelectArr("SELECT * from pdfarchiv where table_id = '".$this->id."' and table_name = '".$this->table."' AND doctype = '".$this->app->DB->real_escape_string($this->doctype)."' AND doctypeorig = '".$this->app->DB->real_escape_string($this->doctypeOrig)."' ORDER BY zeitstempel DESC LIMIT 1"); diff --git a/www/lib/dokumente/class.lieferschein.php b/www/lib/dokumente/class.lieferschein.php index cdc03f2a3..ec6f52189 100644 --- a/www/lib/dokumente/class.lieferschein.php +++ b/www/lib/dokumente/class.lieferschein.php @@ -1,4 +1,4 @@ - - - - - - - - +*/ +?> protokoll !== self::PROTOCOL_DISABLED){ - $this->app->erp->LogFile($nachricht, $this->app->DB->real_escape_string($dump)); + if ($dump !== null && !is_array($dump)) + $dump = ['dump' => $dump]; + $this->app->Container->get('Logger')->info($nachricht, $dump); } } diff --git a/www/pages/Shopimporter_Gambio_Adapter.php b/www/pages/Shopimporter_Gambio_Adapter.php index 9dd0ff3b6..41fe8d0bb 100644 --- a/www/pages/Shopimporter_Gambio_Adapter.php +++ b/www/pages/Shopimporter_Gambio_Adapter.php @@ -1,4 +1,4 @@ - +*/ +?> protokoll){ - $this->app->erp->LogFile($nachricht, print_r($dump, true)); + if ($dump !== null && !is_array($dump)) + $dump = ['dump' => $dump]; + $this->app->Container->get('Logger')->info($nachricht, $dump); } } diff --git a/www/pages/Shopimporter_Presta_Adapter.php b/www/pages/Shopimporter_Presta_Adapter.php index 2e65ee77b..f6dd27d28 100644 --- a/www/pages/Shopimporter_Presta_Adapter.php +++ b/www/pages/Shopimporter_Presta_Adapter.php @@ -1,4 +1,4 @@ - +*/ +?> protokoll){ - $this->app->erp->LogFile($nachricht, print_r($dump, true)); + if ($dump !== null && !is_array($dump)) + $dump = ['dump' => $dump]; + $this->app->Container->get('Logger')->info($nachricht, $dump); } } diff --git a/www/pages/api.php b/www/pages/api.php index fe1e9d044..b50140f73 100644 --- a/www/pages/api.php +++ b/www/pages/api.php @@ -69,6 +69,8 @@ class Api { /** @var array $bestBeforeBatchArticleStock */ protected $bestBeforeBatchArticleStock; + private \Psr\Log\LoggerInterface $logger; + /** * Api constructor. * @@ -85,6 +87,7 @@ public function __construct($app, $intern = false) { $this->api_id = 0; $this->datei_id = 0; $this->apiAccountService = $this->app->Container->get('ApiAccountService'); + $this->logger = $this->app->Container->get('Logger'); if($intern) { return; @@ -6122,7 +6125,7 @@ public function ParsePartXmlSupplierorderProductionWithoutId($typ, &$xml, $ueber if(!file_exists($pfad)){ if(!mkdir($pfad, 0777, true) && !is_dir($pfad)) { - $this->app->erp->LogFile($pfad.' konnte nicht erstellt werden'); + $this->logger->warning($pfad.' konnte nicht erstellt werden'); } } @@ -6131,7 +6134,7 @@ public function ParsePartXmlSupplierorderProductionWithoutId($typ, &$xml, $ueber if(!file_exists($speicherpfad)) { if(!mkdir($speicherpfad, 0777, true) && !is_dir($speicherpfad)) { - $this->app->erp->LogFile($speicherpfad.' konnte nicht erstellt werden'); + $this->logger->warning($speicherpfad.' konnte nicht erstellt werden'); } } @@ -6872,7 +6875,7 @@ public function ParsePartXmlOrderOfferWithoutId($typ, &$xml, $uebertragungen_acc if(!file_exists($pfad) && !mkdir($pfad, 0777, true) && !is_dir($pfad)) { - $this->app->erp->LogFile($pfad.' konnte nicht erstellt werden'); + $this->logger->warning($pfad.' konnte nicht erstellt werden'); } $speicherpfad = $pfad.$this->app->Conf->WFdbname; @@ -6880,7 +6883,7 @@ public function ParsePartXmlOrderOfferWithoutId($typ, &$xml, $uebertragungen_acc if(!file_exists($speicherpfad) && !mkdir($speicherpfad, 0777, true) && !is_dir($speicherpfad)) { - $this->app->erp->LogFile($speicherpfad.' konnte nicht erstellt werden'); + $this->logger->warning($speicherpfad.' konnte nicht erstellt werden'); } $fileid = $this->app->erp->CreateDatei($singledatei->dateiname, !empty($singledatei->titel)?$singledatei->titel:$singledatei->dateiname, !empty($singledatei->beschreibung)?(string)$singledatei->beschreibung:'', '', $name, '',true,$speicherpfad); @@ -7798,7 +7801,7 @@ public function SaveXML(&$xml, $dateiname, $action = '', $tag = '') } $folder = dirname($dateiname); if($folder !== '.' && !is_dir($folder) && !mkdir($folder,0700,true) && !is_dir($folder)) { - $this->app->erp->LogFile($folder.' konnte nicht erstellt werden'); + $this->logger->warning($folder.' konnte nicht erstellt werden'); } $content = $this->EntferneSteuerzeichen($content); if(!empty($tag)) { @@ -8955,7 +8958,7 @@ public function ApiBelegCreate($intern = false, $doctype = 'auftrag') break; case 'bestellung': - $this->app->erp->LogFile($adresse); + $this->logger->info($adresse); $id = $this->app->erp->CreateBestellung($adresse); $this->app->erp->LoadBestellungStandardwerte($id,$adresse); break; @@ -10106,7 +10109,7 @@ protected function AddFiles($files, $doctype, $doctypeid) if(!file_exists($pfad) && !mkdir($pfad, 0777, true) && !is_dir($pfad)) { - $this->app->erp->LogFile($pfad.' konnte nicht erstellt werden'); + $this->logger->warning($pfad.' konnte nicht erstellt werden'); } $speicherpfad = $pfad.$this->app->Conf->WFdbname; @@ -10114,7 +10117,7 @@ protected function AddFiles($files, $doctype, $doctypeid) if(!file_exists($speicherpfad) && !mkdir($speicherpfad, 0777, true) && !is_dir($speicherpfad)) { - $this->app->erp->LogFile($speicherpfad.' konnte nicht erstellt werden'); + $this->logger->warning($speicherpfad.' konnte nicht erstellt werden'); } $fileid = $this->app->erp->CreateDatei($file['dateiname'], !empty($file['titel'])?$file['titel']:$file['dateiname'], !empty($file['beschreibung'])?(string)$file['beschreibung']:'', '', $name, '',true,$speicherpfad); diff --git a/www/pages/artikel.php b/www/pages/artikel.php index fce6ac5de..466c8e304 100644 --- a/www/pages/artikel.php +++ b/www/pages/artikel.php @@ -22,6 +22,8 @@ ?> app->erp->base64_url_encode('
' . $remote_message . '
'); } - $this->app->erp->LogFile($this->app->DB->real_escape_string('manueller Shopexport Artikel: '.$this->app->DB->Select("SELECT nummer FROM artikel WHERE id = '$id' LIMIT 1").' Shop: '.$shop.' Status: '.((int) $remote_status)), $remote_message); + $artikelnummer = $this->app->DB->Select("SELECT nummer FROM artikel WHERE id = '$id' LIMIT 1"); + /** @var LoggerInterface $logger */ + $logger = $this->app->Container->get('Logger'); + $level = $remote_status ? LogLevel::INFO : LogLevel::ERROR; + $logger->log($level, 'manueller Shopexport', [ + 'articleNumber' => $artikelnummer, + 'shop' => $shop, + 'remote_status' => $remote_status, + 'remote_message' => $remote_message, + ]); // keine fehlermeldung vom shop if ($remote_status) { diff --git a/www/pages/benutzer.php b/www/pages/benutzer.php index 283461185..f7048d9a7 100644 --- a/www/pages/benutzer.php +++ b/www/pages/benutzer.php @@ -958,7 +958,7 @@ public function permissionLog($grantingUserId,$receivingUserId,$module,$action,$ $userPermission = $this->app->Container->get('UserPermissionService'); $userPermission->log($grantingUserId,$grantingUserName,$receivingUserId,$receivingUserName,$module,$action,$permission); }catch (Exception $ex){ - $this->app->erp->LogFile('Fehler bei Zuweisung Rechtehistore',$ex->getMessage()); + $this->app->Container->get('Logger')->error('Fehler bei Zuweisung Rechtehistore',[$ex->getMessage()]); } } diff --git a/www/pages/content/einstellungen.tpl b/www/pages/content/einstellungen.tpl index 37e41e5e6..8576263c0 100644 --- a/www/pages/content/einstellungen.tpl +++ b/www/pages/content/einstellungen.tpl @@ -171,9 +171,6 @@
- diff --git a/www/pages/exportvorlage.php b/www/pages/exportvorlage.php index 3ee74c1b5..d4cfc5e28 100644 --- a/www/pages/exportvorlage.php +++ b/www/pages/exportvorlage.php @@ -1,4 +1,4 @@ - +*/ +?> app->erp->fixeUmlaute($value); + $value = $this->app->String->fixeUmlaute($value); foreach($notFounds as $key => $notFound) { if(strpos($value, $notFound) !== false) { unset($notFounds[$key]); @@ -1053,7 +1053,7 @@ function Exportinner($row,&$exportdatenmaskierung,&$exporttrennzeichen, &$intern foreach($row as $value) { - $value = $this->app->erp->fixeUmlaute($value); + $value = $this->app->String->fixeUmlaute($value); // ersetzte platzhalter foreach($replaces as $k => $v) { $value = str_replace($k, $params[$v], $value); diff --git a/www/pages/logfile.php b/www/pages/logfile.php deleted file mode 100644 index 1e47c4ff9..000000000 --- a/www/pages/logfile.php +++ /dev/null @@ -1,273 +0,0 @@ - -app=$app; - if($intern) { - return; - } - $this->app->ActionHandlerInit($this); - - $this->app->ActionHandler("list","LogfileList"); - $this->app->ActionHandler("delete","LogfileDelete"); - $this->app->ActionHandler("deleteall","LogfileDeleteAll"); - $this->app->ActionHandler("minidetail","LogfileMiniDetail"); - - $this->app->DefaultActionHandler("list"); - - $this->app->ActionHandlerListen($app); - } - - /** - * @param Application $app - * @param string $name - * @param array $erlaubtevars - * - * @return array - */ - public function TableSearch($app, $name, $erlaubtevars) - { - // in dieses switch alle lokalen Tabellen (diese Live Tabellen mit Suche etc.) für dieses Modul - switch($name) - { - case 'logfile': - $allowed['logfile'] = array('list'); - - // START EXTRA checkboxen - - // ENDE EXTRA checkboxen - - - // headings - - $heading = array('', 'ID', 'Zeit', 'Bearbeiter', 'Module', 'Action', 'Funktion', 'Meldung', 'Menü'); - $width = array('4%', '4%', '15%', '10%', '10%', '10%', '10%', '40%', '10%', '5%'); - $findcols = array('open', 'a.id', 'a.datum', 'a.bearbeiter', 'a.module', 'a.action', 'a.funktionsname', 'a.meldung', 'a.id'); - $searchsql = array("DATE_FORMAT(a.datum,'%d.%m.%Y %H:%i:%s')", 'a.bearbeiter', 'a.module', 'a.meldung', 'a.action', 'a.funktionsname'); - $defaultorder = 2; - $defaultorderdesc = 1; - $menucol = 1; - $moreinfo = true; - $menu = '
- -
' . - - // "". - - // "app->Conf->WFconf['defaulttheme']}/images/edit.svg\" border=\"0\">". - - - // " ". - - "" . "app->Conf->WFconf['defaulttheme']}/images/delete.svg\" border=\"0\">" . "
"; - - // SQL statement - $sql = "SELECT SQL_CALC_FOUND_ROWS a.id, 'app->Conf->WFconf['defaulttheme']}/images/details_open.png class=details>' as open, a.id,DATE_FORMAT(a.datum,'%d.%m.%Y %H:%i:%s'), a.bearbeiter, - a.module, a.action, a.funktionsname,a.meldung, a.id FROM logfile a"; - - - if($app->erp->GetKonfiguration('logfile_use_fulltext')){ - $matchesql = [ - 'sqlpre' => $sql . ' INNER JOIN (', - 'sqlpost' => ' ) AS `matches` ON matches.id = a.id ', - 'elements' => [] - ]; - $matchesql['elements'][] = [ - 'sql' => 'SELECT l.id - FROM logfile l', - 'where' => ["DATE_FORMAT(l.datum,'%d.%m.%Y %H:%i:%s')", 'l.bearbeiter', 'l.module', 'l.action', 'l.funktionsname'], - 'match' => ['l.meldung', 'l.dump'] - ]; - }else{ - unset($matchesql); - } - - - // gesamt anzahl - - $count = 'SELECT COUNT(a.id) FROM logfile a'; - break; - } - - $erg = array(); - - foreach($erlaubtevars as $k => $v) - { - if(isset($$v)){ - $erg[$v] = $$v; - } - } - return $erg; - } - - public function LogFileMiniDetail() - { - $id = $this->app->Secure->GetGET('id'); - if($id > 0){ - $dump = $this->app->DB->SelectRow("SELECT funktionsname,dump FROM logfile WHERE id='$id' LIMIT 1"); - } - if(!empty($dump)){ - echo '
Funktion ' . $dump['funktionsname'] . ':
'; - echo '

Dump:' . $dump['dump'] . '

'; - if(is_array(unserialize($dump['dump']))){ - echo '
';
-        print_r(unserialize($dump['dump']));
-        echo '
'; - } - } - $this->app->ExitXentral(); - } - - public function LogfileDelete() - { - $id = $this->app->Secure->GetGET('id'); - if($id > 0){ - $this->app->DB->Delete( - sprintf( - 'DELETE FROM `logfile` WHERE `id` = %d LIMIT 1', - $id - ) - ); - } - $msg = $this->app->erp->base64_url_encode('
Der Logeintrag wurde gelöscht!
'); - $this->app->Location->execute('index.php?module=logfile&action=list&msg='.$msg); - } - - - public function LogfileDeleteAll() - { - $this->app->DB->Delete('DELETE FROM `logfile`'); - $this->app->DB->Query('OPTIMIZE TABLE `logfile`'); - $msg = $this->app->erp->base64_url_encode('
Alle Logeinträge wurden wurden gelöscht!
'); - $this->app->Location->execute('index.php?module=logfile&action=list&msg='.$msg); - } - - public function LogfileList() - { - $this->LogfileMenu(); - $isLoggingActive = $this->isLoggingActive(); - if($isLoggingActive) { - $this->app->Tpl->Set('LOGGINGACTIVE', 'checked'); - } - $this->app->YUI->AutoSaveKonfiguration('logginActive', 'logfile_logging_active'); - //$this->app->erp->InternesEvent($this->app->User->GetID(),"Hallo","alarm",1); - - $this->app->YUI->TableSearch('TAB1','logfile','show','','',basename(__FILE__), __CLASS__); - $this->app->Tpl->Parse('PAGE','logfile_list.tpl'); - } - - public function LogfileMenu() - { - $this->app->erp->Headlines('Logdatei'); - $this->app->erp->MenuEintrag('index.php?module=einstellungen&action=list','Zurück zur Übersicht'); - $this->app->erp->MenuEintrag('index.php?module=logfile&action=list','Aktualisieren'); - $this->app->erp->MenuEintrag('index.php?module=logfile&action=deleteall','Alle Einträge löschen'); - } - - public function Install() { - $this->app->erp->CheckTable('logfile'); - $this->app->erp->CheckColumn('id','int(11)','logfile','NOT NULL AUTO_INCREMENT'); - $this->app->erp->CheckColumn('meldung','TEXT','logfile','DEFAULT \'\' NOT NULL'); - $this->app->erp->CheckColumn('dump','TEXT','logfile','DEFAULT \'\' NOT NULL'); - $this->app->erp->CheckColumn('module','VARCHAR(64)','logfile','DEFAULT \'\' NOT NULL'); - $this->app->erp->CheckColumn('action','VARCHAR(64)','logfile','DEFAULT \'\' NOT NULL'); - $this->app->erp->CheckColumn('bearbeiter','VARCHAR(64)','logfile','DEFAULT \'\' NOT NULL'); - $this->app->erp->CheckColumn('funktionsname','VARCHAR(64)','logfile','DEFAULT \'\' NOT NULL'); - $this->app->erp->CheckColumn('datum','DATETIME','logfile'); - - $hasFullIndex = $this->app->erp->CheckFulltextIndex('logfile',['meldung', 'dump']); - $this->app->erp->SetKonfigurationValue('logfile_use_fulltext', $hasFullIndex); - } - - /** - * @return bool - */ - public function isLoggingActive() - { - if($this->logging !== null) { - return (bool)$this->logging; - } - $loggingActive = (string)$this->app->erp->GetKonfiguration('logfile_logging_active'); - if($loggingActive === '') { - $this->app->erp->SetKonfigurationValue('logfile_logging_active', '0'); - $this->logging = false; - - return false; - } - $this->logging = (bool)$loggingActive; - - return $this->logging; - } - - /** - * @param bool $status - */ - public function changeLoggingStatus($status) - { - $this->logging = (bool)$status; - $this->app->erp->SetKonfigurationValue('logfile_logging_active', (int)$this->logging); - } - - /** - * @param array|string $meldung - * @param string $dump - * @param string $module - * @param string $action - * @param string $functionname - * - * @return int - */ - public function addLogFile($meldung,$dump='',$module='',$action='',$functionname='') - { - if(!$this->isLoggingActive()) { - return 0; - } - if($functionname=='') { - if (strnatcmp(phpversion(),'5.0.0') >= 0) { - $backtrace = debug_backtrace(); - $functionname = isset($backtrace[1]) && isset($backtrace[1]['function'])?$backtrace[1]['function']:''; - if($functionname === 'LogFile') { - $functionname = isset($backtrace[2]) && isset($backtrace[2]['function'])?$backtrace[2]['function']:''; - } - } - } - - $module = $this->app->DB->real_escape_string(is_scalar($module) ? strval($module) : print_r($module, true)); - $action = $this->app->DB->real_escape_string(is_scalar($action) ? strval($action) : print_r($action, true)); - $meldung = $this->app->DB->real_escape_string(is_scalar($meldung) ? strval($meldung) : print_r($meldung, true)); - $dump = $this->app->DB->real_escape_string(is_scalar($dump) ? strval($dump) : print_r($dump, true)); - $functionname = $this->app->DB->real_escape_string(is_scalar($functionname) ? strval($functionname) : print_r($functionname, true)); - - $this->app->DB->Insert( - sprintf( - "INSERT INTO logfile (module,action,meldung,dump,datum,bearbeiter,funktionsname) - VALUES ('%s','%s','%s','%s',NOW(),'','%s')", - $module, $action,$meldung,$dump,$functionname - ) - ); - - return (int)$this->app->DB->GetInsertID(); - } -} diff --git a/www/pages/prozessstarter.php b/www/pages/prozessstarter.php index 5c1654216..b2c1b4954 100644 --- a/www/pages/prozessstarter.php +++ b/www/pages/prozessstarter.php @@ -31,6 +31,8 @@ class Prozessstarter extends GenProzessstarter { /** @var int */ protected $parentId; + private \Psr\Log\LoggerInterface $logger; + /** * @param Application $app * @param string $name @@ -156,6 +158,8 @@ public function __construct($app, $intern = false) { return; } + $this->logger = $this->app->Container->get('Logger'); + $this->app->ActionHandlerInit($this); $this->app->ActionHandler("create","ProzessstarterCreate"); @@ -1175,7 +1179,7 @@ public function checkIfCronjobRunning($uid, $task) ) { return; } - $this->app->erp->LogFile( + $this->logger->warning( sprintf( 'Cronjob %s with pid: %s and taskid: %d cronjob_starter_running_id %d was not closed cleanly by starter-proccess.', $task['bezeichnung'], $uid, $task['id'], $runningTask['id'] @@ -1201,14 +1205,14 @@ public function closeAndLogCronjob($uid, $fromStarter2 = false) } if($fromStarter2) { - $this->app->erp->LogFile('Cronjob '.$cronjob['cronjob_name'].' called exit uid: '.$uid); + $this->logger->info('Cronjob '.$cronjob['cronjob_name'].' called exit uid: '.$uid); if(!empty($cronjob['task_id'])) { $this->setCronjobStatus('error', $cronjob['task_id']); $this->setCronjobRunning($uid, $cronjob['task_id'], false); } return; } - $this->app->erp->LogFile('Cronjob with uid: '.$uid.' was killed by module: '.$cronjob['cronjob_name']); + $this->logger->info('Cronjob with uid: '.$uid.' was killed by module: '.$cronjob['cronjob_name']); if(!empty($cronjob['task_id'])) { $this->setCronjobStatus('error', $cronjob['task_id']); @@ -1245,7 +1249,7 @@ public function removeKilledCronjobs() ) ); if($this->app->DB->affected_rows() > 0) { - $this->app->erp->LogFile( + $this->logger->warning( $this->app->DB->real_escape_string( 'Cronjob '.( $this->app->DB->Select( @@ -1468,7 +1472,7 @@ public function setCronjobRunning($uid, $task = null, $active = true) { } if(!empty($check['task_id']) && ($uid != $check['uid'] || $check['task_id'] != $task['id'])) { - $this->app->erp->LogFile( + $this->logger->warning( $this->app->DB->real_escape_string( sprintf( 'Cronjob: %s id: %d was not cleanly closed.', diff --git a/www/pages/report.php b/www/pages/report.php index 69bf0ebf3..a6af79001 100644 --- a/www/pages/report.php +++ b/www/pages/report.php @@ -77,6 +77,8 @@ class Report /** @var Request $request */ private $request; + private \Psr\Log\LoggerInterface $logger; + /** @var array $parameterNameBlacklist */ private $parameterNameBlacklist = [ 'MODULE', 'ACTION', 'CMD', 'ID', 'FORMAT', 'USER_ID', 'USER_PROJECTS', 'USER_ADMIN', 'REPORT_PROJECT' @@ -98,6 +100,7 @@ public function __construct($app, $intern = false) $this->template = $this->app->Tpl; $this->app->ActionHandlerInit($this); $this->request = $this->app->Container->get('Request'); + $this->logger = $this->app->Container->get('Logger'); // ab hier alle Action Handler definieren die das Modul hat $this->app->ActionHandler('list', 'HandleActionList'); @@ -1326,7 +1329,7 @@ public function ReportTable() $this->renderErrorMessages(['Keine Daten gefunden.'], $this->app->Tpl); } catch (Exception $e) { - $this->app->erp->LogFile('Exception while creating report', $e); + $this->logger->error('Exception while creating report', ['exception' => $e]); $this->renderErrorMessages(['Fehler beim Abrufen des Berichts.'], $this->app->Tpl); } @@ -3151,8 +3154,7 @@ private function installJsonReports() { $importDir = dirname(__DIR__, 2) . '/classes/Modules/Report/files'; if (!is_dir($importDir)) { - $this->app->erp->LogFile('Importverzeichnis kann nicht gefunden werden.', $importDir); - + $this->logger->error('Importverzeichnis kann nicht gefunden werden.', ['dir' => $importDir]); return; } $allFiles =scandir($importDir); @@ -3163,12 +3165,12 @@ private function installJsonReports() } } if ((!empty($importPaths)?count($importPaths):0) === 0) { - $this->app->erp->LogFile('No files available for import.', $importDir); + $this->logger->error('No files available for import.', ['dir' => $importDir]); return; } if (!$this->app->Container->has('ReportJsonImportService')) { - $this->app->erp->LogFile('Service ReportJsonImportService not available.'); + $this->logger->error('Service ReportJsonImportService not available.'); return; } @@ -3183,18 +3185,14 @@ private function installJsonReports() $data = json_decode($content, true); $errors = $importer->findJsonStructureErrors($data); if ((!empty($errors)?count($errors):0) > 0) { - $this->app->erp->Logfile( - sprintf( - 'Json parse error in File %s.', $filePath), - implode("\n", $errors) - ); + $this->logger->error('Json parse error', ['file' => $filePath, 'errors' => $errors]); throw new JsonParseException(sprintf('Json parse error in File %s', $filePath)); } $data['readonly'] = true; $importer->importReport($data); $importedReportNames[] = $data['name']; } catch (Exception $e) { - $this->app->erp->LogFile(sprintf('Import of json file failed %s', $filePath),$e); + $this->logger->error('Json import error', ['file' => $filePath, 'error' => $e->getMessage()]); } } diff --git a/www/pages/shopexport.php b/www/pages/shopexport.php index fa80b036c..6355527ee 100644 --- a/www/pages/shopexport.php +++ b/www/pages/shopexport.php @@ -660,7 +660,7 @@ public function HandleResetArticleCacheForArticleWithZeroStock(): RedirectRespon WHERE (oa.storage_cache = 0 OR oa.storage_cache IS NULL) AND a.geloescht = 0" ); $anz = $this->app->DB->affected_rows(); - $this->app->erp->LogFile("Lagerzahlencache zurückgesetzt für $anz Artikel mit 0-Mengen, shopid: $id"); + $this->app->Container->get('Logger')->info("Lagerzahlencache zurückgesetzt für $anz Artikel mit 0-Mengen, shopid: $id"); } $msg = $this->app->erp->base64_url_encode( "
Lagerzahlen Cache für ".$anz." Artikel zurückgesetzt.
" @@ -701,7 +701,7 @@ public function ShopexportArtikeluebertragung() LEFT JOIN (SELECT artikel FROM artikel_onlineshops WHERE shop = '$id' AND aktiv = 1 GROUP BY artikel) oa ON a.id = oa.artikel SET a.cache_lagerplatzinhaltmenge = -999 WHERE (a.shop = '$id' OR a.shop2 = '$id' OR a.shop3 = '$id' OR NOT ISNULL(oa.artikel)) AND a.geloescht = 0"); $anz = $this->app->DB->affected_rows(); - $this->app->erp->LogFile("Lagerzahlencache zurückgesetzt für $anz Artikel, shopid: $id"); + $this->app->Container->get('Logger')->info("Lagerzahlencache zurückgesetzt für $anz Artikel, shopid: $id"); } $msg = $this->app->erp->base64_url_encode("
Lagerzahlen Cache für ".$anz." Artikel zurückgesetzt.
"); $this->app->Location->execute("index.php?module=shopexport&action=artikeluebertragung&id=$id&msg=$msg"); diff --git a/www/pages/shopimport.php b/www/pages/shopimport.php index 664907ba3..4b631a71d 100644 --- a/www/pages/shopimport.php +++ b/www/pages/shopimport.php @@ -1010,13 +1010,13 @@ public function importShopOrder($shopImportedOrderId, $utf8coding, $customerNumb foreach ($shopOrderCleaned as $k => $v) { if (!is_array($v)) { - $shopOrderCleaned[$k] = $this->app->erp->fixeUmlaute($v); + $shopOrderCleaned[$k] = $this->app->String->fixeUmlaute($v); } } $umlautefehler = false; if ((String) $shopOrder['name'] !== '' && (String) $shopOrderCleaned['name'] === '') { $umlautefehler = true; - $this->app->erp->LogFile('Kodierungsfehler in shopimport_auftraege ' . $shopImportedOrderId); + $this->app->Container->get('Logger')->error('Kodierungsfehler in shopimport_auftraege ' . $shopImportedOrderId); } $succes = $this->KundeAnlegenUpdate($shopImportedOrderId, '', $shopOrderCleaned, $customerNumber, $custumerNumberImported, $unknownPaymentTypes); @@ -1512,7 +1512,7 @@ public function getCustomerNumberFromShopCart($arr) { } } foreach ($warenkorb as $k => $v) { - $warenkorb[$k] = $this->app->erp->fixeUmlaute($v); + $warenkorb[$k] = $this->app->String->fixeUmlaute($v); } $kundenurvonprojekt = $this->app->DB->Select("SELECT kundenurvonprojekt FROM shopexport WHERE id = '" . $arr['shopid'] . "' LIMIT 1"); @@ -1659,7 +1659,7 @@ public function drawShopOrderTable($deletedRows) { } } foreach ($warenkorb as $k => $v) { - $warenkorb[$k] = $this->app->erp->fixeUmlaute($v); + $warenkorb[$k] = $this->app->String->fixeUmlaute($v); } $kundenurvonprojekt = $this->app->DB->Select("SELECT kundenurvonprojekt FROM shopexport WHERE id = '" . $arr[$i]['shopid'] . "' LIMIT 1"); $adresseprojekt = ''; diff --git a/www/pages/shopimporter_presta.php b/www/pages/shopimporter_presta.php index 7fce9ab3a..a20fc8a3e 100644 --- a/www/pages/shopimporter_presta.php +++ b/www/pages/shopimporter_presta.php @@ -454,10 +454,13 @@ public function getOrderSearchLimit(): int return 25; } - private function Log($message, $dump = '') + private function Log($message, $dump = null) { if ($this->protocol) { - $this->app->erp->Logfile($message, print_r($dump, true)); + if ($dump !== null && !is_array($dump)) { + $dump = [$dump]; + } + $this->app->Container->get('Logger')->info($message, $dump); } } diff --git a/www/pages/shopimporter_shopify.php b/www/pages/shopimporter_shopify.php index 01a9dd6c0..9f11dda53 100644 --- a/www/pages/shopimporter_shopify.php +++ b/www/pages/shopimporter_shopify.php @@ -3425,7 +3425,7 @@ public function ImportUpdateAuftrag() $result = $this->adapter->call('orders/' . $auftrag . '/fulfillments.json', 'POST', $data); if($this->logging){ - $this->app->erp->LogFile(array($data, $auftrag, $data, $result['data'])); + $this->app->Container->get('Logger')->info('Update Auftrag', array($data, $auftrag, $data, $result['data'])); } $this->adapter->call('orders/' . $auftrag . '/metafields.json', 'POST', array('metafield' => [ 'key' => 'sync_status', @@ -3435,7 +3435,7 @@ public function ImportUpdateAuftrag() ])); }else{ if($this->logging){ - $this->app->erp->LogFile(array($data, $auftrag,'Kein Auftrag')); + $this->app->Container->get('Logger')->info('Kein Auftrag', array($auftrag)); } } return 'OK'; @@ -3687,9 +3687,11 @@ public function ImportAuth() } - function ShopifyLog($nachricht, $dump = ''){ + function ShopifyLog($nachricht, $dump = null){ if($this->logging){ - $this->app->erp->LogFile($nachricht, print_r($dump,true)); + if ($dump !== null && !is_array($dump)) + $dump = ['dump' => $dump]; + $this->app->Container->get('Logger')->info($nachricht, $dump); } } diff --git a/www/pages/shopimporter_shopware.php b/www/pages/shopimporter_shopware.php index 2af27c1d3..c3925a645 100644 --- a/www/pages/shopimporter_shopware.php +++ b/www/pages/shopimporter_shopware.php @@ -2635,10 +2635,12 @@ protected function removeOrderFromOrderList($orderId, $orders) { return $orders; } - public function ShopwareLog($nachricht, $dump = '') + public function ShopwareLog($nachricht, $dump = null) { if($this->protokoll){ - $this->app->erp->Logfile($nachricht, print_r($dump, true)); + if ($dump !== null && !is_array($dump)) + $dump = ['dump' => $dump]; + $this->app->Container->get('Logger')->info($nachricht, $dump); } } diff --git a/www/pages/shopimporter_shopware6.php b/www/pages/shopimporter_shopware6.php index f54ad7417..a4aad65f1 100644 --- a/www/pages/shopimporter_shopware6.php +++ b/www/pages/shopimporter_shopware6.php @@ -950,10 +950,12 @@ public function getCorrectedStockFromAvailable(bool $isStockActive, int $stock, * @param string $message * @param mixed $dump */ - public function Shopware6Log($message, $dump = '') + public function Shopware6Log($message, $dump = null) { if ($this->protocol) { - $this->app->erp->Logfile($message, print_r($dump, true)); + if ($dump !== null && !is_array($dump)) + $dump = ['dump' => $dump]; + $this->app->Container->get('Logger')->info($message, $dump); } } diff --git a/www/pages/welcome.php b/www/pages/welcome.php index 7cbfddb0f..512ed1057 100644 --- a/www/pages/welcome.php +++ b/www/pages/welcome.php @@ -936,7 +936,7 @@ protected function checkFreeSpace(){ } } catch(Exception $e){ - $this->app->erp->LogFile('can not evaluate disk space: ' . $e->getMessage()); + $this->app->Container->get('Logger')->warning('can not evaluate disk space: ' . $e->getMessage()); } } @@ -2915,9 +2915,6 @@ protected function HandleStartClickByClick() ] ] ]; - if($showExampleImport) { - $lastPage['subHeadline'] .= '
Beispieldaten einspielen'; - } $pages[] = $lastPage; diff --git a/www/pages/wiki.php b/www/pages/wiki.php index 1cebd831b..1e4f64a14 100644 --- a/www/pages/wiki.php +++ b/www/pages/wiki.php @@ -1,4 +1,4 @@ - +*/ +?> getArticleByName($actModule,$workspace['id']); - $content = $wiki['content']; + $content = $wiki['content'] ?? null; $menu = null; if(!empty($content)){ list($menu, $content) = $this->parseMenuFromHtml($content); diff --git a/www/plugins/fullcalendar-1.5.3/fullcalendar.css b/www/plugins/fullcalendar-1.5.3/fullcalendar.css deleted file mode 100644 index 43d78401d..000000000 --- a/www/plugins/fullcalendar-1.5.3/fullcalendar.css +++ /dev/null @@ -1,619 +0,0 @@ -/* - * FullCalendar v1.5.3 Stylesheet - * - * Copyright (c) 2011 Adam Shaw - * Dual licensed under the MIT and GPL licenses, located in - * MIT-LICENSE.txt and GPL-LICENSE.txt respectively. - * - * Date: Mon Feb 6 22:40:40 2012 -0800 - * - */ - - - -.fc { - direction: ltr; - text-align: left; - } - -.fc table { - border-collapse: collapse; - border-spacing: 0; - } - -html .fc, -.fc table { - font-size: 1em; - } - -.fc td, -.fc th { - padding: 0; - vertical-align: top; - } - - - -/* Header -------------------------------------------------------------------------*/ - -.fc-header td { - white-space: nowrap; - } - -.fc-header-left { - width: 25%; - text-align: left; - } - -.fc-header-center { - text-align: center; - } - -.fc-header-right { - width: 25%; - text-align: right; - } - -.fc-header-title { - display: inline-block; - vertical-align: top; - } - -.fc-header-title h2 { - margin-top: 0; - white-space: nowrap; - } - -.fc .fc-header-space { - padding-left: 10px; - } - -.fc-header .fc-button { - margin-bottom: 1em; - vertical-align: top; - } - -/* buttons edges butting together */ - -.fc-header .fc-button { - margin-right: -1px; - } - -.fc-header .fc-corner-right { - margin-right: 1px; /* back to normal */ - } - -.fc-header .ui-corner-right { - margin-right: 0; /* back to normal */ - } - -/* button layering (for border precedence) */ - -.fc-header .fc-state-hover, -.fc-header .ui-state-hover { - z-index: 2; - } - -.fc-header .fc-state-down { - z-index: 3; - } - -.fc-header .fc-state-active, -.fc-header .ui-state-active { - z-index: 4; - } - - - -/* Content -------------------------------------------------------------------------*/ - -.fc-content { - clear: both; - } - -.fc-view { - width: 100%; /* needed for view switching (when view is absolute) */ - overflow: hidden; - } - - - -/* Cell Styles -------------------------------------------------------------------------*/ - -.fc-widget-header, /* , usually */ -.fc-widget-content { /* , usually */ - border: 1px solid #ccc; - } - -.fc-state-highlight { /* today cell */ /* TODO: add .fc-today to */ - background: #ffc; - } - -.fc-cell-overlay { /* semi-transparent rectangle while dragging */ - background: #9cf; - opacity: .2; - filter: alpha(opacity=20); /* for IE */ - } - - - -/* Buttons -------------------------------------------------------------------------*/ - -.fc-button { - position: relative; - display: inline-block; - cursor: pointer; - } - -.fc-state-default { /* non-theme */ - border-style: solid; - border-width: 1px 0; - } - -.fc-button-inner { - position: relative; - float: left; - overflow: hidden; - } - -.fc-state-default .fc-button-inner { /* non-theme */ - border-style: solid; - border-width: 0 1px; - } - -.fc-button-content { - position: relative; - float: left; - height: 1.9em; - line-height: 1.9em; - padding: 0 .6em; - white-space: nowrap; - } - -/* icon (for jquery ui) */ - -.fc-button-content .fc-icon-wrap { - position: relative; - float: left; - top: 50%; - } - -.fc-button-content .ui-icon { - position: relative; - float: left; - margin-top: -50%; - *margin-top: 0; - *top: -50%; - } - -/* gloss effect */ - -.fc-state-default .fc-button-effect { - position: absolute; - top: 50%; - left: 0; - } - -.fc-state-default .fc-button-effect span { - position: absolute; - top: -100px; - left: 0; - width: 500px; - height: 100px; - border-width: 100px 0 0 1px; - border-style: solid; - border-color: #fff; - background: #444; - opacity: .09; - filter: alpha(opacity=9); - } - -/* button states (determines colors) */ - -.fc-state-default, -.fc-state-default .fc-button-inner { - border-style: solid; - border-color: #ccc #bbb #aaa; - background: #F3F3F3; - color: #000; - } - -.fc-state-hover, -.fc-state-hover .fc-button-inner { - border-color: #999; - } - -.fc-state-down, -.fc-state-down .fc-button-inner { - border-color: #555; - background: #777; - } - -.fc-state-active, -.fc-state-active .fc-button-inner { - border-color: #555; - background: #777; - color: #fff; - } - -.fc-state-disabled, -.fc-state-disabled .fc-button-inner { - color: #999; - border-color: #ddd; - } - -.fc-state-disabled { - cursor: default; - } - -.fc-state-disabled .fc-button-effect { - display: none; - } - - - -/* Global Event Styles -------------------------------------------------------------------------*/ - -.fc-event { - border-style: solid; - border-width: 0; - font-size: .85em; - cursor: default; - } - -a.fc-event, -.fc-event-draggable { - cursor: pointer; - } - -a.fc-event { - text-decoration: none; - } - -.fc-rtl .fc-event { - text-align: right; - } - -.fc-event-skin { - border-color: #36c; /* default BORDER color */ - background-color: #36c; /* default BACKGROUND color */ - color: #fff; /* default TEXT color */ - } - -.fc-event-inner { - position: relative; - width: 100%; - height: 100%; - border-style: solid; - border-width: 0; - overflow: hidden; - } - -.fc-event-time, -.fc-event-title { - padding: 0 1px; - } - -.fc .ui-resizable-handle { /*** TODO: don't use ui-resizable anymore, change class ***/ - display: block; - position: absolute; - z-index: 99999; - overflow: hidden; /* hacky spaces (IE6/7) */ - font-size: 300%; /* */ - line-height: 50%; /* */ - } - - - -/* Horizontal Events -------------------------------------------------------------------------*/ - -.fc-event-hori { - border-width: 1px 0; - margin-bottom: 1px; - } - -/* resizable */ - -.fc-event-hori .ui-resizable-e { - top: 0 !important; /* importants override pre jquery ui 1.7 styles */ - right: -3px !important; - width: 7px !important; - height: 100% !important; - cursor: e-resize; - } - -.fc-event-hori .ui-resizable-w { - top: 0 !important; - left: -3px !important; - width: 7px !important; - height: 100% !important; - cursor: w-resize; - } - -.fc-event-hori .ui-resizable-handle { - _padding-bottom: 14px; /* IE6 had 0 height */ - } - - - -/* Fake Rounded Corners (for buttons and events) -------------------------------------------------------------*/ - -.fc-corner-left { - margin-left: 1px; - } - -.fc-corner-left .fc-button-inner, -.fc-corner-left .fc-event-inner { - margin-left: -1px; - } - -.fc-corner-right { - margin-right: 1px; - } - -.fc-corner-right .fc-button-inner, -.fc-corner-right .fc-event-inner { - margin-right: -1px; - } - -.fc-corner-top { - margin-top: 1px; - } - -.fc-corner-top .fc-event-inner { - margin-top: -1px; - } - -.fc-corner-bottom { - margin-bottom: 1px; - } - -.fc-corner-bottom .fc-event-inner { - margin-bottom: -1px; - } - - - -/* Fake Rounded Corners SPECIFICALLY FOR EVENTS ------------------------------------------------------------------*/ - -.fc-corner-left .fc-event-inner { - border-left-width: 1px; - } - -.fc-corner-right .fc-event-inner { - border-right-width: 1px; - } - -.fc-corner-top .fc-event-inner { - border-top-width: 1px; - } - -.fc-corner-bottom .fc-event-inner { - border-bottom-width: 1px; - } - - - -/* Reusable Separate-border Table -------------------------------------------------------------*/ - -table.fc-border-separate { - border-collapse: separate; - } - -.fc-border-separate th, -.fc-border-separate td { - border-width: 1px 0 0 1px; - } - -.fc-border-separate th.fc-last, -.fc-border-separate td.fc-last { - border-right-width: 1px; - } - -.fc-border-separate tr.fc-last th, -.fc-border-separate tr.fc-last td { - border-bottom-width: 1px; - } - -.fc-border-separate tbody tr.fc-first td, -.fc-border-separate tbody tr.fc-first th { - border-top-width: 0; - } - - - -/* Month View, Basic Week View, Basic Day View -------------------------------------------------------------------------*/ - -.fc-grid th { - text-align: center; - } - -.fc-grid .fc-day-number { - float: right; - padding: 0 2px; - } - -.fc-grid .fc-other-month .fc-day-number { - opacity: 0.3; - filter: alpha(opacity=30); /* for IE */ - /* opacity with small font can sometimes look too faded - might want to set the 'color' property instead - making day-numbers bold also fixes the problem */ - } - -.fc-grid .fc-day-content { - clear: both; - padding: 2px 2px 1px; /* distance between events and day edges */ - } - -/* event styles */ - -.fc-grid .fc-event-time { - font-weight: bold; - } - -/* right-to-left */ - -.fc-rtl .fc-grid .fc-day-number { - float: left; - } - -.fc-rtl .fc-grid .fc-event-time { - float: right; - } - - - -/* Agenda Week View, Agenda Day View -------------------------------------------------------------------------*/ - -.fc-agenda table { - border-collapse: separate; - } - -.fc-agenda-days th { - text-align: center; - } - -.fc-agenda .fc-agenda-axis { - width: 50px; - padding: 0 4px; - vertical-align: middle; - text-align: right; - white-space: nowrap; - font-weight: normal; - } - -.fc-agenda .fc-day-content { - padding: 2px 2px 1px; - } - -/* make axis border take precedence */ - -.fc-agenda-days .fc-agenda-axis { - border-right-width: 1px; - } - -.fc-agenda-days .fc-col0 { - border-left-width: 0; - } - -/* all-day area */ - -.fc-agenda-allday th { - border-width: 0 1px; - } - -.fc-agenda-allday .fc-day-content { - min-height: 34px; /* TODO: doesnt work well in quirksmode */ - _height: 34px; - } - -/* divider (between all-day and slots) */ - -.fc-agenda-divider-inner { - height: 2px; - overflow: hidden; - } - -.fc-widget-header .fc-agenda-divider-inner { - background: #eee; - } - -/* slot rows */ - -.fc-agenda-slots th { - border-width: 1px 1px 0; - } - -.fc-agenda-slots td { - border-width: 1px 0 0; - background: none; - } - -.fc-agenda-slots td div { - height: 20px; - } - -.fc-agenda-slots tr.fc-slot0 th, -.fc-agenda-slots tr.fc-slot0 td { - border-top-width: 0; - } - -.fc-agenda-slots tr.fc-minor th, -.fc-agenda-slots tr.fc-minor td { - border-top-style: dotted; - } - -.fc-agenda-slots tr.fc-minor th.ui-widget-header { - *border-top-style: solid; /* doesn't work with background in IE6/7 */ - } - - - -/* Vertical Events -------------------------------------------------------------------------*/ - -.fc-event-vert { - border-width: 0 1px; - } - -.fc-event-vert .fc-event-head, -.fc-event-vert .fc-event-content { - position: relative; - z-index: 2; - width: 100%; - overflow: hidden; - } - -.fc-event-vert .fc-event-time { - white-space: nowrap; - font-size: 10px; - } - -.fc-event-vert .fc-event-bg { /* makes the event lighter w/ a semi-transparent overlay */ - position: absolute; - z-index: 1; - top: 0; - left: 0; - width: 100%; - height: 100%; - background: #fff; - opacity: .3; - filter: alpha(opacity=30); - } - -.fc .ui-draggable-dragging .fc-event-bg, /* TODO: something nicer like .fc-opacity */ -.fc-select-helper .fc-event-bg { - display: none\9; /* for IE6/7/8. nested opacity filters while dragging don't work */ - } - -/* resizable */ - -.fc-event-vert .ui-resizable-s { - bottom: 0 !important; /* importants override pre jquery ui 1.7 styles */ - width: 100% !important; - height: 8px !important; - overflow: hidden !important; - line-height: 8px !important; - font-size: 11px !important; - font-family: monospace; - text-align: center; - cursor: s-resize; - } - -.fc-agenda .ui-resizable-resizing { /* TODO: better selector */ - _overflow: hidden; - } - - diff --git a/www/plugins/fullcalendar-1.5.3/fullcalendar.js b/www/plugins/fullcalendar-1.5.3/fullcalendar.js deleted file mode 100644 index 85acda371..000000000 --- a/www/plugins/fullcalendar-1.5.3/fullcalendar.js +++ /dev/null @@ -1,5235 +0,0 @@ -/** - * @preserve - * FullCalendar v1.5.3 - * http://arshaw.com/fullcalendar/ - * - * Use fullcalendar.css for basic styling. - * For event drag & drop, requires jQuery UI draggable. - * For event resizing, requires jQuery UI resizable. - * - * Copyright (c) 2011 Adam Shaw - * Dual licensed under the MIT and GPL licenses, located in - * MIT-LICENSE.txt and GPL-LICENSE.txt respectively. - * - * Date: Mon Feb 6 22:40:40 2012 -0800 - * - */ - -(function($, undefined) { - - -var defaults = { - - // display - defaultView: 'month', - aspectRatio: 1.35, - header: { - left: 'title', - center: '', - right: 'tasks today prev,next' - }, - weekends: true, - - // editing - //editable: false, - //disableDragging: false, - //disableResizing: false, - - allDayDefault: true, - ignoreTimezone: true, - - // event ajax - lazyFetching: true, - startParam: 'start', - endParam: 'end', - - // time formats - titleFormat: { - month: 'MMMM yyyy', - week: "MMM d[ yyyy]{ '—'[ MMM] d yyyy}", - day: 'dddd, MMM d, yyyy' - }, - columnFormat: { - month: 'ddd', - week: 'ddd M/d', - day: 'dddd M/d' - }, - timeFormat: { // for event elements - '': 'h(:mm)t' // default - }, - - // locale - isRTL: false, - firstDay: 0, - monthNames: ['January','February','March','April','May','June','July','August','September','October','November','December'], - monthNamesShort: ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'], - dayNames: ['Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday'], - dayNamesShort: ['Sun','Mon','Tue','Wed','Thu','Fri','Sat'], - buttonText: { - prev: ' ◄ ', - next: ' ► ', - prevYear: ' << ', - nextYear: ' >> ', - today: 'Heute', - tasks: 'Aufgaben anzeigen', - month: 'Monat', - week: 'Woche', - day: 'Tag' - }, - - // jquery-ui theming - theme: false, - buttonIcons: { - prev: 'circle-triangle-w', - next: 'circle-triangle-e' - }, - - //selectable: false, - unselectAuto: true, - - dropAccept: '*' - -}; - -// right-to-left defaults -var rtlDefaults = { - header: { - left: 'next,prev today tasks', - center: '', - right: 'title' - }, - buttonText: { - prev: ' ► ', - next: ' ◄ ', - tasks: ' Aufgaben anzeigen ', - prevYear: ' >> ', - nextYear: ' << ' - }, - buttonIcons: { - prev: 'circle-triangle-e', - next: 'circle-triangle-w' - } -}; - - - -var fc = $.fullCalendar = { version: "1.5.3" }; -var fcViews = fc.views = {}; - - -$.fn.fullCalendar = function(options) { - - - // method calling - if (typeof options == 'string') { - var args = Array.prototype.slice.call(arguments, 1); - var res; - this.each(function() { - var calendar = $.data(this, 'fullCalendar'); - if (calendar && $.isFunction(calendar[options])) { - var r = calendar[options].apply(calendar, args); - if (res === undefined) { - res = r; - } - if (options == 'destroy') { - $.removeData(this, 'fullCalendar'); - } - } - }); - if (res !== undefined) { - return res; - } - return this; - } - - - // would like to have this logic in EventManager, but needs to happen before options are recursively extended - var eventSources = options.eventSources || []; - delete options.eventSources; - if (options.events) { - eventSources.push(options.events); - delete options.events; - } - - - options = $.extend(true, {}, - defaults, - (options.isRTL || options.isRTL===undefined && defaults.isRTL) ? rtlDefaults : {}, - options - ); - - - this.each(function(i, _element) { - var element = $(_element); - var calendar = new Calendar(element, options, eventSources); - element.data('fullCalendar', calendar); // TODO: look into memory leak implications - calendar.render(); - }); - - - return this; - -}; - - -// function for adding/overriding defaults -function setDefaults(d) { - $.extend(true, defaults, d); -} - - - - -function Calendar(element, options, eventSources) { - var t = this; - - - // exports - t.options = options; - t.render = render; - t.destroy = destroy; - t.refetchEvents = refetchEvents; - t.reportEvents = reportEvents; - t.reportEventChange = reportEventChange; - t.rerenderEvents = rerenderEvents; - t.changeView = changeView; - t.select = select; - t.unselect = unselect; - t.prev = prev; - t.next = next; - t.prevYear = prevYear; - t.nextYear = nextYear; - t.today = today; - t.tasks = tasks; - t.gotoDate = gotoDate; - t.incrementDate = incrementDate; - t.formatDate = function(format, date) { return formatDate(format, date, options) }; - t.formatDates = function(format, date1, date2) { return formatDates(format, date1, date2, options) }; - t.getDate = getDate; - t.getView = getView; - t.option = option; - t.trigger = trigger; - - - // imports - EventManager.call(t, options, eventSources); - var isFetchNeeded = t.isFetchNeeded; - var fetchEvents = t.fetchEvents; - - - // locals - var _element = element[0]; - var header; - var headerElement; - var content; - var tm; // for making theme classes - var currentView; - var viewInstances = {}; - var elementOuterWidth; - var suggestedViewHeight; - var absoluteViewElement; - var resizeUID = 0; - var ignoreWindowResize = 0; - var date = new Date(); - var events = []; - var _dragElement; - - - - /* Main Rendering - -----------------------------------------------------------------------------*/ - - - setYMD(date, options.year, options.month, options.date); - - - function render(inc) { - if (!content) { - initialRender(); - }else{ - calcSize(); - markSizesDirty(); - markEventsDirty(); - renderView(inc); - } - } - - - function initialRender() { - tm = options.theme ? 'ui' : 'fc'; - element.addClass('fc'); - if (options.isRTL) { - element.addClass('fc-rtl'); - } - if (options.theme) { - element.addClass('ui-widget'); - } - content = $("
") - .prependTo(element); - header = new Header(t, options); - headerElement = header.render(); - if (headerElement) { - element.prepend(headerElement); - } - changeView(options.defaultView); - $(window).resize(windowResize); - // needed for IE in a 0x0 iframe, b/c when it is resized, never triggers a windowResize - if (!bodyVisible()) { - lateRender(); - } - } - - - // called when we know the calendar couldn't be rendered when it was initialized, - // but we think it's ready now - function lateRender() { - setTimeout(function() { // IE7 needs this so dimensions are calculated correctly - if (!currentView.start && bodyVisible()) { // !currentView.start makes sure this never happens more than once - renderView(); - } - },0); - } - - - function destroy() { - $(window).unbind('resize', windowResize); - header.destroy(); - content.remove(); - element.removeClass('fc fc-rtl ui-widget'); - } - - - - function elementVisible() { - return _element.offsetWidth !== 0; - } - - - function bodyVisible() { - return $('body')[0].offsetWidth !== 0; - } - - - - /* View Rendering - -----------------------------------------------------------------------------*/ - - // TODO: improve view switching (still weird transition in IE, and FF has whiteout problem) - - function changeView(newViewName) { - if (!currentView || newViewName != currentView.name) { - ignoreWindowResize++; // because setMinHeight might change the height before render (and subsequently setSize) is reached - - unselect(); - - var oldView = currentView; - var newViewElement; - - if (oldView) { - (oldView.beforeHide || noop)(); // called before changing min-height. if called after, scroll state is reset (in Opera) - setMinHeight(content, content.height()); - oldView.element.hide(); - }else{ - setMinHeight(content, 1); // needs to be 1 (not 0) for IE7, or else view dimensions miscalculated - } - content.css('overflow', 'hidden'); - - currentView = viewInstances[newViewName]; - if (currentView) { - currentView.element.show(); - }else{ - currentView = viewInstances[newViewName] = new fcViews[newViewName]( - newViewElement = absoluteViewElement = - $("
") - .appendTo(content), - t // the calendar object - ); - } - - if (oldView) { - header.deactivateButton(oldView.name); - } - header.activateButton(newViewName); - - renderView(); // after height has been set, will make absoluteViewElement's position=relative, then set to null - - content.css('overflow', ''); - if (oldView) { - setMinHeight(content, 1); - } - - if (!newViewElement) { - (currentView.afterShow || noop)(); // called after setting min-height/overflow, so in final scroll state (for Opera) - } - - ignoreWindowResize--; - } - } - - - - function renderView(inc) { - if (elementVisible()) { - ignoreWindowResize++; // because renderEvents might temporarily change the height before setSize is reached - - unselect(); - - if (suggestedViewHeight === undefined) { - calcSize(); - } - - var forceEventRender = false; - if (!currentView.start || inc || date < currentView.start || date >= currentView.end) { - // view must render an entire new date range (and refetch/render events) - currentView.render(date, inc || 0); // responsible for clearing events - setSize(true); - forceEventRender = true; - } - else if (currentView.sizeDirty) { - // view must resize (and rerender events) - currentView.clearEvents(); - setSize(); - forceEventRender = true; - } - else if (currentView.eventsDirty) { - currentView.clearEvents(); - forceEventRender = true; - } - currentView.sizeDirty = false; - currentView.eventsDirty = false; - updateEvents(forceEventRender); - - elementOuterWidth = element.outerWidth(); - - header.updateTitle(currentView.title); - var today = new Date(); - if (today >= currentView.start && today < currentView.end) { - header.disableButton('today'); - }else{ - header.enableButton('today'); - } - - ignoreWindowResize--; - currentView.trigger('viewDisplay', _element); - } - } - - - - /* Resizing - -----------------------------------------------------------------------------*/ - - - function updateSize() { - markSizesDirty(); - if (elementVisible()) { - calcSize(); - setSize(); - unselect(); - currentView.clearEvents(); - currentView.renderEvents(events); - currentView.sizeDirty = false; - } - } - - - function markSizesDirty() { - $.each(viewInstances, function(i, inst) { - inst.sizeDirty = true; - }); - } - - - function calcSize() { - if (options.contentHeight) { - suggestedViewHeight = options.contentHeight; - } - else if (options.height) { - suggestedViewHeight = options.height - (headerElement ? headerElement.height() : 0) - vsides(content); - } - else { - suggestedViewHeight = Math.round(content.width() / Math.max(options.aspectRatio, .5)); - } - } - - - function setSize(dateChanged) { // todo: dateChanged? - ignoreWindowResize++; - currentView.setHeight(suggestedViewHeight, dateChanged); - if (absoluteViewElement) { - absoluteViewElement.css('position', 'relative'); - absoluteViewElement = null; - } - currentView.setWidth(content.width(), dateChanged); - ignoreWindowResize--; - } - - - function windowResize() { - if (!ignoreWindowResize) { - if (currentView.start) { // view has already been rendered - var uid = ++resizeUID; - setTimeout(function() { // add a delay - if (uid == resizeUID && !ignoreWindowResize && elementVisible()) { - if (elementOuterWidth != (elementOuterWidth = element.outerWidth())) { - ignoreWindowResize++; // in case the windowResize callback changes the height - updateSize(); - currentView.trigger('windowResize', _element); - ignoreWindowResize--; - } - } - }, 200); - }else{ - // calendar must have been initialized in a 0x0 iframe that has just been resized - lateRender(); - } - } - } - - - - /* Event Fetching/Rendering - -----------------------------------------------------------------------------*/ - - - // fetches events if necessary, rerenders events if necessary (or if forced) - function updateEvents(forceRender) { - if (!options.lazyFetching || isFetchNeeded(currentView.visStart, currentView.visEnd)) { - refetchEvents(); - } - else if (forceRender) { - rerenderEvents(); - } - } - - - function refetchEvents() { - fetchEvents(currentView.visStart, currentView.visEnd); // will call reportEvents - } - - - // called when event data arrives - function reportEvents(_events) { - events = _events; - rerenderEvents(); - } - - - // called when a single event's data has been changed - function reportEventChange(eventID) { - rerenderEvents(eventID); - } - - - // attempts to rerenderEvents - function rerenderEvents(modifiedEventID) { - markEventsDirty(); - if (elementVisible()) { - currentView.clearEvents(); - currentView.renderEvents(events, modifiedEventID); - currentView.eventsDirty = false; - } - } - - - function markEventsDirty() { - $.each(viewInstances, function(i, inst) { - inst.eventsDirty = true; - }); - } - - - - /* Selection - -----------------------------------------------------------------------------*/ - - - function select(start, end, allDay) { - currentView.select(start, end, allDay===undefined ? true : allDay); - } - - - function unselect() { // safe to be called before renderView - if (currentView) { - currentView.unselect(); - } - } - - - - /* Date - -----------------------------------------------------------------------------*/ - - - function prev() { - renderView(-1); - } - - - function next() { - renderView(1); - } - - - function prevYear() { - addYears(date, -1); - renderView(); - } - - - function nextYear() { - addYears(date, 1); - renderView(); - } - - - function today() { - date = new Date(); - renderView(); - } - - function tasks() { - $.get('./index.php?module=kalender&action=taskstatus', function() { location.reload();}); - - } - - - function gotoDate(year, month, dateOfMonth) { - if (year instanceof Date) { - date = cloneDate(year); // provided 1 argument, a Date - }else{ - setYMD(date, year, month, dateOfMonth); - } - renderView(); - } - - - function incrementDate(years, months, days) { - if (years !== undefined) { - addYears(date, years); - } - if (months !== undefined) { - addMonths(date, months); - } - if (days !== undefined) { - addDays(date, days); - } - renderView(); - } - - - function getDate() { - return cloneDate(date); - } - - - - /* Misc - -----------------------------------------------------------------------------*/ - - - function getView() { - return currentView; - } - - - function option(name, value) { - if (value === undefined) { - return options[name]; - } - if (name == 'height' || name == 'contentHeight' || name == 'aspectRatio') { - options[name] = value; - updateSize(); - } - } - - - function trigger(name, thisObj) { - if (options[name]) { - return options[name].apply( - thisObj || _element, - Array.prototype.slice.call(arguments, 2) - ); - } - } - - - - /* External Dragging - ------------------------------------------------------------------------*/ - - if (options.droppable) { - $(document) - .bind('dragstart', function(ev, ui) { - var _e = ev.target; - var e = $(_e); - if (!e.parents('.fc').length) { // not already inside a calendar - var accept = options.dropAccept; - if ($.isFunction(accept) ? accept.call(_e, e) : e.is(accept)) { - _dragElement = _e; - currentView.dragStart(_dragElement, ev, ui); - } - } - }) - .bind('dragstop', function(ev, ui) { - if (_dragElement) { - currentView.dragStop(_dragElement, ev, ui); - _dragElement = null; - } - }); - } - - -} - -function Header(calendar, options) { - var t = this; - - - // exports - t.render = render; - t.destroy = destroy; - t.updateTitle = updateTitle; - t.activateButton = activateButton; - t.deactivateButton = deactivateButton; - t.disableButton = disableButton; - t.enableButton = enableButton; - - - // locals - var element = $([]); - var tm; - - - - function render() { - tm = options.theme ? 'ui' : 'fc'; - var sections = options.header; - if (sections) { - element = $("") - .append( - $("") - .append(renderSection('left')) - .append(renderSection('center')) - .append(renderSection('right')) - ); - return element; - } - } - - - function destroy() { - element.remove(); - } - - - function renderSection(position) { - var e = $("" + - ""; - for (i=0; i"; // need fc- for setDayID - } - s += - "" + - "" + - ""; - for (i=0; i"; - for (j=0; j" + // need fc- for setDayID - "
" + - (showNumbers ? - "
" : - '' - ) + - "
" + - "
 
" + - "
" + - "
" + - ""; - } - s += - ""; - } - s += - "
" + - "
"); - var buttonStr = options.header[position]; - - console.log(buttonStr); - - if (buttonStr) { - $.each(buttonStr.split(' '), function(i) { - if (i > 0) { - e.append(""); - } - var prevButton; - $.each(this.split(','), function(j, buttonName) { - if (buttonName == 'title') { - e.append("

 

"); - if (prevButton) { - prevButton.addClass(tm + '-corner-right'); - } - prevButton = null; - }else{ - var buttonClick; - if (calendar[buttonName]) { - buttonClick = calendar[buttonName]; // calendar method - } - else if (fcViews[buttonName]) { - buttonClick = function() { - button.removeClass(tm + '-state-hover'); // forget why - calendar.changeView(buttonName); - }; - } - if (buttonClick) { - var icon = options.theme ? smartProperty(options.buttonIcons, buttonName) : null; // why are we using smartProperty here? - var text = smartProperty(options.buttonText, buttonName); // why are we using smartProperty here? - var button = $( - "" + - "" + - "" + - (icon ? - "" + - "" + - "" : - text - ) + - "" + - "" + - "" + - "" - ); - if (button) { - button - .click(function() { - if (!button.hasClass(tm + '-state-disabled')) { - buttonClick(); - } - }) - .mousedown(function() { - button - .not('.' + tm + '-state-active') - .not('.' + tm + '-state-disabled') - .addClass(tm + '-state-down'); - }) - .mouseup(function() { - button.removeClass(tm + '-state-down'); - }) - .hover( - function() { - button - .not('.' + tm + '-state-active') - .not('.' + tm + '-state-disabled') - .addClass(tm + '-state-hover'); - }, - function() { - button - .removeClass(tm + '-state-hover') - .removeClass(tm + '-state-down'); - } - ) - .appendTo(e); - if (!prevButton) { - button.addClass(tm + '-corner-left'); - } - prevButton = button; - } - } - } - }); - if (prevButton) { - prevButton.addClass(tm + '-corner-right'); - } - }); - } - return e; - } - - - function updateTitle(html) { - element.find('h2') - .html(html); - } - - - function activateButton(buttonName) { - element.find('span.fc-button-' + buttonName) - .addClass(tm + '-state-active'); - } - - - function deactivateButton(buttonName) { - element.find('span.fc-button-' + buttonName) - .removeClass(tm + '-state-active'); - } - - - function disableButton(buttonName) { - element.find('span.fc-button-' + buttonName) - .addClass(tm + '-state-disabled'); - } - - - function enableButton(buttonName) { - element.find('span.fc-button-' + buttonName) - .removeClass(tm + '-state-disabled'); - } - - -} - -fc.sourceNormalizers = []; -fc.sourceFetchers = []; - -var ajaxDefaults = { - dataType: 'json', - cache: false -}; - -var eventGUID = 1; - - -function EventManager(options, _sources) { - var t = this; - - - // exports - t.isFetchNeeded = isFetchNeeded; - t.fetchEvents = fetchEvents; - t.addEventSource = addEventSource; - t.removeEventSource = removeEventSource; - t.updateEvent = updateEvent; - t.renderEvent = renderEvent; - t.removeEvents = removeEvents; - t.clientEvents = clientEvents; - t.normalizeEvent = normalizeEvent; - - - // imports - var trigger = t.trigger; - var getView = t.getView; - var reportEvents = t.reportEvents; - - - // locals - var stickySource = { events: [] }; - var sources = [ stickySource ]; - var rangeStart, rangeEnd; - var currentFetchID = 0; - var pendingSourceCnt = 0; - var loadingLevel = 0; - var cache = []; - - - for (var i=0; i<_sources.length; i++) { - _addEventSource(_sources[i]); - } - - - - /* Fetching - -----------------------------------------------------------------------------*/ - - - function isFetchNeeded(start, end) { - return !rangeStart || start < rangeStart || end > rangeEnd; - } - - - function fetchEvents(start, end) { - rangeStart = start; - rangeEnd = end; - cache = []; - var fetchID = ++currentFetchID; - var len = sources.length; - pendingSourceCnt = len; - for (var i=0; i)), return null instead - return null; -} - - -function parseISO8601(s, ignoreTimezone) { // ignoreTimezone defaults to false - // derived from http://delete.me.uk/2005/03/iso8601.html - // TODO: for a know glitch/feature, read tests/issue_206_parseDate_dst.html - var m = s.match(/^([0-9]{4})(-([0-9]{2})(-([0-9]{2})([T ]([0-9]{2}):([0-9]{2})(:([0-9]{2})(\.([0-9]+))?)?(Z|(([-+])([0-9]{2})(:?([0-9]{2}))?))?)?)?)?$/); - if (!m) { - return null; - } - var date = new Date(m[1], 0, 1); - if (ignoreTimezone || !m[13]) { - var check = new Date(m[1], 0, 1, 9, 0); - if (m[3]) { - date.setMonth(m[3] - 1); - check.setMonth(m[3] - 1); - } - if (m[5]) { - date.setDate(m[5]); - check.setDate(m[5]); - } - fixDate(date, check); - if (m[7]) { - date.setHours(m[7]); - } - if (m[8]) { - date.setMinutes(m[8]); - } - if (m[10]) { - date.setSeconds(m[10]); - } - if (m[12]) { - date.setMilliseconds(Number("0." + m[12]) * 1000); - } - fixDate(date, check); - }else{ - date.setUTCFullYear( - m[1], - m[3] ? m[3] - 1 : 0, - m[5] || 1 - ); - date.setUTCHours( - m[7] || 0, - m[8] || 0, - m[10] || 0, - m[12] ? Number("0." + m[12]) * 1000 : 0 - ); - if (m[14]) { - var offset = Number(m[16]) * 60 + (m[18] ? Number(m[18]) : 0); - offset *= m[15] == '-' ? 1 : -1; - date = new Date(+date + (offset * 60 * 1000)); - } - } - return date; -} - - -function parseTime(s) { // returns minutes since start of day - if (typeof s == 'number') { // an hour - return s * 60; - } - if (typeof s == 'object') { // a Date object - return s.getHours() * 60 + s.getMinutes(); - } - var m = s.match(/(\d+)(?::(\d+))?\s*(\w+)?/); - if (m) { - var h = parseInt(m[1], 10); - if (m[3]) { - h %= 12; - if (m[3].toLowerCase().charAt(0) == 'p') { - h += 12; - } - } - return h * 60 + (m[2] ? parseInt(m[2], 10) : 0); - } -} - - - -/* Date Formatting ------------------------------------------------------------------------------*/ -// TODO: use same function formatDate(date, [date2], format, [options]) - - -function formatDate(date, format, options) { - return formatDates(date, null, format, options); -} - - -function formatDates(date1, date2, format, options) { - options = options || defaults; - var date = date1, - otherDate = date2, - i, len = format.length, c, - i2, formatter, - res = ''; - for (i=0; ii; i2--) { - if (formatter = dateFormatters[format.substring(i, i2)]) { - if (date) { - res += formatter(date, options); - } - i = i2 - 1; - break; - } - } - if (i2 == i) { - if (date) { - res += c; - } - } - } - } - return res; -}; - - -var dateFormatters = { - s : function(d) { return d.getSeconds() }, - ss : function(d) { return zeroPad(d.getSeconds()) }, - m : function(d) { return d.getMinutes() }, - mm : function(d) { return zeroPad(d.getMinutes()) }, - h : function(d) { return d.getHours() % 12 || 12 }, - hh : function(d) { return zeroPad(d.getHours() % 12 || 12) }, - H : function(d) { return d.getHours() }, - HH : function(d) { return zeroPad(d.getHours()) }, - d : function(d) { return d.getDate() }, - dd : function(d) { return zeroPad(d.getDate()) }, - ddd : function(d,o) { return o.dayNamesShort[d.getDay()] }, - dddd: function(d,o) { return o.dayNames[d.getDay()] }, - M : function(d) { return d.getMonth() + 1 }, - MM : function(d) { return zeroPad(d.getMonth() + 1) }, - MMM : function(d,o) { return o.monthNamesShort[d.getMonth()] }, - MMMM: function(d,o) { return o.monthNames[d.getMonth()] }, - yy : function(d) { return (d.getFullYear()+'').substring(2) }, - yyyy: function(d) { return d.getFullYear() }, - t : function(d) { return d.getHours() < 12 ? 'a' : 'p' }, - tt : function(d) { return d.getHours() < 12 ? 'am' : 'pm' }, - T : function(d) { return d.getHours() < 12 ? 'A' : 'P' }, - TT : function(d) { return d.getHours() < 12 ? 'AM' : 'PM' }, - u : function(d) { return formatDate(d, "yyyy-MM-dd'T'HH:mm:ss'Z'") }, - S : function(d) { - var date = d.getDate(); - if (date > 10 && date < 20) { - return 'th'; - } - return ['st', 'nd', 'rd'][date%10-1] || 'th'; - } -}; - - - -fc.applyAll = applyAll; - - -/* Event Date Math ------------------------------------------------------------------------------*/ - - -function exclEndDay(event) { - if (event.end) { - return _exclEndDay(event.end, event.allDay); - }else{ - return addDays(cloneDate(event.start), 1); - } -} - - -function _exclEndDay(end, allDay) { - end = cloneDate(end); - return allDay || end.getHours() || end.getMinutes() ? addDays(end, 1) : clearTime(end); -} - - -function segCmp(a, b) { - return (b.msLength - a.msLength) * 100 + (a.event.start - b.event.start); -} - - -function segsCollide(seg1, seg2) { - return seg1.end > seg2.start && seg1.start < seg2.end; -} - - - -/* Event Sorting ------------------------------------------------------------------------------*/ - - -// event rendering utilities -function sliceSegs(events, visEventEnds, start, end) { - var segs = [], - i, len=events.length, event, - eventStart, eventEnd, - segStart, segEnd, - isStart, isEnd; - for (i=0; i start && eventStart < end) { - if (eventStart < start) { - segStart = cloneDate(start); - isStart = false; - }else{ - segStart = eventStart; - isStart = true; - } - if (eventEnd > end) { - segEnd = cloneDate(end); - isEnd = false; - }else{ - segEnd = eventEnd; - isEnd = true; - } - segs.push({ - event: event, - start: segStart, - end: segEnd, - isStart: isStart, - isEnd: isEnd, - msLength: segEnd - segStart - }); - } - } - return segs.sort(segCmp); -} - - -// event rendering calculation utilities -function stackSegs(segs) { - var levels = [], - i, len = segs.length, seg, - j, collide, k; - for (i=0; i=0; i--) { - res = obj[parts[i].toLowerCase()]; - if (res !== undefined) { - return res; - } - } - return obj['']; -} - - -function htmlEscape(s) { - return s.replace(/&/g, '&') - .replace(//g, '>') - .replace(/'/g, ''') - .replace(/"/g, '"') - .replace(/\n/g, '
'); -} - - -function cssKey(_element) { - return _element.id + '/' + _element.className + '/' + _element.style.cssText.replace(/(^|;)\s*(top|left|width|height)\s*:[^;]*/ig, ''); -} - - -function disableTextSelection(element) { - element - .attr('unselectable', 'on') - .css('MozUserSelect', 'none') - .bind('selectstart.ui', function() { return false; }); -} - - -/* -function enableTextSelection(element) { - element - .attr('unselectable', 'off') - .css('MozUserSelect', '') - .unbind('selectstart.ui'); -} -*/ - - -function markFirstLast(e) { - e.children() - .removeClass('fc-first fc-last') - .filter(':first-child') - .addClass('fc-first') - .end() - .filter(':last-child') - .addClass('fc-last'); -} - - -function setDayID(cell, date) { - cell.each(function(i, _cell) { - _cell.className = _cell.className.replace(/^fc-\w*/, 'fc-' + dayIDs[date.getDay()]); - // TODO: make a way that doesn't rely on order of classes - }); -} - - -function getSkinCss(event, opt) { - var source = event.source || {}; - var eventColor = event.color; - var sourceColor = source.color; - var optionColor = opt('eventColor'); - var backgroundColor = - event.backgroundColor || - eventColor || - source.backgroundColor || - sourceColor || - opt('eventBackgroundColor') || - optionColor; - var borderColor = - event.borderColor || - eventColor || - source.borderColor || - sourceColor || - opt('eventBorderColor') || - optionColor; - var textColor = - event.textColor || - source.textColor || - opt('eventTextColor'); - var statements = []; - if (backgroundColor) { - statements.push('background-color:' + backgroundColor); - } - if (borderColor) { - statements.push('border-color:' + borderColor); - } - if (textColor) { - statements.push('color:' + textColor); - } - return statements.join(';'); -} - - -function applyAll(functions, thisObj, args) { - if ($.isFunction(functions)) { - functions = [ functions ]; - } - if (functions) { - var i; - var ret; - for (i=0; i" + - "
"; - table = $(s).appendTo(element); - - head = table.find('thead'); - headCells = head.find('th'); - body = table.find('tbody'); - bodyRows = body.find('tr'); - bodyCells = body.find('td'); - bodyFirstCells = bodyCells.filter(':first-child'); - bodyCellTopInners = bodyRows.eq(0).find('div.fc-day-content div'); - - markFirstLast(head.add(head.find('tr'))); // marks first+last tr/th's - markFirstLast(bodyRows); // marks first+last td's - bodyRows.eq(0).addClass('fc-first'); // fc-last is done in updateCells - - dayBind(bodyCells); - - daySegmentContainer = - $("
") - .appendTo(element); - } - - - - function updateCells(firstTime) { - var dowDirty = firstTime || rowCnt == 1; // could the cells' day-of-weeks need updating? - var month = t.start.getMonth(); - var today = clearTime(new Date()); - var cell; - var date; - var row; - - if (dowDirty) { - headCells.each(function(i, _cell) { - cell = $(_cell); - date = indexDate(i); - cell.html(formatDate(date, colFormat)); - setDayID(cell, date); - }); - } - - bodyCells.each(function(i, _cell) { - cell = $(_cell); - date = indexDate(i); - if (date.getMonth() == month) { - cell.removeClass('fc-other-month'); - }else{ - cell.addClass('fc-other-month'); - } - if (+date == +today) { - cell.addClass(tm + '-state-highlight fc-today'); - }else{ - cell.removeClass(tm + '-state-highlight fc-today'); - } - cell.find('div.fc-day-number').text(date.getDate()); - if (dowDirty) { - setDayID(cell, date); - } - }); - - bodyRows.each(function(i, _row) { - row = $(_row); - if (i < rowCnt) { - row.show(); - if (i == rowCnt-1) { - row.addClass('fc-last'); - }else{ - row.removeClass('fc-last'); - } - }else{ - row.hide(); - } - }); - } - - - - function setHeight(height) { - viewHeight = height; - - var bodyHeight = viewHeight - head.height(); - var rowHeight; - var rowHeightLast; - var cell; - - if (opt('weekMode') == 'variable') { - rowHeight = rowHeightLast = Math.floor(bodyHeight / (rowCnt==1 ? 2 : 6)); - }else{ - rowHeight = Math.floor(bodyHeight / rowCnt); - rowHeightLast = bodyHeight - rowHeight * (rowCnt-1); - } - - bodyFirstCells.each(function(i, _cell) { - if (i < rowCnt) { - cell = $(_cell); - setMinHeight( - cell.find('> div'), - (i==rowCnt-1 ? rowHeightLast : rowHeight) - vsides(cell) - ); - } - }); - - } - - - function setWidth(width) { - viewWidth = width; - colContentPositions.clear(); - colWidth = Math.floor(viewWidth / colCnt); - setOuterWidth(headCells.slice(0, -1), colWidth); - } - - - - /* Day clicking and binding - -----------------------------------------------------------*/ - - - function dayBind(days) { - days.click(dayClick) - .mousedown(daySelectionMousedown); - } - - - function dayClick(ev) { - if (!opt('selectable')) { // if selectable, SelectionManager will worry about dayClick - var index = parseInt(this.className.match(/fc\-day(\d+)/)[1]); // TODO: maybe use .data - var date = indexDate(index); - trigger('dayClick', this, date, true, ev); - } - } - - - - /* Semi-transparent Overlay Helpers - ------------------------------------------------------*/ - - - function renderDayOverlay(overlayStart, overlayEnd, refreshCoordinateGrid) { // overlayEnd is exclusive - if (refreshCoordinateGrid) { - coordinateGrid.build(); - } - var rowStart = cloneDate(t.visStart); - var rowEnd = addDays(cloneDate(rowStart), colCnt); - for (var i=0; i" + - "" + - "" + - " "; - for (i=0; i"; // fc- needed for setDayID - } - s += - " " + - "" + - "" + - "" + - "" + - " "; - for (i=0; i" + // fc- needed for setDayID - "
" + - "
" + - "
 
" + - "
" + - "
" + - ""; - } - s += - " " + - "" + - "" + - ""; - dayTable = $(s).appendTo(element); - dayHead = dayTable.find('thead'); - dayHeadCells = dayHead.find('th').slice(1, -1); - dayBody = dayTable.find('tbody'); - dayBodyCells = dayBody.find('td').slice(0, -1); - dayBodyCellInners = dayBodyCells.find('div.fc-day-content div'); - dayBodyFirstCell = dayBodyCells.eq(0); - dayBodyFirstCellStretcher = dayBodyFirstCell.find('> div'); - - markFirstLast(dayHead.add(dayHead.find('tr'))); - markFirstLast(dayBody.add(dayBody.find('tr'))); - - axisFirstCells = dayHead.find('th:first'); - gutterCells = dayTable.find('.fc-agenda-gutter'); - - slotLayer = - $("
") - .appendTo(element); - - if (opt('allDaySlot')) { - - daySegmentContainer = - $("
") - .appendTo(slotLayer); - - s = - "" + - "" + - "" + - "" + - "" + - "" + - "
" + opt('allDayText') + "" + - "
" + - "
 
"; - allDayTable = $(s).appendTo(slotLayer); - allDayRow = allDayTable.find('tr'); - - dayBind(allDayRow.find('td')); - - axisFirstCells = axisFirstCells.add(allDayTable.find('th:first')); - gutterCells = gutterCells.add(allDayTable.find('th.fc-agenda-gutter')); - - slotLayer.append( - "
" + - "
" + - "
" - ); - - }else{ - - daySegmentContainer = $([]); // in jQuery 1.4, we can just do $() - - } - - slotScroller = - $("
") - .appendTo(slotLayer); - - slotContent = - $("
") - .appendTo(slotScroller); - - slotSegmentContainer = - $("
") - .appendTo(slotContent); - - s = - "" + - ""; - d = zeroDate(); - maxd = addMinutes(cloneDate(d), maxMinute); - addMinutes(d, minMinute); - slotCnt = 0; - for (i=0; d < maxd; i++) { - minutes = d.getMinutes(); - s += - "" + - "" + - "" + - ""; - addMinutes(d, opt('slotMinutes')); - slotCnt++; - } - s += - "" + - "
" + - ((!slotNormal || !minutes) ? formatDate(d, opt('axisFormat')) : ' ') + - "" + - "
 
" + - "
"; - slotTable = $(s).appendTo(slotContent); - slotTableFirstInner = slotTable.find('div:first'); - - slotBind(slotTable.find('td')); - - axisFirstCells = axisFirstCells.add(slotTable.find('th:first')); - } - - - - function updateCells() { - var i; - var headCell; - var bodyCell; - var date; - var today = clearTime(new Date()); - for (i=0; i= 0) { - addMinutes(d, minMinute + slotIndex * opt('slotMinutes')); - } - return d; - } - - - function colDate(col) { // returns dates with 00:00:00 - return addDays(cloneDate(t.visStart), col*dis+dit); - } - - - function cellIsAllDay(cell) { - return opt('allDaySlot') && !cell.row; - } - - - function dayOfWeekCol(dayOfWeek) { - return ((dayOfWeek - Math.max(firstDay, nwe) + colCnt) % colCnt)*dis+dit; - } - - - - - // get the Y coordinate of the given time on the given day (both Date objects) - function timePosition(day, time) { // both date objects. day holds 00:00 of current day - day = cloneDate(day, true); - if (time < addMinutes(cloneDate(day), minMinute)) { - return 0; - } - if (time >= addMinutes(cloneDate(day), maxMinute)) { - return slotTable.height(); - } - var slotMinutes = opt('slotMinutes'), - minutes = time.getHours()*60 + time.getMinutes() - minMinute, - slotI = Math.floor(minutes / slotMinutes), - slotTop = slotTopCache[slotI]; - if (slotTop === undefined) { - slotTop = slotTopCache[slotI] = slotTable.find('tr:eq(' + slotI + ') td div')[0].offsetTop; //.position().top; // need this optimization??? - } - return Math.max(0, Math.round( - slotTop - 1 + slotHeight * ((minutes % slotMinutes) / slotMinutes) - )); - } - - - function allDayBounds() { - return { - left: axisWidth, - right: viewWidth - gutterWidth - } - } - - - function getAllDayRow(index) { - return allDayRow; - } - - - function defaultEventEnd(event) { - var start = cloneDate(event.start); - if (event.allDay) { - return start; - } - return addMinutes(start, opt('defaultEventMinutes')); - } - - - - /* Selection - ---------------------------------------------------------------------------------*/ - - - function defaultSelectionEnd(startDate, allDay) { - if (allDay) { - return cloneDate(startDate); - } - return addMinutes(cloneDate(startDate), opt('slotMinutes')); - } - - - function renderSelection(startDate, endDate, allDay) { // only for all-day - if (allDay) { - if (opt('allDaySlot')) { - renderDayOverlay(startDate, addDays(cloneDate(endDate), 1), true); - } - }else{ - renderSlotSelection(startDate, endDate); - } - } - - - function renderSlotSelection(startDate, endDate) { - var helperOption = opt('selectHelper'); - coordinateGrid.build(); - if (helperOption) { - var col = dayDiff(startDate, t.visStart) * dis + dit; - if (col >= 0 && col < colCnt) { // only works when times are on same day - var rect = coordinateGrid.rect(0, col, 0, col, slotContent); // only for horizontal coords - var top = timePosition(startDate, startDate); - var bottom = timePosition(startDate, endDate); - if (bottom > top) { // protect against selections that are entirely before or after visible range - rect.top = top; - rect.height = bottom - top; - rect.left += 2; - rect.width -= 5; - if ($.isFunction(helperOption)) { - var helperRes = helperOption(startDate, endDate); - if (helperRes) { - rect.position = 'absolute'; - rect.zIndex = 8; - selectionHelper = $(helperRes) - .css(rect) - .appendTo(slotContent); - } - }else{ - rect.isStart = true; // conside rect a "seg" now - rect.isEnd = true; // - selectionHelper = $(slotSegHtml( - { - title: '', - start: startDate, - end: endDate, - className: ['fc-select-helper'], - editable: false - }, - rect - )); - selectionHelper.css('opacity', opt('dragOpacity')); - } - if (selectionHelper) { - slotBind(selectionHelper); - slotContent.append(selectionHelper); - setOuterWidth(selectionHelper, rect.width, true); // needs to be after appended - setOuterHeight(selectionHelper, rect.height, true); - } - } - } - }else{ - renderSlotOverlay(startDate, endDate); - } - } - - - function clearSelection() { - clearOverlays(); - if (selectionHelper) { - selectionHelper.remove(); - selectionHelper = null; - } - } - - - function slotSelectionMousedown(ev) { - if (ev.which == 1 && opt('selectable')) { // ev.which==1 means left mouse button - unselect(ev); - var dates; - hoverListener.start(function(cell, origCell) { - clearSelection(); - if (cell && cell.col == origCell.col && !cellIsAllDay(cell)) { - var d1 = cellDate(origCell); - var d2 = cellDate(cell); - dates = [ - d1, - addMinutes(cloneDate(d1), opt('slotMinutes')), - d2, - addMinutes(cloneDate(d2), opt('slotMinutes')) - ].sort(cmp); - renderSlotSelection(dates[0], dates[3]); - }else{ - dates = null; - } - }, ev); - $(document).one('mouseup', function(ev) { - hoverListener.stop(); - if (dates) { - if (+dates[0] == +dates[1]) { - reportDayClick(dates[0], false, ev); - } - reportSelection(dates[0], dates[3], false, ev); - } - }); - } - } - - - function reportDayClick(date, allDay, ev) { - trigger('dayClick', dayBodyCells[dayOfWeekCol(date.getDay())], date, allDay, ev); - } - - - - /* External Dragging - --------------------------------------------------------------------------------*/ - - - function dragStart(_dragElement, ev, ui) { - hoverListener.start(function(cell) { - clearOverlays(); - if (cell) { - if (cellIsAllDay(cell)) { - renderCellOverlay(cell.row, cell.col, cell.row, cell.col); - }else{ - var d1 = cellDate(cell); - var d2 = addMinutes(cloneDate(d1), opt('defaultEventMinutes')); - renderSlotOverlay(d1, d2); - } - } - }, ev); - } - - - function dragStop(_dragElement, ev, ui) { - var cell = hoverListener.stop(); - clearOverlays(); - if (cell) { - trigger('drop', _dragElement, cellDate(cell), cellIsAllDay(cell), ev, ui); - } - } - - -} - -function AgendaEventRenderer() { - var t = this; - - - // exports - t.renderEvents = renderEvents; - t.compileDaySegs = compileDaySegs; // for DayEventRenderer - t.clearEvents = clearEvents; - t.slotSegHtml = slotSegHtml; - t.bindDaySeg = bindDaySeg; - - - // imports - DayEventRenderer.call(t); - var opt = t.opt; - var trigger = t.trigger; - //var setOverflowHidden = t.setOverflowHidden; - var isEventDraggable = t.isEventDraggable; - var isEventResizable = t.isEventResizable; - var eventEnd = t.eventEnd; - var reportEvents = t.reportEvents; - var reportEventClear = t.reportEventClear; - var eventElementHandlers = t.eventElementHandlers; - var setHeight = t.setHeight; - var getDaySegmentContainer = t.getDaySegmentContainer; - var getSlotSegmentContainer = t.getSlotSegmentContainer; - var getHoverListener = t.getHoverListener; - var getMaxMinute = t.getMaxMinute; - var getMinMinute = t.getMinMinute; - var timePosition = t.timePosition; - var colContentLeft = t.colContentLeft; - var colContentRight = t.colContentRight; - var renderDaySegs = t.renderDaySegs; - var resizableDayEvent = t.resizableDayEvent; // TODO: streamline binding architecture - var getColCnt = t.getColCnt; - var getColWidth = t.getColWidth; - var getSlotHeight = t.getSlotHeight; - var getBodyContent = t.getBodyContent; - var reportEventElement = t.reportEventElement; - var showEvents = t.showEvents; - var hideEvents = t.hideEvents; - var eventDrop = t.eventDrop; - var eventResize = t.eventResize; - var renderDayOverlay = t.renderDayOverlay; - var clearOverlays = t.clearOverlays; - var calendar = t.calendar; - var formatDate = calendar.formatDate; - var formatDates = calendar.formatDates; - - - - /* Rendering - ----------------------------------------------------------------------------*/ - - - function renderEvents(events, modifiedEventId) { - reportEvents(events); - var i, len=events.length, - dayEvents=[], - slotEvents=[]; - for (i=0; i" + - "
" + - "
" + - "
" + - htmlEscape(formatDates(event.start, event.end, opt('timeFormat'))) + - "
" + - "
" + - "
" + - "
" + - htmlEscape(event.title) + - "
" + - "
" + - "
" + - "
"; // close inner - if (seg.isEnd && isEventResizable(event)) { - html += - "
=
"; - } - html += - ""; - return html; - } - - - function bindDaySeg(event, eventElement, seg) { - if (isEventDraggable(event)) { - draggableDayEvent(event, eventElement, seg.isStart); - } - if (seg.isEnd && isEventResizable(event)) { - resizableDayEvent(event, eventElement, seg); - } - eventElementHandlers(event, eventElement); - // needs to be after, because resizableDayEvent might stopImmediatePropagation on click - } - - - function bindSlotSeg(event, eventElement, seg) { - var timeElement = eventElement.find('div.fc-event-time'); - if (isEventDraggable(event)) { - draggableSlotEvent(event, eventElement, timeElement); - } - if (seg.isEnd && isEventResizable(event)) { - resizableSlotEvent(event, eventElement, timeElement); - } - eventElementHandlers(event, eventElement); - } - - - - /* Dragging - -----------------------------------------------------------------------------------*/ - - - // when event starts out FULL-DAY - - function draggableDayEvent(event, eventElement, isStart) { - var origWidth; - var revert; - var allDay=true; - var dayDelta; - var dis = opt('isRTL') ? -1 : 1; - var hoverListener = getHoverListener(); - var colWidth = getColWidth(); - var slotHeight = getSlotHeight(); - var minMinute = getMinMinute(); - eventElement.draggable({ - zIndex: 9, - opacity: opt('dragOpacity', 'month'), // use whatever the month view was using - revertDuration: opt('dragRevertDuration'), - start: function(ev, ui) { - trigger('eventDragStart', eventElement, event, ev, ui); - hideEvents(event, eventElement); - origWidth = eventElement.width(); - hoverListener.start(function(cell, origCell, rowDelta, colDelta) { - clearOverlays(); - if (cell) { - //setOverflowHidden(true); - revert = false; - dayDelta = colDelta * dis; - if (!cell.row) { - // on full-days - renderDayOverlay( - addDays(cloneDate(event.start), dayDelta), - addDays(exclEndDay(event), dayDelta) - ); - resetElement(); - }else{ - // mouse is over bottom slots - if (isStart) { - if (allDay) { - // convert event to temporary slot-event - eventElement.width(colWidth - 10); // don't use entire width - setOuterHeight( - eventElement, - slotHeight * Math.round( - (event.end ? ((event.end - event.start) / MINUTE_MS) : opt('defaultEventMinutes')) - / opt('slotMinutes') - ) - ); - eventElement.draggable('option', 'grid', [colWidth, 1]); - allDay = false; - } - }else{ - revert = true; - } - } - revert = revert || (allDay && !dayDelta); - }else{ - resetElement(); - //setOverflowHidden(false); - revert = true; - } - eventElement.draggable('option', 'revert', revert); - }, ev, 'drag'); - }, - stop: function(ev, ui) { - hoverListener.stop(); - clearOverlays(); - trigger('eventDragStop', eventElement, event, ev, ui); - if (revert) { - // hasn't moved or is out of bounds (draggable has already reverted) - resetElement(); - eventElement.css('filter', ''); // clear IE opacity side-effects - showEvents(event, eventElement); - }else{ - // changed! - var minuteDelta = 0; - if (!allDay) { - minuteDelta = Math.round((eventElement.offset().top - getBodyContent().offset().top) / slotHeight) - * opt('slotMinutes') - + minMinute - - (event.start.getHours() * 60 + event.start.getMinutes()); - } - eventDrop(this, event, dayDelta, minuteDelta, allDay, ev, ui); - } - //setOverflowHidden(false); - } - }); - function resetElement() { - if (!allDay) { - eventElement - .width(origWidth) - .height('') - .draggable('option', 'grid', null); - allDay = true; - } - } - } - - - // when event starts out IN TIMESLOTS - - function draggableSlotEvent(event, eventElement, timeElement) { - var origPosition; - var allDay=false; - var dayDelta; - var minuteDelta; - var prevMinuteDelta; - var dis = opt('isRTL') ? -1 : 1; - var hoverListener = getHoverListener(); - var colCnt = getColCnt(); - var colWidth = getColWidth(); - var slotHeight = getSlotHeight(); - eventElement.draggable({ - zIndex: 9, - scroll: false, - grid: [colWidth, slotHeight], - axis: colCnt==1 ? 'y' : false, - opacity: opt('dragOpacity'), - revertDuration: opt('dragRevertDuration'), - start: function(ev, ui) { - trigger('eventDragStart', eventElement, event, ev, ui); - hideEvents(event, eventElement); - origPosition = eventElement.position(); - minuteDelta = prevMinuteDelta = 0; - hoverListener.start(function(cell, origCell, rowDelta, colDelta) { - eventElement.draggable('option', 'revert', !cell); - clearOverlays(); - if (cell) { - dayDelta = colDelta * dis; - if (opt('allDaySlot') && !cell.row) { - // over full days - if (!allDay) { - // convert to temporary all-day event - allDay = true; - timeElement.hide(); - eventElement.draggable('option', 'grid', null); - } - renderDayOverlay( - addDays(cloneDate(event.start), dayDelta), - addDays(exclEndDay(event), dayDelta) - ); - }else{ - // on slots - resetElement(); - } - } - }, ev, 'drag'); - }, - drag: function(ev, ui) { - minuteDelta = Math.round((ui.position.top - origPosition.top) / slotHeight) * opt('slotMinutes'); - if (minuteDelta != prevMinuteDelta) { - if (!allDay) { - updateTimeText(minuteDelta); - } - prevMinuteDelta = minuteDelta; - } - }, - stop: function(ev, ui) { - var cell = hoverListener.stop(); - clearOverlays(); - trigger('eventDragStop', eventElement, event, ev, ui); - if (cell && (dayDelta || minuteDelta || allDay)) { - // changed! - eventDrop(this, event, dayDelta, allDay ? 0 : minuteDelta, allDay, ev, ui); - }else{ - // either no change or out-of-bounds (draggable has already reverted) - resetElement(); - eventElement.css('filter', ''); // clear IE opacity side-effects - eventElement.css(origPosition); // sometimes fast drags make event revert to wrong position - updateTimeText(0); - showEvents(event, eventElement); - } - } - }); - function updateTimeText(minuteDelta) { - var newStart = addMinutes(cloneDate(event.start), minuteDelta); - var newEnd; - if (event.end) { - newEnd = addMinutes(cloneDate(event.end), minuteDelta); - } - timeElement.text(formatDates(newStart, newEnd, opt('timeFormat'))); - } - function resetElement() { - // convert back to original slot-event - if (allDay) { - timeElement.css('display', ''); // show() was causing display=inline - eventElement.draggable('option', 'grid', [colWidth, slotHeight]); - allDay = false; - } - } - } - - - - /* Resizing - --------------------------------------------------------------------------------------*/ - - - function resizableSlotEvent(event, eventElement, timeElement) { - var slotDelta, prevSlotDelta; - var slotHeight = getSlotHeight(); - eventElement.resizable({ - handles: { - s: 'div.ui-resizable-s' - }, - grid: slotHeight, - start: function(ev, ui) { - slotDelta = prevSlotDelta = 0; - hideEvents(event, eventElement); - eventElement.css('z-index', 9); - trigger('eventResizeStart', this, event, ev, ui); - }, - resize: function(ev, ui) { - // don't rely on ui.size.height, doesn't take grid into account - slotDelta = Math.round((Math.max(slotHeight, eventElement.height()) - ui.originalSize.height) / slotHeight); - if (slotDelta != prevSlotDelta) { - timeElement.text( - formatDates( - event.start, - (!slotDelta && !event.end) ? null : // no change, so don't display time range - addMinutes(eventEnd(event), opt('slotMinutes')*slotDelta), - opt('timeFormat') - ) - ); - prevSlotDelta = slotDelta; - } - }, - stop: function(ev, ui) { - trigger('eventResizeStop', this, event, ev, ui); - if (slotDelta) { - eventResize(this, event, 0, opt('slotMinutes')*slotDelta, ev, ui); - }else{ - eventElement.css('z-index', 8); - showEvents(event, eventElement); - // BUG: if event was really short, need to put title back in span - } - } - }); - } - - -} - - -function countForwardSegs(levels) { - var i, j, k, level, segForward, segBack; - for (i=levels.length-1; i>0; i--) { - level = levels[i]; - for (j=0; j"); - var elements; - var segmentContainer = getDaySegmentContainer(); - var i; - var segCnt = segs.length; - var element; - tempContainer[0].innerHTML = daySegHTML(segs); // faster than .html() - elements = tempContainer.children(); - segmentContainer.append(elements); - daySegElementResolve(segs, elements); - daySegCalcHSides(segs); - daySegSetWidths(segs); - daySegCalcHeights(segs); - daySegSetTops(segs, getRowTops(getRowDivs())); - elements = []; - for (i=0; i" + - ""; - if (!event.allDay && seg.isStart) { - html += - "" + - htmlEscape(formatDates(event.start, event.end, opt('timeFormat'))) + - ""; - } - html += - "" + htmlEscape(event.title) + "" + - "
"; - if (seg.isEnd && isEventResizable(event)) { - html += - "
" + - "   " + // makes hit area a lot better for IE6/7 - "
"; - } - html += - ""; - seg.left = left; - seg.outerWidth = right - left; - seg.startCol = leftCol; - seg.endCol = rightCol + 1; // needs to be exclusive - } - return html; - } - - - function daySegElementResolve(segs, elements) { // sets seg.element - var i; - var segCnt = segs.length; - var seg; - var event; - var element; - var triggerRes; - for (i=0; i div'); // optimal selector? - } - return rowDivs; - } - - - function getRowTops(rowDivs) { - var i; - var rowCnt = rowDivs.length; - var tops = []; - for (i=0; i selection for IE - element - .mousedown(function(ev) { // prevent native selection for others - ev.preventDefault(); - }) - .click(function(ev) { - if (isResizing) { - ev.preventDefault(); // prevent link from being visited (only method that worked in IE6) - ev.stopImmediatePropagation(); // prevent fullcalendar eventClick handler from being called - // (eventElementHandlers needs to be bound after resizableDayEvent) - } - }); - - handle.mousedown(function(ev) { - if (ev.which != 1) { - return; // needs to be left mouse button - } - isResizing = true; - var hoverListener = t.getHoverListener(); - var rowCnt = getRowCnt(); - var colCnt = getColCnt(); - var dis = rtl ? -1 : 1; - var dit = rtl ? colCnt-1 : 0; - var elementTop = element.css('top'); - var dayDelta; - var helpers; - var eventCopy = $.extend({}, event); - var minCell = dateCell(event.start); - clearSelection(); - $('body') - .css('cursor', direction + '-resize') - .one('mouseup', mouseup); - trigger('eventResizeStart', this, event, ev); - hoverListener.start(function(cell, origCell) { - if (cell) { - var r = Math.max(minCell.row, cell.row); - var c = cell.col; - if (rowCnt == 1) { - r = 0; // hack for all-day area in agenda views - } - if (r == minCell.row) { - if (rtl) { - c = Math.min(minCell.col, c); - }else{ - c = Math.max(minCell.col, c); - } - } - dayDelta = (r*7 + c*dis+dit) - (origCell.row*7 + origCell.col*dis+dit); - var newEnd = addDays(eventEnd(event), dayDelta, true); - if (dayDelta) { - eventCopy.end = newEnd; - var oldHelpers = helpers; - helpers = renderTempDaySegs(compileDaySegs([eventCopy]), seg.row, elementTop); - helpers.find('*').css('cursor', direction + '-resize'); - if (oldHelpers) { - oldHelpers.remove(); - } - hideEvents(event); - }else{ - if (helpers) { - showEvents(event); - helpers.remove(); - helpers = null; - } - } - clearOverlays(); - renderDayOverlay(event.start, addDays(cloneDate(newEnd), 1)); // coordinate grid already rebuild at hoverListener.start - } - }, ev); - - function mouseup(ev) { - trigger('eventResizeStop', this, event, ev); - $('body').css('cursor', ''); - hoverListener.stop(); - clearOverlays(); - if (dayDelta) { - eventResize(this, event, dayDelta, 0, ev); - // event redraw will clear helpers - } - // otherwise, the drag handler already restored the old events - - setTimeout(function() { // make this happen after the element's click event - isResizing = false; - },0); - } - - }); - } - - -} - -//BUG: unselect needs to be triggered when events are dragged+dropped - -function SelectionManager() { - var t = this; - - - // exports - t.select = select; - t.unselect = unselect; - t.reportSelection = reportSelection; - t.daySelectionMousedown = daySelectionMousedown; - - - // imports - var opt = t.opt; - var trigger = t.trigger; - var defaultSelectionEnd = t.defaultSelectionEnd; - var renderSelection = t.renderSelection; - var clearSelection = t.clearSelection; - - - // locals - var selected = false; - - - - // unselectAuto - if (opt('selectable') && opt('unselectAuto')) { - $(document).mousedown(function(ev) { - var ignore = opt('unselectCancel'); - if (ignore) { - if ($(ev.target).parents(ignore).length) { // could be optimized to stop after first match - return; - } - } - unselect(ev); - }); - } - - - function select(startDate, endDate, allDay) { - unselect(); - if (!endDate) { - endDate = defaultSelectionEnd(startDate, allDay); - } - renderSelection(startDate, endDate, allDay); - reportSelection(startDate, endDate, allDay); - } - - - function unselect(ev) { - if (selected) { - selected = false; - clearSelection(); - trigger('unselect', null, ev); - } - } - - - function reportSelection(startDate, endDate, allDay, ev) { - selected = true; - trigger('select', null, startDate, endDate, allDay, ev); - } - - - function daySelectionMousedown(ev) { // not really a generic manager method, oh well - var cellDate = t.cellDate; - var cellIsAllDay = t.cellIsAllDay; - var hoverListener = t.getHoverListener(); - var reportDayClick = t.reportDayClick; // this is hacky and sort of weird - if (ev.which == 1 && opt('selectable')) { // which==1 means left mouse button - unselect(ev); - var _mousedownElement = this; - var dates; - hoverListener.start(function(cell, origCell) { // TODO: maybe put cellDate/cellIsAllDay info in cell - clearSelection(); - if (cell && cellIsAllDay(cell)) { - dates = [ cellDate(origCell), cellDate(cell) ].sort(cmp); - renderSelection(dates[0], dates[1], true); - }else{ - dates = null; - } - }, ev); - $(document).one('mouseup', function(ev) { - hoverListener.stop(); - if (dates) { - if (+dates[0] == +dates[1]) { - reportDayClick(dates[0], true, ev); - } - reportSelection(dates[0], dates[1], true, ev); - } - }); - } - } - - -} - -function OverlayManager() { - var t = this; - - - // exports - t.renderOverlay = renderOverlay; - t.clearOverlays = clearOverlays; - - - // locals - var usedOverlays = []; - var unusedOverlays = []; - - - function renderOverlay(rect, parent) { - var e = unusedOverlays.shift(); - if (!e) { - e = $("
"); - } - if (e[0].parentNode != parent[0]) { - e.appendTo(parent); - } - usedOverlays.push(e.css(rect).show()); - return e; - } - - - function clearOverlays() { - var e; - while (e = usedOverlays.shift()) { - unusedOverlays.push(e.hide().unbind()); - } - } - - -} - -function CoordinateGrid(buildFunc) { - - var t = this; - var rows; - var cols; - - - t.build = function() { - rows = []; - cols = []; - buildFunc(rows, cols); - }; - - - t.cell = function(x, y) { - var rowCnt = rows.length; - var colCnt = cols.length; - var i, r=-1, c=-1; - for (i=0; i= rows[i][0] && y < rows[i][1]) { - r = i; - break; - } - } - for (i=0; i= cols[i][0] && x < cols[i][1]) { - c = i; - break; - } - } - return (r>=0 && c>=0) ? { row:r, col:c } : null; - }; - - - t.rect = function(row0, col0, row1, col1, originElement) { // row1,col1 is inclusive - var origin = originElement.offset(); - return { - top: rows[row0][0] - origin.top, - left: cols[col0][0] - origin.left, - width: cols[col1][1] - cols[col0][0], - height: rows[row1][1] - rows[row0][0] - }; - }; - -} - -function HoverListener(coordinateGrid) { - - - var t = this; - var bindType; - var change; - var firstCell; - var cell; - - - t.start = function(_change, ev, _bindType) { - change = _change; - firstCell = cell = null; - coordinateGrid.build(); - mouse(ev); - bindType = _bindType || 'mousemove'; - $(document).bind(bindType, mouse); - }; - - - function mouse(ev) { - _fixUIEvent(ev); // see below - var newCell = coordinateGrid.cell(ev.pageX, ev.pageY); - if (!newCell != !cell || newCell && (newCell.row != cell.row || newCell.col != cell.col)) { - if (newCell) { - if (!firstCell) { - firstCell = newCell; - } - change(newCell, firstCell, newCell.row-firstCell.row, newCell.col-firstCell.col); - }else{ - change(newCell, firstCell); - } - cell = newCell; - } - } - - - t.stop = function() { - $(document).unbind(bindType, mouse); - return cell; - }; - - -} - - - -// this fix was only necessary for jQuery UI 1.8.16 (and jQuery 1.7 or 1.7.1) -// upgrading to jQuery UI 1.8.17 (and using either jQuery 1.7 or 1.7.1) fixed the problem -// but keep this in here for 1.8.16 users -// and maybe remove it down the line - -function _fixUIEvent(event) { // for issue 1168 - if (event.pageX === undefined) { - event.pageX = event.originalEvent.pageX; - event.pageY = event.originalEvent.pageY; - } -} -function HorizontalPositionCache(getElement) { - - var t = this, - elements = {}, - lefts = {}, - rights = {}; - - function e(i) { - return elements[i] = elements[i] || getElement(i); - } - - t.left = function(i) { - return lefts[i] = lefts[i] === undefined ? e(i).position().left : lefts[i]; - }; - - t.right = function(i) { - return rights[i] = rights[i] === undefined ? t.left(i) + e(i).width() : rights[i]; - }; - - t.clear = function() { - elements = {}; - lefts = {}; - rights = {}; - }; - -} - -})(jQuery); diff --git a/www/plugins/fullcalendar-1.5.3/fullcalendar.min.js b/www/plugins/fullcalendar-1.5.3/fullcalendar.min.js deleted file mode 100644 index ad119bc31..000000000 --- a/www/plugins/fullcalendar-1.5.3/fullcalendar.min.js +++ /dev/null @@ -1,114 +0,0 @@ -/* - - FullCalendar v1.5.3 - http://arshaw.com/fullcalendar/ - - Use fullcalendar.css for basic styling. - For event drag & drop, requires jQuery UI draggable. - For event resizing, requires jQuery UI resizable. - - Copyright (c) 2011 Adam Shaw - Dual licensed under the MIT and GPL licenses, located in - MIT-LICENSE.txt and GPL-LICENSE.txt respectively. - - Date: Mon Feb 6 22:40:40 2012 -0800 - -*/ -(function(m,ma){function wb(a){m.extend(true,Ya,a)}function Yb(a,b,e){function d(k){if(E){u();q();na();S(k)}else f()}function f(){B=b.theme?"ui":"fc";a.addClass("fc");b.isRTL&&a.addClass("fc-rtl");b.theme&&a.addClass("ui-widget");E=m("
").prependTo(a);C=new Zb(X,b);(P=C.render())&&a.prepend(P);y(b.defaultView);m(window).resize(oa);t()||g()}function g(){setTimeout(function(){!n.start&&t()&&S()},0)}function l(){m(window).unbind("resize",oa);C.destroy(); -E.remove();a.removeClass("fc fc-rtl ui-widget")}function j(){return i.offsetWidth!==0}function t(){return m("body")[0].offsetWidth!==0}function y(k){if(!n||k!=n.name){F++;pa();var D=n,Z;if(D){(D.beforeHide||xb)();Za(E,E.height());D.element.hide()}else Za(E,1);E.css("overflow","hidden");if(n=Y[k])n.element.show();else n=Y[k]=new Ja[k](Z=s=m("
").appendTo(E),X);D&&C.deactivateButton(D.name);C.activateButton(k);S();E.css("overflow","");D&& -Za(E,1);Z||(n.afterShow||xb)();F--}}function S(k){if(j()){F++;pa();o===ma&&u();var D=false;if(!n.start||k||r=n.end){n.render(r,k||0);fa(true);D=true}else if(n.sizeDirty){n.clearEvents();fa();D=true}else if(n.eventsDirty){n.clearEvents();D=true}n.sizeDirty=false;n.eventsDirty=false;ga(D);W=a.outerWidth();C.updateTitle(n.title);k=new Date;k>=n.start&&k").append(m("").append(f("left")).append(f("center")).append(f("right")))}function d(){Q.remove()}function f(u){var fa=m("");(u=b.header[u])&&m.each(u.split(" "),function(oa){oa>0&&fa.append("");var ga; -m.each(this.split(","),function(ra,sa){if(sa=="title"){fa.append("

 

");ga&&ga.addClass(q+"-corner-right");ga=null}else{var ha;if(a[sa])ha=a[sa];else if(Ja[sa])ha=function(){na.removeClass(q+"-state-hover");a.changeView(sa)};if(ha){ra=b.theme?jb(b.buttonIcons,sa):null;var da=jb(b.buttonText,sa),na=m(""+(ra?"":da)+"");if(na){na.click(function(){na.hasClass(q+"-state-disabled")||ha()}).mousedown(function(){na.not("."+q+"-state-active").not("."+q+"-state-disabled").addClass(q+"-state-down")}).mouseup(function(){na.removeClass(q+"-state-down")}).hover(function(){na.not("."+q+"-state-active").not("."+q+"-state-disabled").addClass(q+"-state-hover")},function(){na.removeClass(q+"-state-hover").removeClass(q+"-state-down")}).appendTo(fa); -ga||na.addClass(q+"-corner-left");ga=na}}}});ga&&ga.addClass(q+"-corner-right")});return fa}function g(u){Q.find("h2").html(u)}function l(u){Q.find("span.fc-button-"+u).addClass(q+"-state-active")}function j(u){Q.find("span.fc-button-"+u).removeClass(q+"-state-active")}function t(u){Q.find("span.fc-button-"+u).addClass(q+"-state-disabled")}function y(u){Q.find("span.fc-button-"+u).removeClass(q+"-state-disabled")}var S=this;S.render=e;S.destroy=d;S.updateTitle=g;S.activateButton=l;S.deactivateButton= -j;S.disableButton=t;S.enableButton=y;var Q=m([]),q}function $b(a,b){function e(c,z){return!ca||cka}function d(c,z){ca=c;ka=z;L=[];c=++qa;G=z=U.length;for(var H=0;Hl;y--)if(S=dc[e.substring(l,y)]){if(f)Q+=S(f,d);l=y-1;break}if(y==l)if(f)Q+=t}}return Q}function Ua(a){return a.end?ec(a.end,a.allDay):ba(N(a.start),1)}function ec(a,b){a=N(a);return b||a.getHours()||a.getMinutes()?ba(a,1):Ka(a)}function fc(a,b){return(b.msLength-a.msLength)*100+(a.event.start-b.event.start)}function Cb(a,b){return a.end>b.start&&a.starte&&td){y=N(d);Q=false}else{y=y;Q=true}f.push({event:j,start:t,end:y,isStart:S,isEnd:Q,msLength:y-t})}}return f.sort(fc)}function ob(a){var b=[],e,d=a.length,f,g,l,j;for(e=0;e=0;e--){d=a[b[e].toLowerCase()];if(d!== -ma)return d}return a[""]}function Qa(a){return a.replace(/&/g,"&").replace(//g,">").replace(/'/g,"'").replace(/"/g,""").replace(/\n/g,"
")}function Ib(a){return a.id+"/"+a.className+"/"+a.style.cssText.replace(/(^|;)\s*(top|left|width|height)\s*:[^;]*/ig,"")}function qb(a){a.attr("unselectable","on").css("MozUserSelect","none").bind("selectstart.ui",function(){return false})}function ab(a){a.children().removeClass("fc-first fc-last").filter(":first-child").addClass("fc-first").end().filter(":last-child").addClass("fc-last")} -function rb(a,b){a.each(function(e,d){d.className=d.className.replace(/^fc-\w*/,"fc-"+lc[b.getDay()])})}function Jb(a,b){var e=a.source||{},d=a.color,f=e.color,g=b("eventColor"),l=a.backgroundColor||d||e.backgroundColor||f||b("eventBackgroundColor")||g;d=a.borderColor||d||e.borderColor||f||b("eventBorderColor")||g;a=a.textColor||e.textColor||b("eventTextColor");b=[];l&&b.push("background-color:"+l);d&&b.push("border-color:"+d);a&&b.push("color:"+a);return b.join(";")}function $a(a,b,e){if(m.isFunction(a))a= -[a];if(a){var d,f;for(d=0;d";for(aa=0;aa";R+="";for(aa=0;aa";for(V=0;V
"+(I?"
":"")+"
 
";R+=""}R+="";w= -m(R).appendTo(a);K=w.find("thead");i=K.find("th");C=w.find("tbody");P=C.find("tr");E=C.find("td");B=E.filter(":first-child");n=P.eq(0).find("div.fc-day-content div");ab(K.add(K.find("tr")));ab(P);P.eq(0).addClass("fc-first");y(E);Y=m("
").appendTo(a)}function l(w){var I=w||v==1,R=p.start.getMonth(),V=Ka(new Date),ea,aa,va;I&&i.each(function(wa,Ga){ea=m(Ga);aa=ca(wa);ea.html(ya(aa,$));rb(ea,aa)});E.each(function(wa,Ga){ea=m(Ga);aa=ca(wa);aa.getMonth()== -R?ea.removeClass("fc-other-month"):ea.addClass("fc-other-month");+aa==+V?ea.addClass(la+"-state-highlight fc-today"):ea.removeClass(la+"-state-highlight fc-today");ea.find("div.fc-day-number").text(aa.getDate());I&&rb(ea,aa)});P.each(function(wa,Ga){va=m(Ga);if(wa div"),(ea==v-1?R:I)-Sa(V))}})}function t(w){W=w;M.clear();s=Math.floor(W/F);Va(i.slice(0,-1),s)}function y(w){w.click(S).mousedown(X)}function S(w){if(!L("selectable")){var I=parseInt(this.className.match(/fc\-day(\d+)/)[1]);I=ca(I);c("dayClick",this,I,true,w)}}function Q(w,I,R){R&&r.build();R=N(p.visStart);for(var V=ba(N(R),F),ea=0;ea ";for(A=0;A";x+="  ";for(A=0;A
 
";x+=" ";v=m(x).appendTo(a);F=v.find("thead");r=F.find("th").slice(1,-1);J=v.find("tbody");M=J.find("td").slice(0,-1);k=M.find("div.fc-day-content div");D=M.eq(0);Z=D.find("> div");ab(F.add(F.find("tr")));ab(J.add(J.find("tr")));aa=F.find("th:first");va=v.find(".fc-agenda-gutter");ja=m("
").appendTo(a); -if(i("allDaySlot")){ia=m("
").appendTo(ja);x="
"+i("allDayText")+"
 
";la=m(x).appendTo(ja);$=la.find("tr");q($.find("td"));aa=aa.add(la.find("th:first"));va=va.add(la.find("th.fc-agenda-gutter"));ja.append("
")}else ia=m([]);w=m("
").appendTo(ja);I=m("
").appendTo(w);R=m("
").appendTo(I);x="";ta=zb();za=xa(N(ta),bb);xa(ta,La);for(A=tb=0;ta";xa(ta,i("slotMinutes"));tb++}x+="
"+(!Ea||!Da?s(ta,i("axisFormat")):" ")+"
 
";V=m(x).appendTo(I);ea=V.find("div:first");u(V.find("td"));aa=aa.add(V.find("th:first"))}function l(){var h,O,x,A,ta=Ka(new Date);for(h=0;h=0&&xa(O,La+h*i("slotMinutes"));return O}function ua(h){return ba(N(K.visStart),h*Ha+Ia)}function pa(h){return i("allDaySlot")&&!h.row}function U(h){return(h-Math.max(Tb,Sb)+Ba)%Ba*Ha+Ia}function ca(h,O){h=N(h,true);if(O=xa(N(h),bb))return V.height(); -h=i("slotMinutes");O=O.getHours()*60+O.getMinutes()-La;var x=Math.floor(O/h),A=ub[x];if(A===ma)A=ub[x]=V.find("tr:eq("+x+") td div")[0].offsetTop;return Math.max(0,Math.round(A-1+Xa*(O%h/h)))}function ka(){return{left:Ma,right:Ga-vb}}function qa(){return $}function G(h){var O=N(h.start);if(h.allDay)return O;return xa(O,i("defaultEventMinutes"))}function p(h,O){if(O)return N(h);return xa(N(h),i("slotMinutes"))}function L(h,O,x){if(x)i("allDaySlot")&&oa(h,ba(N(O),1),true);else c(h,O)}function c(h,O){var x= -i("selectHelper");Na.build();if(x){var A=Ca(h,K.visStart)*Ha+Ia;if(A>=0&&Ata){A.top=ta;A.height=za-ta;A.left+=2;A.width-=5;if(m.isFunction(x)){if(h=x(h,O)){A.position="absolute";A.zIndex=8;wa=m(h).css(A).appendTo(I)}}else{A.isStart=true;A.isEnd=true;wa=m(o({title:"",start:h,end:O,className:["fc-select-helper"],editable:false},A));wa.css("opacity",i("dragOpacity"))}if(wa){u(wa);I.append(wa);Va(wa,A.width,true);Eb(wa,A.height,true)}}}}else ra(h, -O)}function z(){B();if(wa){wa.remove();wa=null}}function H(h){if(h.which==1&&i("selectable")){Y(h);var O;Ra.start(function(x,A){z();if(x&&x.col==A.col&&!pa(x)){A=na(A);x=na(x);O=[A,xa(N(A),i("slotMinutes")),x,xa(N(x),i("slotMinutes"))].sort(Gb);c(O[0],O[3])}else O=null},h);m(document).one("mouseup",function(x){Ra.stop();if(O){+O[0]==+O[1]&&T(O[0],false,x);n(O[0],O[3],false,x)}})}}function T(h,O,x){C("dayClick",M[U(h.getDay())],h,O,x)}function X(h,O){Ra.start(function(x){B();if(x)if(pa(x))ga(x.row, -x.col,x.row,x.col);else{x=na(x);var A=xa(N(x),i("defaultEventMinutes"));ra(x,A)}},O)}function ya(h,O,x){var A=Ra.stop();B();A&&C("drop",h,na(A),pa(A),O,x)}var K=this;K.renderAgenda=d;K.setWidth=t;K.setHeight=j;K.beforeHide=S;K.afterShow=Q;K.defaultEventEnd=G;K.timePosition=ca;K.dayOfWeekCol=U;K.dateCell=da;K.cellDate=na;K.cellIsAllDay=pa;K.allDayRow=qa;K.allDayBounds=ka;K.getHoverListener=function(){return Ra};K.colContentLeft=sa;K.colContentRight=ha;K.getDaySegmentContainer=function(){return ia}; -K.getSlotSegmentContainer=function(){return R};K.getMinMinute=function(){return La};K.getMaxMinute=function(){return bb};K.getBodyContent=function(){return I};K.getRowCnt=function(){return 1};K.getColCnt=function(){return Ba};K.getColWidth=function(){return db};K.getSlotHeight=function(){return Xa};K.defaultSelectionEnd=p;K.renderDayOverlay=oa;K.renderSelection=L;K.clearSelection=z;K.reportDayClick=T;K.dragStart=X;K.dragStop=ya;Kb.call(K,a,b,e);Lb.call(K);Mb.call(K);sc.call(K);var i=K.opt,C=K.trigger, -P=K.clearEvents,E=K.renderOverlay,B=K.clearOverlays,n=K.reportSelection,Y=K.unselect,W=K.daySelectionMousedown,o=K.slotSegHtml,s=b.formatDate,v,F,r,J,M,k,D,Z,ja,ia,la,$,w,I,R,V,ea,aa,va,wa,Ga,Wb,Ma,db,vb,Xa,Xb,Ba,tb,Na,Ra,cb,ub={},Wa,Tb,Sb,Ub,Ha,Ia,La,bb,Vb;qb(a.addClass("fc-agenda"));Na=new Nb(function(h,O){function x(eb){return Math.max(Ea,Math.min(tc,eb))}var A,ta,za;r.each(function(eb,uc){A=m(uc);ta=A.offset().left;if(eb)za[1]=ta;za=[ta];O[eb]=za});za[1]=ta+A.outerWidth();if(i("allDaySlot")){A= -$;ta=A.offset().top;h[0]=[ta,ta+A.outerHeight()]}for(var Da=I.offset().top,Ea=w.offset().top,tc=Ea+w.outerHeight(),fb=0;fb
"+Qa(W(o.start,o.end,u("timeFormat")))+"
"+Qa(o.title)+"
";if(s.isEnd&&ga(o))v+="
=
"; -v+="";return v}function j(o,s,v){oa(o)&&y(o,s,v.isStart);v.isEnd&&ga(o)&&c(o,s,v);da(o,s)}function t(o,s,v){var F=s.find("div.fc-event-time");oa(o)&&S(o,s,F);v.isEnd&&ga(o)&&Q(o,s,F);da(o,s)}function y(o,s,v){function F(){if(!M){s.width(r).height("").draggable("option","grid",null);M=true}}var r,J,M=true,k,D=u("isRTL")?-1:1,Z=U(),ja=H(),ia=T(),la=ka();s.draggable({zIndex:9,opacity:u("dragOpacity","month"),revertDuration:u("dragRevertDuration"),start:function($,w){fa("eventDragStart", -s,o,$,w);i(o,s);r=s.width();Z.start(function(I,R,V,ea){B();if(I){J=false;k=ea*D;if(I.row)if(v){if(M){s.width(ja-10);Eb(s,ia*Math.round((o.end?(o.end-o.start)/wc:u("defaultEventMinutes"))/u("slotMinutes")));s.draggable("option","grid",[ja,1]);M=false}}else J=true;else{E(ba(N(o.start),k),ba(Ua(o),k));F()}J=J||M&&!k}else{F();J=true}s.draggable("option","revert",J)},$,"drag")},stop:function($,w){Z.stop();B();fa("eventDragStop",s,o,$,w);if(J){F();s.css("filter","");K(o,s)}else{var I=0;M||(I=Math.round((s.offset().top- -X().offset().top)/ia)*u("slotMinutes")+la-(o.start.getHours()*60+o.start.getMinutes()));C(this,o,k,I,M,$,w)}}})}function S(o,s,v){function F(I){var R=xa(N(o.start),I),V;if(o.end)V=xa(N(o.end),I);v.text(W(R,V,u("timeFormat")))}function r(){if(M){v.css("display","");s.draggable("option","grid",[$,w]);M=false}}var J,M=false,k,D,Z,ja=u("isRTL")?-1:1,ia=U(),la=z(),$=H(),w=T();s.draggable({zIndex:9,scroll:false,grid:[$,w],axis:la==1?"y":false,opacity:u("dragOpacity"),revertDuration:u("dragRevertDuration"), -start:function(I,R){fa("eventDragStart",s,o,I,R);i(o,s);J=s.position();D=Z=0;ia.start(function(V,ea,aa,va){s.draggable("option","revert",!V);B();if(V){k=va*ja;if(u("allDaySlot")&&!V.row){if(!M){M=true;v.hide();s.draggable("option","grid",null)}E(ba(N(o.start),k),ba(Ua(o),k))}else r()}},I,"drag")},drag:function(I,R){D=Math.round((R.position.top-J.top)/w)*u("slotMinutes");if(D!=Z){M||F(D);Z=D}},stop:function(I,R){var V=ia.stop();B();fa("eventDragStop",s,o,I,R);if(V&&(k||D||M))C(this,o,k,M?0:D,M,I,R); -else{r();s.css("filter","");s.css(J);F(0);K(o,s)}}})}function Q(o,s,v){var F,r,J=T();s.resizable({handles:{s:"div.ui-resizable-s"},grid:J,start:function(M,k){F=r=0;i(o,s);s.css("z-index",9);fa("eventResizeStart",this,o,M,k)},resize:function(M,k){F=Math.round((Math.max(J,s.height())-k.originalSize.height)/J);if(F!=r){v.text(W(o.start,!F&&!o.end?null:xa(ra(o),u("slotMinutes")*F),u("timeFormat")));r=F}},stop:function(M,k){fa("eventResizeStop",this,o,M,k);if(F)P(this,o,0,u("slotMinutes")*F,M,k);else{s.css("z-index", -8);K(o,s)}}})}var q=this;q.renderEvents=a;q.compileDaySegs=e;q.clearEvents=b;q.slotSegHtml=l;q.bindDaySeg=j;Qb.call(q);var u=q.opt,fa=q.trigger,oa=q.isEventDraggable,ga=q.isEventResizable,ra=q.eventEnd,sa=q.reportEvents,ha=q.reportEventClear,da=q.eventElementHandlers,na=q.setHeight,ua=q.getDaySegmentContainer,pa=q.getSlotSegmentContainer,U=q.getHoverListener,ca=q.getMaxMinute,ka=q.getMinMinute,qa=q.timePosition,G=q.colContentLeft,p=q.colContentRight,L=q.renderDaySegs,c=q.resizableDayEvent,z=q.getColCnt, -H=q.getColWidth,T=q.getSlotHeight,X=q.getBodyContent,ya=q.reportEventElement,K=q.showEvents,i=q.hideEvents,C=q.eventDrop,P=q.eventResize,E=q.renderDayOverlay,B=q.clearOverlays,n=q.calendar,Y=n.formatDate,W=n.formatDates}function vc(a){var b,e,d,f,g,l;for(b=a.length-1;b>0;b--){f=a[b];for(e=0;e"),B=z(),n=i.length,Y;E[0].innerHTML=e(i);E=E.children();B.append(E);d(i,E);l(i);j(i);t(i);Q(i,S(y()));E=[];for(B=0;B
";if(!n.allDay&&B.isStart)k+=""+Qa(T(n.start,n.end,fa("timeFormat")))+"";k+=""+Qa(n.title)+"
";if(B.isEnd&&ra(n))k+="
   
";k+="";B.left=r;B.outerWidth=J-r;B.startCol=v;B.endCol=F+1}return k}function d(i,C){var P,E=i.length,B,n,Y;for(P=0;P div");return P}function S(i){var C,P=i.length,E=[];for(C=0;C"));j[0].parentNode!=l[0]&&j.appendTo(l);d.push(j.css(g).show());return j}function b(){for(var g;g=d.shift();)f.push(g.hide().unbind())}var e=this;e.renderOverlay=a;e.clearOverlays=b;var d=[],f=[]}function Nb(a){var b=this,e,d;b.build=function(){e=[];d=[];a(e,d)};b.cell=function(f,g){var l=e.length,j=d.length, -t,y=-1,S=-1;for(t=0;t=e[t][0]&&g=d[t][0]&&f=0&&S>=0?{row:y,col:S}:null};b.rect=function(f,g,l,j,t){t=t.offset();return{top:e[f][0]-t.top,left:d[g][0]-t.left,width:d[j][1]-d[g][0],height:e[l][1]-e[f][0]}}}function Ob(a){function b(j){xc(j);j=a.cell(j.pageX,j.pageY);if(!j!=!l||j&&(j.row!=l.row||j.col!=l.col)){if(j){g||(g=j);f(j,g,j.row-g.row,j.col-g.col)}else f(j,g);l=j}}var e=this,d,f,g,l;e.start=function(j,t,y){f=j; -g=l=null;a.build();b(t);d=y||"mousemove";m(document).bind(d,b)};e.stop=function(){m(document).unbind(d,b);return l}}function xc(a){if(a.pageX===ma){a.pageX=a.originalEvent.pageX;a.pageY=a.originalEvent.pageY}}function Pb(a){function b(l){return d[l]=d[l]||a(l)}var e=this,d={},f={},g={};e.left=function(l){return f[l]=f[l]===ma?b(l).position().left:f[l]};e.right=function(l){return g[l]=g[l]===ma?e.left(l)+b(l).width():g[l]};e.clear=function(){d={};f={};g={}}}var Ya={defaultView:"month",aspectRatio:1.35, -header:{left:"title",center:"",right:"today prev,next"},weekends:true,allDayDefault:true,ignoreTimezone:true,lazyFetching:true,startParam:"start",endParam:"end",titleFormat:{month:"MMMM yyyy",week:"MMM d[ yyyy]{ '—'[ MMM] d yyyy}",day:"dddd, MMM d, yyyy"},columnFormat:{month:"ddd",week:"ddd M/d",day:"dddd M/d"},timeFormat:{"":"h(:mm)t"},isRTL:false,firstDay:0,monthNames:["January","February","March","April","Mai","June","July","August","September","October","November","December"],monthNamesShort:["Jan", -"Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],dayNames:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],dayNamesShort:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],buttonText:{prev:" ◄ ",next:" ► ",prevYear:" << ",nextYear:" >> ",today:"today",month:"month",week:"week",day:"day"},theme:false,buttonIcons:{prev:"circle-triangle-w",next:"circle-triangle-e"},unselectAuto:true,dropAccept:"*"},yc= -{header:{left:"next,prev today",center:"",right:"title"},buttonText:{prev:" ► ",next:" ◄ ",prevYear:" >> ",nextYear:" << "},buttonIcons:{prev:"circle-triangle-e",next:"circle-triangle-w"}},Aa=m.fullCalendar={version:"1.5.3"},Ja=Aa.views={};m.fn.fullCalendar=function(a){if(typeof a=="string"){var b=Array.prototype.slice.call(arguments,1),e;this.each(function(){var f=m.data(this,"fullCalendar");if(f&&m.isFunction(f[a])){f=f[a].apply(f, -b);if(e===ma)e=f;a=="destroy"&&m.removeData(this,"fullCalendar")}});if(e!==ma)return e;return this}var d=a.eventSources||[];delete a.eventSources;if(a.events){d.push(a.events);delete a.events}a=m.extend(true,{},Ya,a.isRTL||a.isRTL===ma&&Ya.isRTL?yc:{},a);this.each(function(f,g){f=m(g);g=new Yb(f,a,d);f.data("fullCalendar",g);g.render()});return this};Aa.sourceNormalizers=[];Aa.sourceFetchers=[];var ac={dataType:"json",cache:false},bc=1;Aa.addDays=ba;Aa.cloneDate=N;Aa.parseDate=kb;Aa.parseISO8601= -Bb;Aa.parseTime=mb;Aa.formatDate=Oa;Aa.formatDates=ib;var lc=["sun","mon","tue","wed","thu","fri","sat"],Ab=864E5,cc=36E5,wc=6E4,dc={s:function(a){return a.getSeconds()},ss:function(a){return Pa(a.getSeconds())},m:function(a){return a.getMinutes()},mm:function(a){return Pa(a.getMinutes())},h:function(a){return a.getHours()%12||12},hh:function(a){return Pa(a.getHours()%12||12)},H:function(a){return a.getHours()},HH:function(a){return Pa(a.getHours())},d:function(a){return a.getDate()},dd:function(a){return Pa(a.getDate())}, -ddd:function(a,b){return b.dayNamesShort[a.getDay()]},dddd:function(a,b){return b.dayNames[a.getDay()]},M:function(a){return a.getMonth()+1},MM:function(a){return Pa(a.getMonth()+1)},MMM:function(a,b){return b.monthNamesShort[a.getMonth()]},MMMM:function(a,b){return b.monthNames[a.getMonth()]},yy:function(a){return(a.getFullYear()+"").substring(2)},yyyy:function(a){return a.getFullYear()},t:function(a){return a.getHours()<12?"a":"p"},tt:function(a){return a.getHours()<12?"am":"pm"},T:function(a){return a.getHours()< -12?"A":"P"},TT:function(a){return a.getHours()<12?"AM":"PM"},u:function(a){return Oa(a,"yyyy-MM-dd'T'HH:mm:ss'Z'")},S:function(a){a=a.getDate();if(a>10&&a<20)return"th";return["st","nd","rd"][a%10-1]||"th"}};Aa.applyAll=$a;Ja.month=mc;Ja.basicWeek=nc;Ja.basicDay=oc;wb({weekMode:"fixed"});Ja.agendaWeek=qc;Ja.agendaDay=rc;wb({allDaySlot:true,allDayText:"all-day",firstHour:6,slotMinutes:30,defaultEventMinutes:120,axisFormat:"h(:mm)tt",timeFormat:{agenda:"h:mm{ - h:mm}"},dragOpacity:{agenda:0.5},minTime:0, -maxTime:24})})(jQuery); diff --git a/www/plugins/fullcalendar-1.5.3/fullcalendar.print.css b/www/plugins/fullcalendar-1.5.3/fullcalendar.print.css deleted file mode 100644 index e11c18163..000000000 --- a/www/plugins/fullcalendar-1.5.3/fullcalendar.print.css +++ /dev/null @@ -1,61 +0,0 @@ -/* - * FullCalendar v1.5.3 Print Stylesheet - * - * Include this stylesheet on your page to get a more printer-friendly calendar. - * When including this stylesheet, use the media='print' attribute of the tag. - * Make sure to include this stylesheet IN ADDITION to the regular fullcalendar.css. - * - * Copyright (c) 2011 Adam Shaw - * Dual licensed under the MIT and GPL licenses, located in - * MIT-LICENSE.txt and GPL-LICENSE.txt respectively. - * - * Date: Mon Feb 6 22:40:40 2012 -0800 - * - */ - - - /* Events ------------------------------------------------------*/ - -.fc-event-skin { - background: none !important; - color: #000 !important; - } - -/* horizontal events */ - -.fc-event-hori { - border-width: 0 0 1px 0 !important; - border-bottom-style: dotted !important; - border-bottom-color: #000 !important; - padding: 1px 0 0 0 !important; - } - -.fc-event-hori .fc-event-inner { - border-width: 0 !important; - padding: 0 1px !important; - } - -/* vertical events */ - -.fc-event-vert { - border-width: 0 0 0 1px !important; - border-left-style: dotted !important; - border-left-color: #000 !important; - padding: 0 1px 0 0 !important; - } - -.fc-event-vert .fc-event-inner { - border-width: 0 !important; - padding: 1px 0 !important; - } - -.fc-event-bg { - display: none !important; - } - -.fc-event .ui-resizable-handle { - display: none !important; - } - - diff --git a/www/plugins/fullcalendar-1.5.3/gcal.js b/www/plugins/fullcalendar-1.5.3/gcal.js deleted file mode 100644 index e9bbe26d8..000000000 --- a/www/plugins/fullcalendar-1.5.3/gcal.js +++ /dev/null @@ -1,112 +0,0 @@ -/* - * FullCalendar v1.5.3 Google Calendar Plugin - * - * Copyright (c) 2011 Adam Shaw - * Dual licensed under the MIT and GPL licenses, located in - * MIT-LICENSE.txt and GPL-LICENSE.txt respectively. - * - * Date: Mon Feb 6 22:40:40 2012 -0800 - * - */ - -(function($) { - - -var fc = $.fullCalendar; -var formatDate = fc.formatDate; -var parseISO8601 = fc.parseISO8601; -var addDays = fc.addDays; -var applyAll = fc.applyAll; - - -fc.sourceNormalizers.push(function(sourceOptions) { - if (sourceOptions.dataType == 'gcal' || - sourceOptions.dataType === undefined && - (sourceOptions.url || '').match(/^(http|https):\/\/www.google.com\/calendar\/feeds\//)) { - sourceOptions.dataType = 'gcal'; - if (sourceOptions.editable === undefined) { - sourceOptions.editable = false; - } - } -}); - - -fc.sourceFetchers.push(function(sourceOptions, start, end) { - if (sourceOptions.dataType == 'gcal') { - return transformOptions(sourceOptions, start, end); - } -}); - - -function transformOptions(sourceOptions, start, end) { - - var success = sourceOptions.success; - var data = $.extend({}, sourceOptions.data || {}, { - 'start-min': formatDate(start, 'u'), - 'start-max': formatDate(end, 'u'), - 'singleevents': true, - 'max-results': 9999 - }); - - var ctz = sourceOptions.currentTimezone; - if (ctz) { - data.ctz = ctz = ctz.replace(' ', '_'); - } - - return $.extend({}, sourceOptions, { - url: sourceOptions.url.replace(/\/basic$/, '/full') + '?alt=json-in-script&callback=?', - dataType: 'jsonp', - data: data, - startParam: false, - endParam: false, - success: function(data) { - var events = []; - if (data.feed.entry) { - $.each(data.feed.entry, function(i, entry) { - var startStr = entry['gd$when'][0]['startTime']; - var start = parseISO8601(startStr, true); - var end = parseISO8601(entry['gd$when'][0]['endTime'], true); - var allDay = startStr.indexOf('T') == -1; - var url; - $.each(entry.link, function(i, link) { - if (link.type == 'text/html') { - url = link.href; - if (ctz) { - url += (url.indexOf('?') == -1 ? '?' : '&') + 'ctz=' + ctz; - } - } - }); - if (allDay) { - addDays(end, -1); // make inclusive - } - events.push({ - id: entry['gCal$uid']['value'], - title: entry['title']['$t'], - url: url, - start: start, - end: end, - allDay: allDay, - location: entry['gd$where'][0]['valueString'], - description: entry['content']['$t'] - }); - }); - } - var args = [events].concat(Array.prototype.slice.call(arguments, 1)); - var res = applyAll(success, this, args); - if ($.isArray(res)) { - return res; - } - return events; - } - }); - -} - - -// legacy -fc.gcalFeed = function(url, sourceOptions) { - return $.extend({}, sourceOptions, { url: url, dataType: 'gcal' }); -}; - - -})(jQuery); diff --git a/www/plugins/fullcalendar-1.6.4/fullcalendar.css b/www/plugins/fullcalendar-1.6.4/fullcalendar.css deleted file mode 100644 index b9834884e..000000000 --- a/www/plugins/fullcalendar-1.6.4/fullcalendar.css +++ /dev/null @@ -1,589 +0,0 @@ -/*! - * FullCalendar v1.6.4 Stylesheet - * Docs & License: http://arshaw.com/fullcalendar/ - * (c) 2013 Adam Shaw - */ - - -.fc { - direction: ltr; - text-align: left; - } - -.fc table { - border-collapse: collapse; - border-spacing: 0; - } - -html .fc, -.fc table { - font-size: 1em; - } - -.fc td, -.fc th { - padding: 0; - vertical-align: top; - } - - - -/* Header -------------------------------------------------------------------------*/ - -.fc-header td { - white-space: nowrap; - } - -.fc-header-left { - width: 25%; - text-align: left; - } - -.fc-header-center { - text-align: center; - } - -.fc-header-right { - width: 25%; - text-align: right; - } - -.fc-header-title { - display: inline-block; - vertical-align: top; - } - -.fc-header-title h2 { - margin-top: 0; - white-space: nowrap; - } - -.fc .fc-header-space { - padding-left: 10px; - } - -.fc-header .fc-button { - margin-bottom: 1em; - vertical-align: top; - } - -/* buttons edges butting together */ - -.fc-header .fc-button { - margin-right: -1px; - } - -.fc-header .fc-corner-right, /* non-theme */ -.fc-header .ui-corner-right { /* theme */ - margin-right: 0; /* back to normal */ - } - -/* button layering (for border precedence) */ - -.fc-header .fc-state-hover, -.fc-header .ui-state-hover { - z-index: 2; - } - -.fc-header .fc-state-down { - z-index: 3; - } - -.fc-header .fc-state-active, -.fc-header .ui-state-active { - z-index: 1; - } - - - -/* Content -------------------------------------------------------------------------*/ - -.fc-content { - clear: both; - zoom: 1; /* for IE7, gives accurate coordinates for [un]freezeContentHeight */ - } - -.fc-view { - width: 100%; - overflow: hidden; - } - - - -/* Cell Styles -------------------------------------------------------------------------*/ - -.fc-widget-header, /* , usually */ -.fc-widget-content { /* , usually */ - border: 1px solid #ddd; - } - -.fc-state-highlight { /* today cell */ /* TODO: add .fc-today to */ - background: #fcf8e3; - } - -.fc-cell-overlay { /* semi-transparent rectangle while dragging */ - background: #bce8f1; - opacity: .3; - filter: alpha(opacity=30); /* for IE */ - } - - - -/* Buttons -------------------------------------------------------------------------*/ - -.fc-button { - position: relative; - display: inline-block; - padding: 0 .6em; - overflow: hidden; - height: 1.9em; - line-height: 1.9em; - white-space: nowrap; - cursor: pointer; - } - -.fc-state-default { /* non-theme */ - border: 1px solid; - } - -.fc-state-default.fc-corner-left { /* non-theme */ - border-top-left-radius: 4px; - border-bottom-left-radius: 4px; - } - -.fc-state-default.fc-corner-right { /* non-theme */ - border-top-right-radius: 4px; - border-bottom-right-radius: 4px; - } - -/* - Our default prev/next buttons use HTML entities like ‹ › « » - and we'll try to make them look good cross-browser. -*/ - -.fc-text-arrow { - margin: 0 .1em; - font-size: 2em; - font-family: "Courier New", Courier, monospace; - vertical-align: baseline; /* for IE7 */ - } - -.fc-button-prev .fc-text-arrow, -.fc-button-next .fc-text-arrow { /* for ‹ › */ - font-weight: bold; - } - -/* icon (for jquery ui) */ - -.fc-button .fc-icon-wrap { - position: relative; - float: left; - top: 50%; - } - -.fc-button .ui-icon { - position: relative; - float: left; - margin-top: -50%; - *margin-top: 0; - *top: -50%; - } - -/* - button states - borrowed from twitter bootstrap (http://twitter.github.com/bootstrap/) -*/ - -.fc-state-default { - background-color: #f5f5f5; - background-image: -moz-linear-gradient(top, #ffffff, #e6e6e6); - background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#e6e6e6)); - background-image: -webkit-linear-gradient(top, #ffffff, #e6e6e6); - background-image: -o-linear-gradient(top, #ffffff, #e6e6e6); - background-image: linear-gradient(to bottom, #ffffff, #e6e6e6); - background-repeat: repeat-x; - border-color: #e6e6e6 #e6e6e6 #bfbfbf; - border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); - color: #333; - text-shadow: 0 1px 1px rgba(255, 255, 255, 0.75); - box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); - } - -.fc-state-hover, -.fc-state-down, -.fc-state-active, -.fc-state-disabled { - color: #333333; - background-color: #e6e6e6; - } - -.fc-state-hover { - color: #333333; - text-decoration: none; - background-position: 0 -15px; - -webkit-transition: background-position 0.1s linear; - -moz-transition: background-position 0.1s linear; - -o-transition: background-position 0.1s linear; - transition: background-position 0.1s linear; - } - -.fc-state-down, -.fc-state-active { - background-color: #cccccc; - background-image: none; - outline: 0; - box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); - } - -.fc-state-disabled { - cursor: default; - background-image: none; - opacity: 0.65; - filter: alpha(opacity=65); - box-shadow: none; - } - - - -/* Global Event Styles -------------------------------------------------------------------------*/ - -.fc-event-container > * { - z-index: 8; - } - -.fc-event-container > .ui-draggable-dragging, -.fc-event-container > .ui-resizable-resizing { - z-index: 9; - } - -.fc-event { - border: 1px solid #3a87ad; /* default BORDER color */ - background-color: #3a87ad; /* default BACKGROUND color */ - color: #fff; /* default TEXT color */ - font-size: .85em; - cursor: default; - } - -a.fc-event { - text-decoration: none; - } - -a.fc-event, -.fc-event-draggable { - cursor: pointer; - } - -.fc-rtl .fc-event { - text-align: right; - } - -.fc-event-inner { - width: 100%; - height: 100%; - overflow: hidden; - } - -.fc-event-time, -.fc-event-title { - padding: 0 1px; - } - -.fc .ui-resizable-handle { - display: block; - position: absolute; - z-index: 99999; - overflow: hidden; /* hacky spaces (IE6/7) */ - font-size: 300%; /* */ - line-height: 50%; /* */ - } - - - -/* Horizontal Events -------------------------------------------------------------------------*/ - -.fc-event-hori { - border-width: 1px 0; - margin-bottom: 1px; - } - -.fc-ltr .fc-event-hori.fc-event-start, -.fc-rtl .fc-event-hori.fc-event-end { - border-left-width: 1px; - border-top-left-radius: 3px; - border-bottom-left-radius: 3px; - } - -.fc-ltr .fc-event-hori.fc-event-end, -.fc-rtl .fc-event-hori.fc-event-start { - border-right-width: 1px; - border-top-right-radius: 3px; - border-bottom-right-radius: 3px; - } - -/* resizable */ - -.fc-event-hori .ui-resizable-e { - top: 0 !important; /* importants override pre jquery ui 1.7 styles */ - right: -3px !important; - width: 7px !important; - height: 100% !important; - cursor: e-resize; - } - -.fc-event-hori .ui-resizable-w { - top: 0 !important; - left: -3px !important; - width: 7px !important; - height: 100% !important; - cursor: w-resize; - } - -.fc-event-hori .ui-resizable-handle { - _padding-bottom: 14px; /* IE6 had 0 height */ - } - - - -/* Reusable Separate-border Table -------------------------------------------------------------*/ - -table.fc-border-separate { - border-collapse: separate; - } - -.fc-border-separate th, -.fc-border-separate td { - border-width: 1px 0 0 1px; - } - -.fc-border-separate th.fc-last, -.fc-border-separate td.fc-last { - border-right-width: 1px; - } - -.fc-border-separate tr.fc-last th, -.fc-border-separate tr.fc-last td { - border-bottom-width: 1px; - } - -.fc-border-separate tbody tr.fc-first td, -.fc-border-separate tbody tr.fc-first th { - border-top-width: 0; - } - - - -/* Month View, Basic Week View, Basic Day View -------------------------------------------------------------------------*/ - -.fc-grid th { - text-align: center; - } - -.fc .fc-week-number { - width: 22px; - text-align: center; - } - -.fc .fc-week-number div { - padding: 0 2px; - } - -.fc-grid .fc-day-number { - float: right; - padding: 0 2px; - } - -.fc-grid .fc-other-month .fc-day-number { - opacity: 0.3; - filter: alpha(opacity=30); /* for IE */ - /* opacity with small font can sometimes look too faded - might want to set the 'color' property instead - making day-numbers bold also fixes the problem */ - } - -.fc-grid .fc-day-content { - clear: both; - padding: 2px 2px 1px; /* distance between events and day edges */ - } - -/* event styles */ - -.fc-grid .fc-event-time { - font-weight: bold; - } - -/* right-to-left */ - -.fc-rtl .fc-grid .fc-day-number { - float: left; - } - -.fc-rtl .fc-grid .fc-event-time { - float: right; - } - - - -/* Agenda Week View, Agenda Day View -------------------------------------------------------------------------*/ - -.fc-agenda table { - border-collapse: separate; - } - -.fc-agenda-days th { - text-align: center; - } - -.fc-agenda .fc-agenda-axis { - width: 50px; - padding: 0 4px; - vertical-align: middle; - text-align: right; - white-space: nowrap; - font-weight: normal; - } - -.fc-agenda .fc-week-number { - font-weight: bold; - } - -.fc-agenda .fc-day-content { - padding: 2px 2px 1px; - } - -/* make axis border take precedence */ - -.fc-agenda-days .fc-agenda-axis { - border-right-width: 1px; - } - -.fc-agenda-days .fc-col0 { - border-left-width: 0; - } - -/* all-day area */ - -.fc-agenda-allday th { - border-width: 0 1px; - } - -.fc-agenda-allday .fc-day-content { - min-height: 34px; /* TODO: doesnt work well in quirksmode */ - _height: 34px; - } - -/* divider (between all-day and slots) */ - -.fc-agenda-divider-inner { - height: 2px; - overflow: hidden; - } - -.fc-widget-header .fc-agenda-divider-inner { - background: #eee; - } - -/* slot rows */ - -.fc-agenda-slots th { - border-width: 1px 1px 0; - } - -.fc-agenda-slots td { - border-width: 1px 0 0; - background: none; - } - -.fc-agenda-slots td div { - height: 20px; - } - -.fc-agenda-slots tr.fc-slot0 th, -.fc-agenda-slots tr.fc-slot0 td { - border-top-width: 0; - } - -.fc-agenda-slots tr.fc-minor th, -.fc-agenda-slots tr.fc-minor td { - border-top-style: dotted; - } - -.fc-agenda-slots tr.fc-minor th.ui-widget-header { - *border-top-style: solid; /* doesn't work with background in IE6/7 */ - } - - - -/* Vertical Events -------------------------------------------------------------------------*/ - -.fc-event-vert { - border-width: 0 1px; - } - -.fc-event-vert.fc-event-start { - border-top-width: 1px; - border-top-left-radius: 3px; - border-top-right-radius: 3px; - } - -.fc-event-vert.fc-event-end { - border-bottom-width: 1px; - border-bottom-left-radius: 3px; - border-bottom-right-radius: 3px; - } - -.fc-event-vert .fc-event-time { - white-space: nowrap; - font-size: 10px; - } - -.fc-event-vert .fc-event-inner { - position: relative; - z-index: 2; - } - -.fc-event-vert .fc-event-bg { /* makes the event lighter w/ a semi-transparent overlay */ - position: absolute; - z-index: 1; - top: 0; - left: 0; - width: 100%; - height: 100%; - background: #fff; - opacity: .25; - filter: alpha(opacity=25); - } - -.fc .ui-draggable-dragging .fc-event-bg, /* TODO: something nicer like .fc-opacity */ -.fc-select-helper .fc-event-bg { - display: none\9; /* for IE6/7/8. nested opacity filters while dragging don't work */ - } - -/* resizable */ - -.fc-event-vert .ui-resizable-s { - bottom: 0 !important; /* importants override pre jquery ui 1.7 styles */ - width: 100% !important; - height: 8px !important; - overflow: hidden !important; - line-height: 8px !important; - font-size: 11px !important; - font-family: monospace; - text-align: center; - cursor: s-resize; - } - -.fc-agenda .ui-resizable-resizing { /* TODO: better selector */ - _overflow: hidden; - } - - diff --git a/www/plugins/fullcalendar-1.6.4/fullcalendar.js b/www/plugins/fullcalendar-1.6.4/fullcalendar.js deleted file mode 100644 index 3a37bdba8..000000000 --- a/www/plugins/fullcalendar-1.6.4/fullcalendar.js +++ /dev/null @@ -1,6110 +0,0 @@ -/*! - * FullCalendar v1.6.4 - * Docs & License: http://arshaw.com/fullcalendar/ - * (c) 2013 Adam Shaw - */ - -/* - * Use fullcalendar.css for basic styling. - * For event drag & drop, requires jQuery UI draggable. - * For event resizing, requires jQuery UI resizable. - */ - -(function($, undefined) { - - -;; - -var defaults = { - - // display - defaultView: 'month', - aspectRatio: 1.35, - header: { - left: 'title', - center: '', - right: 'today prev,next' - }, - weekends: true, - weekNumbers: false, - weekNumberCalculation: 'iso', - weekNumberTitle: 'W', - - // editing - //editable: false, - //disableDragging: false, - //disableResizing: false, - - allDayDefault: true, - ignoreTimezone: true, - - // event ajax - lazyFetching: true, - startParam: 'start', - endParam: 'end', - - // time formats - titleFormat: { - month: 'MMMM yyyy', - week: "MMM d[ yyyy]{ '—'[ MMM] d yyyy}", - day: 'dddd, MMM d, yyyy' - }, - columnFormat: { - month: 'ddd', - week: 'ddd M/d', - day: 'dddd M/d' - }, - timeFormat: { // for event elements - '': 'h(:mm)t' // default - }, - - // locale - isRTL: false, - firstDay: 0, - monthNames: ['January','February','March','April','May','June','July','August','September','October','November','December'], - monthNamesShort: ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'], - dayNames: ['Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday'], - dayNamesShort: ['Sun','Mon','Tue','Wed','Thu','Fri','Sat'], - buttonText: { - prev: "", - next: "", - prevYear: "«", - nextYear: "»", - today: 'today', - month: 'month', - week: 'week', - day: 'day' - }, - - // jquery-ui theming - theme: false, - buttonIcons: { - prev: 'circle-triangle-w', - next: 'circle-triangle-e' - }, - - //selectable: false, - unselectAuto: true, - - dropAccept: '*', - - handleWindowResize: true - -}; - -// right-to-left defaults -var rtlDefaults = { - header: { - left: 'next,prev today', - center: '', - right: 'title' - }, - buttonText: { - prev: "", - next: "", - prevYear: "»", - nextYear: "«" - }, - buttonIcons: { - prev: 'circle-triangle-e', - next: 'circle-triangle-w' - } -}; - - - -;; - -var fc = $.fullCalendar = { version: "1.6.4" }; -var fcViews = fc.views = {}; - - -$.fn.fullCalendar = function(options) { - - - // method calling - if (typeof options == 'string') { - var args = Array.prototype.slice.call(arguments, 1); - var res; - this.each(function() { - var calendar = $.data(this, 'fullCalendar'); - if (calendar && $.isFunction(calendar[options])) { - var r = calendar[options].apply(calendar, args); - if (res === undefined) { - res = r; - } - if (options == 'destroy') { - $.removeData(this, 'fullCalendar'); - } - } - }); - if (res !== undefined) { - return res; - } - return this; - } - - options = options || {}; - - // would like to have this logic in EventManager, but needs to happen before options are recursively extended - var eventSources = options.eventSources || []; - delete options.eventSources; - if (options.events) { - eventSources.push(options.events); - delete options.events; - } - - - options = $.extend(true, {}, - defaults, - (options.isRTL || options.isRTL===undefined && defaults.isRTL) ? rtlDefaults : {}, - options - ); - - - this.each(function(i, _element) { - var element = $(_element); - var calendar = new Calendar(element, options, eventSources); - element.data('fullCalendar', calendar); // TODO: look into memory leak implications - calendar.render(); - }); - - - return this; - -}; - - -// function for adding/overriding defaults -function setDefaults(d) { - $.extend(true, defaults, d); -} - - - -;; - - -function Calendar(element, options, eventSources) { - var t = this; - - - // exports - t.options = options; - t.render = render; - t.destroy = destroy; - t.refetchEvents = refetchEvents; - t.reportEvents = reportEvents; - t.reportEventChange = reportEventChange; - t.rerenderEvents = rerenderEvents; - t.changeView = changeView; - t.select = select; - t.unselect = unselect; - t.prev = prev; - t.next = next; - t.prevYear = prevYear; - t.nextYear = nextYear; - t.today = today; - t.gotoDate = gotoDate; - t.incrementDate = incrementDate; - t.formatDate = function(format, date) { return formatDate(format, date, options) }; - t.formatDates = function(format, date1, date2) { return formatDates(format, date1, date2, options) }; - t.getDate = getDate; - t.getView = getView; - t.option = option; - t.trigger = trigger; - - - // imports - EventManager.call(t, options, eventSources); - var isFetchNeeded = t.isFetchNeeded; - var fetchEvents = t.fetchEvents; - - - // locals - var _element = element[0]; - var header; - var headerElement; - var content; - var tm; // for making theme classes - var currentView; - var elementOuterWidth; - var suggestedViewHeight; - var resizeUID = 0; - var ignoreWindowResize = 0; - var date = new Date(); - var events = []; - var _dragElement; - - - - /* Main Rendering - -----------------------------------------------------------------------------*/ - - - setYMD(date, options.year, options.month, options.date); - - - function render(inc) { - if (!content) { - initialRender(); - } - else if (elementVisible()) { - // mainly for the public API - calcSize(); - _renderView(inc); - } - } - - - function initialRender() { - tm = options.theme ? 'ui' : 'fc'; - element.addClass('fc'); - if (options.isRTL) { - element.addClass('fc-rtl'); - } - else { - element.addClass('fc-ltr'); - } - if (options.theme) { - element.addClass('ui-widget'); - } - - content = $("
") - .prependTo(element); - - header = new Header(t, options); - headerElement = header.render(); - if (headerElement) { - element.prepend(headerElement); - } - - changeView(options.defaultView); - - if (options.handleWindowResize) { - $(window).resize(windowResize); - } - - // needed for IE in a 0x0 iframe, b/c when it is resized, never triggers a windowResize - if (!bodyVisible()) { - lateRender(); - } - } - - - // called when we know the calendar couldn't be rendered when it was initialized, - // but we think it's ready now - function lateRender() { - setTimeout(function() { // IE7 needs this so dimensions are calculated correctly - if (!currentView.start && bodyVisible()) { // !currentView.start makes sure this never happens more than once - renderView(); - } - },0); - } - - - function destroy() { - - if (currentView) { - trigger('viewDestroy', currentView, currentView, currentView.element); - currentView.triggerEventDestroy(); - } - - $(window).unbind('resize', windowResize); - - header.destroy(); - content.remove(); - element.removeClass('fc fc-rtl ui-widget'); - } - - - function elementVisible() { - return element.is(':visible'); - } - - - function bodyVisible() { - return $('body').is(':visible'); - } - - - - /* View Rendering - -----------------------------------------------------------------------------*/ - - - function changeView(newViewName) { - if (!currentView || newViewName != currentView.name) { - _changeView(newViewName); - } - } - - - function _changeView(newViewName) { - ignoreWindowResize++; - - if (currentView) { - trigger('viewDestroy', currentView, currentView, currentView.element); - unselect(); - currentView.triggerEventDestroy(); // trigger 'eventDestroy' for each event - freezeContentHeight(); - currentView.element.remove(); - header.deactivateButton(currentView.name); - } - - header.activateButton(newViewName); - - currentView = new fcViews[newViewName]( - $("
") - .appendTo(content), - t // the calendar object - ); - - renderView(); - unfreezeContentHeight(); - - ignoreWindowResize--; - } - - - function renderView(inc) { - if ( - !currentView.start || // never rendered before - inc || date < currentView.start || date >= currentView.end // or new date range - ) { - if (elementVisible()) { - _renderView(inc); - } - } - } - - - function _renderView(inc) { // assumes elementVisible - ignoreWindowResize++; - - if (currentView.start) { // already been rendered? - trigger('viewDestroy', currentView, currentView, currentView.element); - unselect(); - clearEvents(); - } - - freezeContentHeight(); - currentView.render(date, inc || 0); // the view's render method ONLY renders the skeleton, nothing else - setSize(); - unfreezeContentHeight(); - (currentView.afterRender || noop)(); - - updateTitle(); - updateTodayButton(); - - trigger('viewRender', currentView, currentView, currentView.element); - currentView.trigger('viewDisplay', _element); // deprecated - - ignoreWindowResize--; - - getAndRenderEvents(); - } - - - - /* Resizing - -----------------------------------------------------------------------------*/ - - - function updateSize() { - if (elementVisible()) { - unselect(); - clearEvents(); - calcSize(); - setSize(); - renderEvents(); - } - } - - - function calcSize() { // assumes elementVisible - if (options.contentHeight) { - suggestedViewHeight = options.contentHeight; - } - else if (options.height) { - suggestedViewHeight = options.height - (headerElement ? headerElement.height() : 0) - vsides(content); - } - else { - suggestedViewHeight = Math.round(content.width() / Math.max(options.aspectRatio, .5)); - } - } - - - function setSize() { // assumes elementVisible - - if (suggestedViewHeight === undefined) { - calcSize(); // for first time - // NOTE: we don't want to recalculate on every renderView because - // it could result in oscillating heights due to scrollbars. - } - - ignoreWindowResize++; - currentView.setHeight(suggestedViewHeight); - currentView.setWidth(content.width()); - ignoreWindowResize--; - - elementOuterWidth = element.outerWidth(); - } - - - function windowResize() { - if (!ignoreWindowResize) { - if (currentView.start) { // view has already been rendered - var uid = ++resizeUID; - setTimeout(function() { // add a delay - if (uid == resizeUID && !ignoreWindowResize && elementVisible()) { - if (elementOuterWidth != (elementOuterWidth = element.outerWidth())) { - ignoreWindowResize++; // in case the windowResize callback changes the height - updateSize(); - currentView.trigger('windowResize', _element); - ignoreWindowResize--; - } - } - }, 200); - }else{ - // calendar must have been initialized in a 0x0 iframe that has just been resized - lateRender(); - } - } - } - - - - /* Event Fetching/Rendering - -----------------------------------------------------------------------------*/ - // TODO: going forward, most of this stuff should be directly handled by the view - - - function refetchEvents() { // can be called as an API method - clearEvents(); - fetchAndRenderEvents(); - } - - - function rerenderEvents(modifiedEventID) { // can be called as an API method - clearEvents(); - renderEvents(modifiedEventID); - } - - - function renderEvents(modifiedEventID) { // TODO: remove modifiedEventID hack - if (elementVisible()) { - currentView.setEventData(events); // for View.js, TODO: unify with renderEvents - currentView.renderEvents(events, modifiedEventID); // actually render the DOM elements - currentView.trigger('eventAfterAllRender'); - } - } - - - function clearEvents() { - currentView.triggerEventDestroy(); // trigger 'eventDestroy' for each event - currentView.clearEvents(); // actually remove the DOM elements - currentView.clearEventData(); // for View.js, TODO: unify with clearEvents - } - - - function getAndRenderEvents() { - if (!options.lazyFetching || isFetchNeeded(currentView.visStart, currentView.visEnd)) { - fetchAndRenderEvents(); - } - else { - renderEvents(); - } - } - - - function fetchAndRenderEvents() { - fetchEvents(currentView.visStart, currentView.visEnd); - // ... will call reportEvents - // ... which will call renderEvents - } - - - // called when event data arrives - function reportEvents(_events) { - events = _events; - renderEvents(); - } - - - // called when a single event's data has been changed - function reportEventChange(eventID) { - rerenderEvents(eventID); - } - - - - /* Header Updating - -----------------------------------------------------------------------------*/ - - - function updateTitle() { - header.updateTitle(currentView.title); - } - - - function updateTodayButton() { - var today = new Date(); - if (today >= currentView.start && today < currentView.end) { - header.disableButton('today'); - } - else { - header.enableButton('today'); - } - } - - - - /* Selection - -----------------------------------------------------------------------------*/ - - - function select(start, end, allDay) { - currentView.select(start, end, allDay===undefined ? true : allDay); - } - - - function unselect() { // safe to be called before renderView - if (currentView) { - currentView.unselect(); - } - } - - - - /* Date - -----------------------------------------------------------------------------*/ - - - function prev() { - renderView(-1); - } - - - function next() { - renderView(1); - } - - - function prevYear() { - addYears(date, -1); - renderView(); - } - - - function nextYear() { - addYears(date, 1); - renderView(); - } - - - function today() { - date = new Date(); - renderView(); - } - - - function gotoDate(year, month, dateOfMonth) { - if (year instanceof Date) { - date = cloneDate(year); // provided 1 argument, a Date - }else{ - setYMD(date, year, month, dateOfMonth); - } - renderView(); - } - - - function incrementDate(years, months, days) { - if (years !== undefined) { - addYears(date, years); - } - if (months !== undefined) { - addMonths(date, months); - } - if (days !== undefined) { - addDays(date, days); - } - renderView(); - } - - - function getDate() { - return cloneDate(date); - } - - - - /* Height "Freezing" - -----------------------------------------------------------------------------*/ - - - function freezeContentHeight() { - content.css({ - width: '100%', - height: content.height(), - overflow: 'hidden' - }); - } - - - function unfreezeContentHeight() { - content.css({ - width: '', - height: '', - overflow: '' - }); - } - - - - /* Misc - -----------------------------------------------------------------------------*/ - - - function getView() { - return currentView; - } - - - function option(name, value) { - if (value === undefined) { - return options[name]; - } - if (name == 'height' || name == 'contentHeight' || name == 'aspectRatio') { - options[name] = value; - updateSize(); - } - } - - - function trigger(name, thisObj) { - if (options[name]) { - return options[name].apply( - thisObj || _element, - Array.prototype.slice.call(arguments, 2) - ); - } - } - - - - /* External Dragging - ------------------------------------------------------------------------*/ - - if (options.droppable) { - $(document) - .bind('dragstart', function(ev, ui) { - var _e = ev.target; - var e = $(_e); - if (!e.parents('.fc').length) { // not already inside a calendar - var accept = options.dropAccept; - if ($.isFunction(accept) ? accept.call(_e, e) : e.is(accept)) { - _dragElement = _e; - currentView.dragStart(_dragElement, ev, ui); - } - } - }) - .bind('dragstop', function(ev, ui) { - if (_dragElement) { - currentView.dragStop(_dragElement, ev, ui); - _dragElement = null; - } - }); - } - - -} - -;; - -function Header(calendar, options) { - var t = this; - - - // exports - t.render = render; - t.destroy = destroy; - t.updateTitle = updateTitle; - t.activateButton = activateButton; - t.deactivateButton = deactivateButton; - t.disableButton = disableButton; - t.enableButton = enableButton; - - - // locals - var element = $([]); - var tm; - - - - function render() { - tm = options.theme ? 'ui' : 'fc'; - var sections = options.header; - if (sections) { - element = $("") - .append( - $("") - .append(renderSection('left')) - .append(renderSection('center')) - .append(renderSection('right')) - ); - return element; - } - } - - - function destroy() { - element.remove(); - } - - - function renderSection(position) { - var e = $(""; - - if (showWeekNumbers) { - html += - ""; - } - - for (col=0; col" + - htmlEscape(formatDate(date, colFormat)) + - ""; - } - - html += ""; - - return html; - } - - - function buildBodyHTML() { - var contentClass = tm + "-widget-content"; - var html = ''; - var row; - var col; - var date; - - html += ""; - - for (row=0; row" + - "
" + - htmlEscape(formatDate(date, weekNumberFormat)) + - "
" + - ""; - } - - for (col=0; col" + - "
"; - - if (showNumbers) { - html += "
" + date.getDate() + "
"; - } - - html += - "
" + - "
 
" + - "
" + - "
" + - ""; - - return html; - } - - - - /* Dimensions - -----------------------------------------------------------*/ - - - function setHeight(height) { - viewHeight = height; - - var bodyHeight = viewHeight - head.height(); - var rowHeight; - var rowHeightLast; - var cell; - - if (opt('weekMode') == 'variable') { - rowHeight = rowHeightLast = Math.floor(bodyHeight / (rowCnt==1 ? 2 : 6)); - }else{ - rowHeight = Math.floor(bodyHeight / rowCnt); - rowHeightLast = bodyHeight - rowHeight * (rowCnt-1); - } - - bodyFirstCells.each(function(i, _cell) { - if (i < rowCnt) { - cell = $(_cell); - cell.find('> div').css( - 'min-height', - (i==rowCnt-1 ? rowHeightLast : rowHeight) - vsides(cell) - ); - } - }); - - } - - - function setWidth(width) { - viewWidth = width; - colPositions.clear(); - colContentPositions.clear(); - - weekNumberWidth = 0; - if (showWeekNumbers) { - weekNumberWidth = head.find('th.fc-week-number').outerWidth(); - } - - colWidth = Math.floor((viewWidth - weekNumberWidth) / colCnt); - setOuterWidth(headCells.slice(0, -1), colWidth); - } - - - - /* Day clicking and binding - -----------------------------------------------------------*/ - - - function dayBind(days) { - days.click(dayClick) - .mousedown(daySelectionMousedown); - } - - - function dayClick(ev) { - if (!opt('selectable')) { // if selectable, SelectionManager will worry about dayClick - var date = parseISO8601($(this).data('date')); - trigger('dayClick', this, date, true, ev); - } - } - - - - /* Semi-transparent Overlay Helpers - ------------------------------------------------------*/ - // TODO: should be consolidated with AgendaView's methods - - - function renderDayOverlay(overlayStart, overlayEnd, refreshCoordinateGrid) { // overlayEnd is exclusive - - if (refreshCoordinateGrid) { - coordinateGrid.build(); - } - - var segments = rangeToSegments(overlayStart, overlayEnd); - - for (var i=0; i") - .appendTo(element); - - if (opt('allDaySlot')) { - - daySegmentContainer = - $("
") - .appendTo(slotLayer); - - s = - "
"); - var buttonStr = options.header[position]; - if (buttonStr) { - $.each(buttonStr.split(' '), function(i) { - if (i > 0) { - e.append(""); - } - var prevButton; - $.each(this.split(','), function(j, buttonName) { - if (buttonName == 'title') { - e.append("

 

"); - if (prevButton) { - prevButton.addClass(tm + '-corner-right'); - } - prevButton = null; - }else{ - var buttonClick; - if (calendar[buttonName]) { - buttonClick = calendar[buttonName]; // calendar method - } - else if (fcViews[buttonName]) { - buttonClick = function() { - button.removeClass(tm + '-state-hover'); // forget why - calendar.changeView(buttonName); - }; - } - if (buttonClick) { - var icon = options.theme ? smartProperty(options.buttonIcons, buttonName) : null; // why are we using smartProperty here? - var text = smartProperty(options.buttonText, buttonName); // why are we using smartProperty here? - var button = $( - "" + - (icon ? - "" + - "" + - "" : - text - ) + - "" - ) - .click(function() { - if (!button.hasClass(tm + '-state-disabled')) { - buttonClick(); - } - }) - .mousedown(function() { - button - .not('.' + tm + '-state-active') - .not('.' + tm + '-state-disabled') - .addClass(tm + '-state-down'); - }) - .mouseup(function() { - button.removeClass(tm + '-state-down'); - }) - .hover( - function() { - button - .not('.' + tm + '-state-active') - .not('.' + tm + '-state-disabled') - .addClass(tm + '-state-hover'); - }, - function() { - button - .removeClass(tm + '-state-hover') - .removeClass(tm + '-state-down'); - } - ) - .appendTo(e); - disableTextSelection(button); - if (!prevButton) { - button.addClass(tm + '-corner-left'); - } - prevButton = button; - } - } - }); - if (prevButton) { - prevButton.addClass(tm + '-corner-right'); - } - }); - } - return e; - } - - - function updateTitle(html) { - element.find('h2') - .html(html); - } - - - function activateButton(buttonName) { - element.find('span.fc-button-' + buttonName) - .addClass(tm + '-state-active'); - } - - - function deactivateButton(buttonName) { - element.find('span.fc-button-' + buttonName) - .removeClass(tm + '-state-active'); - } - - - function disableButton(buttonName) { - element.find('span.fc-button-' + buttonName) - .addClass(tm + '-state-disabled'); - } - - - function enableButton(buttonName) { - element.find('span.fc-button-' + buttonName) - .removeClass(tm + '-state-disabled'); - } - - -} - -;; - -fc.sourceNormalizers = []; -fc.sourceFetchers = []; - -var ajaxDefaults = { - dataType: 'json', - cache: false -}; - -var eventGUID = 1; - - -function EventManager(options, _sources) { - var t = this; - - - // exports - t.isFetchNeeded = isFetchNeeded; - t.fetchEvents = fetchEvents; - t.addEventSource = addEventSource; - t.removeEventSource = removeEventSource; - t.updateEvent = updateEvent; - t.renderEvent = renderEvent; - t.removeEvents = removeEvents; - t.clientEvents = clientEvents; - t.normalizeEvent = normalizeEvent; - - - // imports - var trigger = t.trigger; - var getView = t.getView; - var reportEvents = t.reportEvents; - - - // locals - var stickySource = { events: [] }; - var sources = [ stickySource ]; - var rangeStart, rangeEnd; - var currentFetchID = 0; - var pendingSourceCnt = 0; - var loadingLevel = 0; - var cache = []; - - - for (var i=0; i<_sources.length; i++) { - _addEventSource(_sources[i]); - } - - - - /* Fetching - -----------------------------------------------------------------------------*/ - - - function isFetchNeeded(start, end) { - return !rangeStart || start < rangeStart || end > rangeEnd; - } - - - function fetchEvents(start, end) { - rangeStart = start; - rangeEnd = end; - cache = []; - var fetchID = ++currentFetchID; - var len = sources.length; - pendingSourceCnt = len; - for (var i=0; i)), return null instead - return null; -} - - -function parseISO8601(s, ignoreTimezone) { // ignoreTimezone defaults to false - // derived from http://delete.me.uk/2005/03/iso8601.html - // TODO: for a know glitch/feature, read tests/issue_206_parseDate_dst.html - var m = s.match(/^([0-9]{4})(-([0-9]{2})(-([0-9]{2})([T ]([0-9]{2}):([0-9]{2})(:([0-9]{2})(\.([0-9]+))?)?(Z|(([-+])([0-9]{2})(:?([0-9]{2}))?))?)?)?)?$/); - if (!m) { - return null; - } - var date = new Date(m[1], 0, 1); - if (ignoreTimezone || !m[13]) { - var check = new Date(m[1], 0, 1, 9, 0); - if (m[3]) { - date.setMonth(m[3] - 1); - check.setMonth(m[3] - 1); - } - if (m[5]) { - date.setDate(m[5]); - check.setDate(m[5]); - } - fixDate(date, check); - if (m[7]) { - date.setHours(m[7]); - } - if (m[8]) { - date.setMinutes(m[8]); - } - if (m[10]) { - date.setSeconds(m[10]); - } - if (m[12]) { - date.setMilliseconds(Number("0." + m[12]) * 1000); - } - fixDate(date, check); - }else{ - date.setUTCFullYear( - m[1], - m[3] ? m[3] - 1 : 0, - m[5] || 1 - ); - date.setUTCHours( - m[7] || 0, - m[8] || 0, - m[10] || 0, - m[12] ? Number("0." + m[12]) * 1000 : 0 - ); - if (m[14]) { - var offset = Number(m[16]) * 60 + (m[18] ? Number(m[18]) : 0); - offset *= m[15] == '-' ? 1 : -1; - date = new Date(+date + (offset * 60 * 1000)); - } - } - return date; -} - - -function parseTime(s) { // returns minutes since start of day - if (typeof s == 'number') { // an hour - return s * 60; - } - if (typeof s == 'object') { // a Date object - return s.getHours() * 60 + s.getMinutes(); - } - var m = s.match(/(\d+)(?::(\d+))?\s*(\w+)?/); - if (m) { - var h = parseInt(m[1], 10); - if (m[3]) { - h %= 12; - if (m[3].toLowerCase().charAt(0) == 'p') { - h += 12; - } - } - return h * 60 + (m[2] ? parseInt(m[2], 10) : 0); - } -} - - - -/* Date Formatting ------------------------------------------------------------------------------*/ -// TODO: use same function formatDate(date, [date2], format, [options]) - - -function formatDate(date, format, options) { - return formatDates(date, null, format, options); -} - - -function formatDates(date1, date2, format, options) { - options = options || defaults; - var date = date1, - otherDate = date2, - i, len = format.length, c, - i2, formatter, - res = ''; - for (i=0; ii; i2--) { - if (formatter = dateFormatters[format.substring(i, i2)]) { - if (date) { - res += formatter(date, options); - } - i = i2 - 1; - break; - } - } - if (i2 == i) { - if (date) { - res += c; - } - } - } - } - return res; -}; - - -var dateFormatters = { - s : function(d) { return d.getSeconds() }, - ss : function(d) { return zeroPad(d.getSeconds()) }, - m : function(d) { return d.getMinutes() }, - mm : function(d) { return zeroPad(d.getMinutes()) }, - h : function(d) { return d.getHours() % 12 || 12 }, - hh : function(d) { return zeroPad(d.getHours() % 12 || 12) }, - H : function(d) { return d.getHours() }, - HH : function(d) { return zeroPad(d.getHours()) }, - d : function(d) { return d.getDate() }, - dd : function(d) { return zeroPad(d.getDate()) }, - ddd : function(d,o) { return o.dayNamesShort[d.getDay()] }, - dddd: function(d,o) { return o.dayNames[d.getDay()] }, - M : function(d) { return d.getMonth() + 1 }, - MM : function(d) { return zeroPad(d.getMonth() + 1) }, - MMM : function(d,o) { return o.monthNamesShort[d.getMonth()] }, - MMMM: function(d,o) { return o.monthNames[d.getMonth()] }, - yy : function(d) { return (d.getFullYear()+'').substring(2) }, - yyyy: function(d) { return d.getFullYear() }, - t : function(d) { return d.getHours() < 12 ? 'a' : 'p' }, - tt : function(d) { return d.getHours() < 12 ? 'am' : 'pm' }, - T : function(d) { return d.getHours() < 12 ? 'A' : 'P' }, - TT : function(d) { return d.getHours() < 12 ? 'AM' : 'PM' }, - u : function(d) { return formatDate(d, "yyyy-MM-dd'T'HH:mm:ss'Z'") }, - S : function(d) { - var date = d.getDate(); - if (date > 10 && date < 20) { - return 'th'; - } - return ['st', 'nd', 'rd'][date%10-1] || 'th'; - }, - w : function(d, o) { // local - return o.weekNumberCalculation(d); - }, - W : function(d) { // ISO - return iso8601Week(d); - } -}; -fc.dateFormatters = dateFormatters; - - -/* thanks jQuery UI (https://github.com/jquery/jquery-ui/blob/master/ui/jquery.ui.datepicker.js) - * - * Set as calculateWeek to determine the week of the year based on the ISO 8601 definition. - * `date` - the date to get the week for - * `number` - the number of the week within the year that contains this date - */ -function iso8601Week(date) { - var time; - var checkDate = new Date(date.getTime()); - - // Find Thursday of this week starting on Monday - checkDate.setDate(checkDate.getDate() + 4 - (checkDate.getDay() || 7)); - - time = checkDate.getTime(); - checkDate.setMonth(0); // Compare with Jan 1 - checkDate.setDate(1); - return Math.floor(Math.round((time - checkDate) / 86400000) / 7) + 1; -} - - -;; - -fc.applyAll = applyAll; - - -/* Event Date Math ------------------------------------------------------------------------------*/ - - -function exclEndDay(event) { - if (event.end) { - return _exclEndDay(event.end, event.allDay); - }else{ - return addDays(cloneDate(event.start), 1); - } -} - - -function _exclEndDay(end, allDay) { - end = cloneDate(end); - return allDay || end.getHours() || end.getMinutes() ? addDays(end, 1) : clearTime(end); - // why don't we check for seconds/ms too? -} - - - -/* Event Element Binding ------------------------------------------------------------------------------*/ - - -function lazySegBind(container, segs, bindHandlers) { - container.unbind('mouseover').mouseover(function(ev) { - var parent=ev.target, e, - i, seg; - while (parent != this) { - e = parent; - parent = parent.parentNode; - } - if ((i = e._fci) !== undefined) { - e._fci = undefined; - seg = segs[i]; - bindHandlers(seg.event, seg.element, seg); - $(ev.target).trigger(ev); - } - ev.stopPropagation(); - }); -} - - - -/* Element Dimensions ------------------------------------------------------------------------------*/ - - -function setOuterWidth(element, width, includeMargins) { - for (var i=0, e; i=0; i--) { - res = obj[parts[i].toLowerCase()]; - if (res !== undefined) { - return res; - } - } - return obj['']; -} - - -function htmlEscape(s) { - return s.replace(/&/g, '&') - .replace(//g, '>') - .replace(/'/g, ''') - .replace(/"/g, '"') - .replace(/\n/g, '
'); -} - - -function disableTextSelection(element) { - element - .attr('unselectable', 'on') - .css('MozUserSelect', 'none') - .bind('selectstart.ui', function() { return false; }); -} - - -/* -function enableTextSelection(element) { - element - .attr('unselectable', 'off') - .css('MozUserSelect', '') - .unbind('selectstart.ui'); -} -*/ - - -function markFirstLast(e) { - e.children() - .removeClass('fc-first fc-last') - .filter(':first-child') - .addClass('fc-first') - .end() - .filter(':last-child') - .addClass('fc-last'); -} - - -function setDayID(cell, date) { - cell.each(function(i, _cell) { - _cell.className = _cell.className.replace(/^fc-\w*/, 'fc-' + dayIDs[date.getDay()]); - // TODO: make a way that doesn't rely on order of classes - }); -} - - -function getSkinCss(event, opt) { - var source = event.source || {}; - var eventColor = event.color; - var sourceColor = source.color; - var optionColor = opt('eventColor'); - var backgroundColor = - event.backgroundColor || - eventColor || - source.backgroundColor || - sourceColor || - opt('eventBackgroundColor') || - optionColor; - var borderColor = - event.borderColor || - eventColor || - source.borderColor || - sourceColor || - opt('eventBorderColor') || - optionColor; - var textColor = - event.textColor || - source.textColor || - opt('eventTextColor'); - var statements = []; - if (backgroundColor) { - statements.push('background-color:' + backgroundColor); - } - if (borderColor) { - statements.push('border-color:' + borderColor); - } - if (textColor) { - statements.push('color:' + textColor); - } - return statements.join(';'); -} - - -function applyAll(functions, thisObj, args) { - if ($.isFunction(functions)) { - functions = [ functions ]; - } - if (functions) { - var i; - var ret; - for (i=0; i") - .appendTo(element); - } - - - function buildTable() { - var html = buildTableHTML(); - - if (table) { - table.remove(); - } - table = $(html).appendTo(element); - - head = table.find('thead'); - headCells = head.find('.fc-day-header'); - body = table.find('tbody'); - bodyRows = body.find('tr'); - bodyCells = body.find('.fc-day'); - bodyFirstCells = bodyRows.find('td:first-child'); - - firstRowCellInners = bodyRows.eq(0).find('.fc-day > div'); - firstRowCellContentInners = bodyRows.eq(0).find('.fc-day-content > div'); - - markFirstLast(head.add(head.find('tr'))); // marks first+last tr/th's - markFirstLast(bodyRows); // marks first+last td's - bodyRows.eq(0).addClass('fc-first'); - bodyRows.filter(':last').addClass('fc-last'); - - bodyCells.each(function(i, _cell) { - var date = cellToDate( - Math.floor(i / colCnt), - i % colCnt - ); - trigger('dayRender', t, date, $(_cell)); - }); - - dayBind(bodyCells); - } - - - - /* HTML Building - -----------------------------------------------------------*/ - - - function buildTableHTML() { - var html = - "" + - buildHeadHTML() + - buildBodyHTML() + - "
"; - - return html; - } - - - function buildHeadHTML() { - var headerClass = tm + "-widget-header"; - var html = ''; - var col; - var date; - - html += "
" + - htmlEscape(weekNumberTitle) + - "
" + - "" + - "" + - "" + - "" + - "" + - "
" + opt('allDayText') + "" + - "
" + - "
 
"; - allDayTable = $(s).appendTo(slotLayer); - allDayRow = allDayTable.find('tr'); - - dayBind(allDayRow.find('td')); - - slotLayer.append( - "
" + - "
" + - "
" - ); - - }else{ - - daySegmentContainer = $([]); // in jQuery 1.4, we can just do $() - - } - - slotScroller = - $("
") - .appendTo(slotLayer); - - slotContainer = - $("
") - .appendTo(slotScroller); - - slotSegmentContainer = - $("
") - .appendTo(slotContainer); - - s = - "" + - ""; - d = zeroDate(); - maxd = addMinutes(cloneDate(d), maxMinute); - addMinutes(d, minMinute); - slotCnt = 0; - for (i=0; d < maxd; i++) { - minutes = d.getMinutes(); - s += - "" + - "" + - "" + - ""; - addMinutes(d, opt('slotMinutes')); - slotCnt++; - } - s += - "" + - "
" + - ((!slotNormal || !minutes) ? formatDate(d, opt('axisFormat')) : ' ') + - "" + - "
 
" + - "
"; - slotTable = $(s).appendTo(slotContainer); - - slotBind(slotTable.find('td')); - } - - - - /* Build Day Table - -----------------------------------------------------------------------*/ - - - function buildDayTable() { - var html = buildDayTableHTML(); - - if (dayTable) { - dayTable.remove(); - } - dayTable = $(html).appendTo(element); - - dayHead = dayTable.find('thead'); - dayHeadCells = dayHead.find('th').slice(1, -1); // exclude gutter - dayBody = dayTable.find('tbody'); - dayBodyCells = dayBody.find('td').slice(0, -1); // exclude gutter - dayBodyCellInners = dayBodyCells.find('> div'); - dayBodyCellContentInners = dayBodyCells.find('.fc-day-content > div'); - - dayBodyFirstCell = dayBodyCells.eq(0); - dayBodyFirstCellStretcher = dayBodyCellInners.eq(0); - - markFirstLast(dayHead.add(dayHead.find('tr'))); - markFirstLast(dayBody.add(dayBody.find('tr'))); - - // TODO: now that we rebuild the cells every time, we should call dayRender - } - - - function buildDayTableHTML() { - var html = - "" + - buildDayTableHeadHTML() + - buildDayTableBodyHTML() + - "
"; - - return html; - } - - - function buildDayTableHeadHTML() { - var headerClass = tm + "-widget-header"; - var date; - var html = ''; - var weekText; - var col; - - html += - "" + - ""; - - if (showWeekNumbers) { - date = cellToDate(0, 0); - weekText = formatDate(date, weekNumberFormat); - if (rtl) { - weekText += weekNumberTitle; - } - else { - weekText = weekNumberTitle + weekText; - } - html += - "" + - htmlEscape(weekText) + - ""; - } - else { - html += " "; - } - - for (col=0; col" + - htmlEscape(formatDate(date, colFormat)) + - ""; - } - - html += - " " + - "" + - ""; - - return html; - } - - - function buildDayTableBodyHTML() { - var headerClass = tm + "-widget-header"; // TODO: make these when updateOptions() called - var contentClass = tm + "-widget-content"; - var date; - var today = clearTime(new Date()); - var col; - var cellsHTML; - var cellHTML; - var classNames; - var html = ''; - - html += - "" + - "" + - " "; - - cellsHTML = ''; - - for (col=0; col" + - "
" + - "
" + - "
 
" + - "
" + - "
" + - ""; - - cellsHTML += cellHTML; - } - - html += cellsHTML; - html += - " " + - "" + - ""; - - return html; - } - - - // TODO: data-date on the cells - - - - /* Dimensions - -----------------------------------------------------------------------*/ - - - function setHeight(height) { - if (height === undefined) { - height = viewHeight; - } - viewHeight = height; - slotTopCache = {}; - - var headHeight = dayBody.position().top; - var allDayHeight = slotScroller.position().top; // including divider - var bodyHeight = Math.min( // total body height, including borders - height - headHeight, // when scrollbars - slotTable.height() + allDayHeight + 1 // when no scrollbars. +1 for bottom border - ); - - dayBodyFirstCellStretcher - .height(bodyHeight - vsides(dayBodyFirstCell)); - - slotLayer.css('top', headHeight); - - slotScroller.height(bodyHeight - allDayHeight - 1); - - // the stylesheet guarantees that the first row has no border. - // this allows .height() to work well cross-browser. - slotHeight = slotTable.find('tr:first').height() + 1; // +1 for bottom border - - snapRatio = opt('slotMinutes') / snapMinutes; - snapHeight = slotHeight / snapRatio; - } - - - function setWidth(width) { - viewWidth = width; - colPositions.clear(); - colContentPositions.clear(); - - var axisFirstCells = dayHead.find('th:first'); - if (allDayTable) { - axisFirstCells = axisFirstCells.add(allDayTable.find('th:first')); - } - axisFirstCells = axisFirstCells.add(slotTable.find('th:first')); - - axisWidth = 0; - setOuterWidth( - axisFirstCells - .width('') - .each(function(i, _cell) { - axisWidth = Math.max(axisWidth, $(_cell).outerWidth()); - }), - axisWidth - ); - - var gutterCells = dayTable.find('.fc-agenda-gutter'); - if (allDayTable) { - gutterCells = gutterCells.add(allDayTable.find('th.fc-agenda-gutter')); - } - - var slotTableWidth = slotScroller[0].clientWidth; // needs to be done after axisWidth (for IE7) - - gutterWidth = slotScroller.width() - slotTableWidth; - if (gutterWidth) { - setOuterWidth(gutterCells, gutterWidth); - gutterCells - .show() - .prev() - .removeClass('fc-last'); - }else{ - gutterCells - .hide() - .prev() - .addClass('fc-last'); - } - - colWidth = Math.floor((slotTableWidth - axisWidth) / colCnt); - setOuterWidth(dayHeadCells.slice(0, -1), colWidth); - } - - - - /* Scrolling - -----------------------------------------------------------------------*/ - - - function resetScroll() { - var d0 = zeroDate(); - var scrollDate = cloneDate(d0); - scrollDate.setHours(opt('firstHour')); - var top = timePosition(d0, scrollDate) + 1; // +1 for the border - function scroll() { - slotScroller.scrollTop(top); - } - scroll(); - setTimeout(scroll, 0); // overrides any previous scroll state made by the browser - } - - - function afterRender() { // after the view has been freshly rendered and sized - resetScroll(); - } - - - - /* Slot/Day clicking and binding - -----------------------------------------------------------------------*/ - - - function dayBind(cells) { - cells.click(slotClick) - .mousedown(daySelectionMousedown); - } - - - function slotBind(cells) { - cells.click(slotClick) - .mousedown(slotSelectionMousedown); - } - - - function slotClick(ev) { - if (!opt('selectable')) { // if selectable, SelectionManager will worry about dayClick - var col = Math.min(colCnt-1, Math.floor((ev.pageX - dayTable.offset().left - axisWidth) / colWidth)); - var date = cellToDate(0, col); - var rowMatch = this.parentNode.className.match(/fc-slot(\d+)/); // TODO: maybe use data - if (rowMatch) { - var mins = parseInt(rowMatch[1]) * opt('slotMinutes'); - var hours = Math.floor(mins/60); - date.setHours(hours); - date.setMinutes(mins%60 + minMinute); - trigger('dayClick', dayBodyCells[col], date, false, ev); - }else{ - trigger('dayClick', dayBodyCells[col], date, true, ev); - } - } - } - - - - /* Semi-transparent Overlay Helpers - -----------------------------------------------------*/ - // TODO: should be consolidated with BasicView's methods - - - function renderDayOverlay(overlayStart, overlayEnd, refreshCoordinateGrid) { // overlayEnd is exclusive - - if (refreshCoordinateGrid) { - coordinateGrid.build(); - } - - var segments = rangeToSegments(overlayStart, overlayEnd); - - for (var i=0; i= 0) { - addMinutes(d, minMinute + slotIndex * snapMinutes); - } - return d; - } - - - // get the Y coordinate of the given time on the given day (both Date objects) - function timePosition(day, time) { // both date objects. day holds 00:00 of current day - day = cloneDate(day, true); - if (time < addMinutes(cloneDate(day), minMinute)) { - return 0; - } - if (time >= addMinutes(cloneDate(day), maxMinute)) { - return slotTable.height(); - } - var slotMinutes = opt('slotMinutes'), - minutes = time.getHours()*60 + time.getMinutes() - minMinute, - slotI = Math.floor(minutes / slotMinutes), - slotTop = slotTopCache[slotI]; - if (slotTop === undefined) { - slotTop = slotTopCache[slotI] = - slotTable.find('tr').eq(slotI).find('td div')[0].offsetTop; - // .eq() is faster than ":eq()" selector - // [0].offsetTop is faster than .position().top (do we really need this optimization?) - // a better optimization would be to cache all these divs - } - return Math.max(0, Math.round( - slotTop - 1 + slotHeight * ((minutes % slotMinutes) / slotMinutes) - )); - } - - - function getAllDayRow(index) { - return allDayRow; - } - - - function defaultEventEnd(event) { - var start = cloneDate(event.start); - if (event.allDay) { - return start; - } - return addMinutes(start, opt('defaultEventMinutes')); - } - - - - /* Selection - ---------------------------------------------------------------------------------*/ - - - function defaultSelectionEnd(startDate, allDay) { - if (allDay) { - return cloneDate(startDate); - } - return addMinutes(cloneDate(startDate), opt('slotMinutes')); - } - - - function renderSelection(startDate, endDate, allDay) { // only for all-day - if (allDay) { - if (opt('allDaySlot')) { - renderDayOverlay(startDate, addDays(cloneDate(endDate), 1), true); - } - }else{ - renderSlotSelection(startDate, endDate); - } - } - - - function renderSlotSelection(startDate, endDate) { - var helperOption = opt('selectHelper'); - coordinateGrid.build(); - if (helperOption) { - var col = dateToCell(startDate).col; - if (col >= 0 && col < colCnt) { // only works when times are on same day - var rect = coordinateGrid.rect(0, col, 0, col, slotContainer); // only for horizontal coords - var top = timePosition(startDate, startDate); - var bottom = timePosition(startDate, endDate); - if (bottom > top) { // protect against selections that are entirely before or after visible range - rect.top = top; - rect.height = bottom - top; - rect.left += 2; - rect.width -= 5; - if ($.isFunction(helperOption)) { - var helperRes = helperOption(startDate, endDate); - if (helperRes) { - rect.position = 'absolute'; - selectionHelper = $(helperRes) - .css(rect) - .appendTo(slotContainer); - } - }else{ - rect.isStart = true; // conside rect a "seg" now - rect.isEnd = true; // - selectionHelper = $(slotSegHtml( - { - title: '', - start: startDate, - end: endDate, - className: ['fc-select-helper'], - editable: false - }, - rect - )); - selectionHelper.css('opacity', opt('dragOpacity')); - } - if (selectionHelper) { - slotBind(selectionHelper); - slotContainer.append(selectionHelper); - setOuterWidth(selectionHelper, rect.width, true); // needs to be after appended - setOuterHeight(selectionHelper, rect.height, true); - } - } - } - }else{ - renderSlotOverlay(startDate, endDate); - } - } - - - function clearSelection() { - clearOverlays(); - if (selectionHelper) { - selectionHelper.remove(); - selectionHelper = null; - } - } - - - function slotSelectionMousedown(ev) { - if (ev.which == 1 && opt('selectable')) { // ev.which==1 means left mouse button - unselect(ev); - var dates; - hoverListener.start(function(cell, origCell) { - clearSelection(); - if (cell && cell.col == origCell.col && !getIsCellAllDay(cell)) { - var d1 = realCellToDate(origCell); - var d2 = realCellToDate(cell); - dates = [ - d1, - addMinutes(cloneDate(d1), snapMinutes), // calculate minutes depending on selection slot minutes - d2, - addMinutes(cloneDate(d2), snapMinutes) - ].sort(dateCompare); - renderSlotSelection(dates[0], dates[3]); - }else{ - dates = null; - } - }, ev); - $(document).one('mouseup', function(ev) { - hoverListener.stop(); - if (dates) { - if (+dates[0] == +dates[1]) { - reportDayClick(dates[0], false, ev); - } - reportSelection(dates[0], dates[3], false, ev); - } - }); - } - } - - - function reportDayClick(date, allDay, ev) { - trigger('dayClick', dayBodyCells[dateToCell(date).col], date, allDay, ev); - } - - - - /* External Dragging - --------------------------------------------------------------------------------*/ - - - function dragStart(_dragElement, ev, ui) { - hoverListener.start(function(cell) { - clearOverlays(); - if (cell) { - if (getIsCellAllDay(cell)) { - renderCellOverlay(cell.row, cell.col, cell.row, cell.col); - }else{ - var d1 = realCellToDate(cell); - var d2 = addMinutes(cloneDate(d1), opt('defaultEventMinutes')); - renderSlotOverlay(d1, d2); - } - } - }, ev); - } - - - function dragStop(_dragElement, ev, ui) { - var cell = hoverListener.stop(); - clearOverlays(); - if (cell) { - trigger('drop', _dragElement, realCellToDate(cell), getIsCellAllDay(cell), ev, ui); - } - } - - -} - -;; - -function AgendaEventRenderer() { - var t = this; - - - // exports - t.renderEvents = renderEvents; - t.clearEvents = clearEvents; - t.slotSegHtml = slotSegHtml; - - - // imports - DayEventRenderer.call(t); - var opt = t.opt; - var trigger = t.trigger; - var isEventDraggable = t.isEventDraggable; - var isEventResizable = t.isEventResizable; - var eventEnd = t.eventEnd; - var eventElementHandlers = t.eventElementHandlers; - var setHeight = t.setHeight; - var getDaySegmentContainer = t.getDaySegmentContainer; - var getSlotSegmentContainer = t.getSlotSegmentContainer; - var getHoverListener = t.getHoverListener; - var getMaxMinute = t.getMaxMinute; - var getMinMinute = t.getMinMinute; - var timePosition = t.timePosition; - var getIsCellAllDay = t.getIsCellAllDay; - var colContentLeft = t.colContentLeft; - var colContentRight = t.colContentRight; - var cellToDate = t.cellToDate; - var getColCnt = t.getColCnt; - var getColWidth = t.getColWidth; - var getSnapHeight = t.getSnapHeight; - var getSnapMinutes = t.getSnapMinutes; - var getSlotContainer = t.getSlotContainer; - var reportEventElement = t.reportEventElement; - var showEvents = t.showEvents; - var hideEvents = t.hideEvents; - var eventDrop = t.eventDrop; - var eventResize = t.eventResize; - var renderDayOverlay = t.renderDayOverlay; - var clearOverlays = t.clearOverlays; - var renderDayEvents = t.renderDayEvents; - var calendar = t.calendar; - var formatDate = calendar.formatDate; - var formatDates = calendar.formatDates; - - - // overrides - t.draggableDayEvent = draggableDayEvent; - - - - /* Rendering - ----------------------------------------------------------------------------*/ - - - function renderEvents(events, modifiedEventId) { - var i, len=events.length, - dayEvents=[], - slotEvents=[]; - for (i=0; i start && eventStart < end) { - if (eventStart < start) { - segStart = cloneDate(start); - isStart = false; - }else{ - segStart = eventStart; - isStart = true; - } - if (eventEnd > end) { - segEnd = cloneDate(end); - isEnd = false; - }else{ - segEnd = eventEnd; - isEnd = true; - } - segs.push({ - event: event, - start: segStart, - end: segEnd, - isStart: isStart, - isEnd: isEnd - }); - } - } - return segs.sort(compareSlotSegs); - } - - - function slotEventEnd(event) { - if (event.end) { - return cloneDate(event.end); - }else{ - return addMinutes(cloneDate(event.start), opt('defaultEventMinutes')); - } - } - - - // renders events in the 'time slots' at the bottom - // TODO: when we refactor this, when user returns `false` eventRender, don't have empty space - // TODO: refactor will include using pixels to detect collisions instead of dates (handy for seg cmp) - - function renderSlotSegs(segs, modifiedEventId) { - - var i, segCnt=segs.length, seg, - event, - top, - bottom, - columnLeft, - columnRight, - columnWidth, - width, - left, - right, - html = '', - eventElements, - eventElement, - triggerRes, - titleElement, - height, - slotSegmentContainer = getSlotSegmentContainer(), - isRTL = opt('isRTL'); - - // calculate position/dimensions, create html - for (i=0; i" + - "
" + - "
" + - htmlEscape(formatDates(event.start, event.end, opt('timeFormat'))) + - "
" + - "
" + - htmlEscape(event.title || '') + - "
" + - "
" + - "
"; - if (seg.isEnd && isEventResizable(event)) { - html += - "
=
"; - } - html += - ""; - return html; - } - - - function bindSlotSeg(event, eventElement, seg) { - var timeElement = eventElement.find('div.fc-event-time'); - if (isEventDraggable(event)) { - draggableSlotEvent(event, eventElement, timeElement); - } - if (seg.isEnd && isEventResizable(event)) { - resizableSlotEvent(event, eventElement, timeElement); - } - eventElementHandlers(event, eventElement); - } - - - - /* Dragging - -----------------------------------------------------------------------------------*/ - - - // when event starts out FULL-DAY - // overrides DayEventRenderer's version because it needs to account for dragging elements - // to and from the slot area. - - function draggableDayEvent(event, eventElement, seg) { - var isStart = seg.isStart; - var origWidth; - var revert; - var allDay = true; - var dayDelta; - var hoverListener = getHoverListener(); - var colWidth = getColWidth(); - var snapHeight = getSnapHeight(); - var snapMinutes = getSnapMinutes(); - var minMinute = getMinMinute(); - eventElement.draggable({ - opacity: opt('dragOpacity', 'month'), // use whatever the month view was using - revertDuration: opt('dragRevertDuration'), - start: function(ev, ui) { - trigger('eventDragStart', eventElement, event, ev, ui); - hideEvents(event, eventElement); - origWidth = eventElement.width(); - hoverListener.start(function(cell, origCell) { - clearOverlays(); - if (cell) { - revert = false; - var origDate = cellToDate(0, origCell.col); - var date = cellToDate(0, cell.col); - dayDelta = dayDiff(date, origDate); - if (!cell.row) { - // on full-days - renderDayOverlay( - addDays(cloneDate(event.start), dayDelta), - addDays(exclEndDay(event), dayDelta) - ); - resetElement(); - }else{ - // mouse is over bottom slots - if (isStart) { - if (allDay) { - // convert event to temporary slot-event - eventElement.width(colWidth - 10); // don't use entire width - setOuterHeight( - eventElement, - snapHeight * Math.round( - (event.end ? ((event.end - event.start) / MINUTE_MS) : opt('defaultEventMinutes')) / - snapMinutes - ) - ); - eventElement.draggable('option', 'grid', [colWidth, 1]); - allDay = false; - } - }else{ - revert = true; - } - } - revert = revert || (allDay && !dayDelta); - }else{ - resetElement(); - revert = true; - } - eventElement.draggable('option', 'revert', revert); - }, ev, 'drag'); - }, - stop: function(ev, ui) { - hoverListener.stop(); - clearOverlays(); - trigger('eventDragStop', eventElement, event, ev, ui); - if (revert) { - // hasn't moved or is out of bounds (draggable has already reverted) - resetElement(); - eventElement.css('filter', ''); // clear IE opacity side-effects - showEvents(event, eventElement); - }else{ - // changed! - var minuteDelta = 0; - if (!allDay) { - minuteDelta = Math.round((eventElement.offset().top - getSlotContainer().offset().top) / snapHeight) - * snapMinutes - + minMinute - - (event.start.getHours() * 60 + event.start.getMinutes()); - } - eventDrop(this, event, dayDelta, minuteDelta, allDay, ev, ui); - } - } - }); - function resetElement() { - if (!allDay) { - eventElement - .width(origWidth) - .height('') - .draggable('option', 'grid', null); - allDay = true; - } - } - } - - - // when event starts out IN TIMESLOTS - - function draggableSlotEvent(event, eventElement, timeElement) { - var coordinateGrid = t.getCoordinateGrid(); - var colCnt = getColCnt(); - var colWidth = getColWidth(); - var snapHeight = getSnapHeight(); - var snapMinutes = getSnapMinutes(); - - // states - var origPosition; // original position of the element, not the mouse - var origCell; - var isInBounds, prevIsInBounds; - var isAllDay, prevIsAllDay; - var colDelta, prevColDelta; - var dayDelta; // derived from colDelta - var minuteDelta, prevMinuteDelta; - - eventElement.draggable({ - scroll: false, - grid: [ colWidth, snapHeight ], - axis: colCnt==1 ? 'y' : false, - opacity: opt('dragOpacity'), - revertDuration: opt('dragRevertDuration'), - start: function(ev, ui) { - - trigger('eventDragStart', eventElement, event, ev, ui); - hideEvents(event, eventElement); - - coordinateGrid.build(); - - // initialize states - origPosition = eventElement.position(); - origCell = coordinateGrid.cell(ev.pageX, ev.pageY); - isInBounds = prevIsInBounds = true; - isAllDay = prevIsAllDay = getIsCellAllDay(origCell); - colDelta = prevColDelta = 0; - dayDelta = 0; - minuteDelta = prevMinuteDelta = 0; - - }, - drag: function(ev, ui) { - - // NOTE: this `cell` value is only useful for determining in-bounds and all-day. - // Bad for anything else due to the discrepancy between the mouse position and the - // element position while snapping. (problem revealed in PR #55) - // - // PS- the problem exists for draggableDayEvent() when dragging an all-day event to a slot event. - // We should overhaul the dragging system and stop relying on jQuery UI. - var cell = coordinateGrid.cell(ev.pageX, ev.pageY); - - // update states - isInBounds = !!cell; - if (isInBounds) { - isAllDay = getIsCellAllDay(cell); - - // calculate column delta - colDelta = Math.round((ui.position.left - origPosition.left) / colWidth); - if (colDelta != prevColDelta) { - // calculate the day delta based off of the original clicked column and the column delta - var origDate = cellToDate(0, origCell.col); - var col = origCell.col + colDelta; - col = Math.max(0, col); - col = Math.min(colCnt-1, col); - var date = cellToDate(0, col); - dayDelta = dayDiff(date, origDate); - } - - // calculate minute delta (only if over slots) - if (!isAllDay) { - minuteDelta = Math.round((ui.position.top - origPosition.top) / snapHeight) * snapMinutes; - } - } - - // any state changes? - if ( - isInBounds != prevIsInBounds || - isAllDay != prevIsAllDay || - colDelta != prevColDelta || - minuteDelta != prevMinuteDelta - ) { - - updateUI(); - - // update previous states for next time - prevIsInBounds = isInBounds; - prevIsAllDay = isAllDay; - prevColDelta = colDelta; - prevMinuteDelta = minuteDelta; - } - - // if out-of-bounds, revert when done, and vice versa. - eventElement.draggable('option', 'revert', !isInBounds); - - }, - stop: function(ev, ui) { - - clearOverlays(); - trigger('eventDragStop', eventElement, event, ev, ui); - - if (isInBounds && (isAllDay || dayDelta || minuteDelta)) { // changed! - eventDrop(this, event, dayDelta, isAllDay ? 0 : minuteDelta, isAllDay, ev, ui); - } - else { // either no change or out-of-bounds (draggable has already reverted) - - // reset states for next time, and for updateUI() - isInBounds = true; - isAllDay = false; - colDelta = 0; - dayDelta = 0; - minuteDelta = 0; - - updateUI(); - eventElement.css('filter', ''); // clear IE opacity side-effects - - // sometimes fast drags make event revert to wrong position, so reset. - // also, if we dragged the element out of the area because of snapping, - // but the *mouse* is still in bounds, we need to reset the position. - eventElement.css(origPosition); - - showEvents(event, eventElement); - } - } - }); - - function updateUI() { - clearOverlays(); - if (isInBounds) { - if (isAllDay) { - timeElement.hide(); - eventElement.draggable('option', 'grid', null); // disable grid snapping - renderDayOverlay( - addDays(cloneDate(event.start), dayDelta), - addDays(exclEndDay(event), dayDelta) - ); - } - else { - updateTimeText(minuteDelta); - timeElement.css('display', ''); // show() was causing display=inline - eventElement.draggable('option', 'grid', [colWidth, snapHeight]); // re-enable grid snapping - } - } - } - - function updateTimeText(minuteDelta) { - var newStart = addMinutes(cloneDate(event.start), minuteDelta); - var newEnd; - if (event.end) { - newEnd = addMinutes(cloneDate(event.end), minuteDelta); - } - timeElement.text(formatDates(newStart, newEnd, opt('timeFormat'))); - } - - } - - - - /* Resizing - --------------------------------------------------------------------------------------*/ - - - function resizableSlotEvent(event, eventElement, timeElement) { - var snapDelta, prevSnapDelta; - var snapHeight = getSnapHeight(); - var snapMinutes = getSnapMinutes(); - eventElement.resizable({ - handles: { - s: '.ui-resizable-handle' - }, - grid: snapHeight, - start: function(ev, ui) { - snapDelta = prevSnapDelta = 0; - hideEvents(event, eventElement); - trigger('eventResizeStart', this, event, ev, ui); - }, - resize: function(ev, ui) { - // don't rely on ui.size.height, doesn't take grid into account - snapDelta = Math.round((Math.max(snapHeight, eventElement.height()) - ui.originalSize.height) / snapHeight); - if (snapDelta != prevSnapDelta) { - timeElement.text( - formatDates( - event.start, - (!snapDelta && !event.end) ? null : // no change, so don't display time range - addMinutes(eventEnd(event), snapMinutes*snapDelta), - opt('timeFormat') - ) - ); - prevSnapDelta = snapDelta; - } - }, - stop: function(ev, ui) { - trigger('eventResizeStop', this, event, ev, ui); - if (snapDelta) { - eventResize(this, event, 0, snapMinutes*snapDelta, ev, ui); - }else{ - showEvents(event, eventElement); - // BUG: if event was really short, need to put title back in span - } - } - }); - } - - -} - - - -/* Agenda Event Segment Utilities ------------------------------------------------------------------------------*/ - - -// Sets the seg.backwardCoord and seg.forwardCoord on each segment and returns a new -// list in the order they should be placed into the DOM (an implicit z-index). -function placeSlotSegs(segs) { - var levels = buildSlotSegLevels(segs); - var level0 = levels[0]; - var i; - - computeForwardSlotSegs(levels); - - if (level0) { - - for (i=0; i seg2.start && seg1.start < seg2.end; -} - - -// A cmp function for determining which forward segment to rely on more when computing coordinates. -function compareForwardSlotSegs(seg1, seg2) { - // put higher-pressure first - return seg2.forwardPressure - seg1.forwardPressure || - // put segments that are closer to initial edge first (and favor ones with no coords yet) - (seg1.backwardCoord || 0) - (seg2.backwardCoord || 0) || - // do normal sorting... - compareSlotSegs(seg1, seg2); -} - - -// A cmp function for determining which segment should be closer to the initial edge -// (the left edge on a left-to-right calendar). -function compareSlotSegs(seg1, seg2) { - return seg1.start - seg2.start || // earlier start time goes first - (seg2.end - seg2.start) - (seg1.end - seg1.start) || // tie? longer-duration goes first - (seg1.event.title || '').localeCompare(seg2.event.title); // tie? alphabetically by title -} - - -;; - - -function View(element, calendar, viewName) { - var t = this; - - - // exports - t.element = element; - t.calendar = calendar; - t.name = viewName; - t.opt = opt; - t.trigger = trigger; - t.isEventDraggable = isEventDraggable; - t.isEventResizable = isEventResizable; - t.setEventData = setEventData; - t.clearEventData = clearEventData; - t.eventEnd = eventEnd; - t.reportEventElement = reportEventElement; - t.triggerEventDestroy = triggerEventDestroy; - t.eventElementHandlers = eventElementHandlers; - t.showEvents = showEvents; - t.hideEvents = hideEvents; - t.eventDrop = eventDrop; - t.eventResize = eventResize; - // t.title - // t.start, t.end - // t.visStart, t.visEnd - - - // imports - var defaultEventEnd = t.defaultEventEnd; - var normalizeEvent = calendar.normalizeEvent; // in EventManager - var reportEventChange = calendar.reportEventChange; - - - // locals - var eventsByID = {}; // eventID mapped to array of events (there can be multiple b/c of repeating events) - var eventElementsByID = {}; // eventID mapped to array of jQuery elements - var eventElementCouples = []; // array of objects, { event, element } // TODO: unify with segment system - var options = calendar.options; - - - - function opt(name, viewNameOverride) { - var v = options[name]; - if ($.isPlainObject(v)) { - return smartProperty(v, viewNameOverride || viewName); - } - return v; - } - - - function trigger(name, thisObj) { - return calendar.trigger.apply( - calendar, - [name, thisObj || t].concat(Array.prototype.slice.call(arguments, 2), [t]) - ); - } - - - - /* Event Editable Boolean Calculations - ------------------------------------------------------------------------------*/ - - - function isEventDraggable(event) { - var source = event.source || {}; - return firstDefined( - event.startEditable, - source.startEditable, - opt('eventStartEditable'), - event.editable, - source.editable, - opt('editable') - ) - && !opt('disableDragging'); // deprecated - } - - - function isEventResizable(event) { // but also need to make sure the seg.isEnd == true - var source = event.source || {}; - return firstDefined( - event.durationEditable, - source.durationEditable, - opt('eventDurationEditable'), - event.editable, - source.editable, - opt('editable') - ) - && !opt('disableResizing'); // deprecated - } - - - - /* Event Data - ------------------------------------------------------------------------------*/ - - - function setEventData(events) { // events are already normalized at this point - eventsByID = {}; - var i, len=events.length, event; - for (i=0; i
").prependTo(n),ne=new a(ee,r),re=ne.render(),re&&n.prepend(re),y(r.defaultView),r.handleWindowResize&&t(window).resize(x),m()||v()}function v(){setTimeout(function(){!ie.start&&m()&&C()},0)}function h(){ie&&(te("viewDestroy",ie,ie,ie.element),ie.triggerEventDestroy()),t(window).unbind("resize",x),ne.destroy(),ae.remove(),n.removeClass("fc fc-rtl ui-widget")}function p(){return n.is(":visible")}function m(){return t("body").is(":visible")}function y(t){ie&&t==ie.name||D(t)}function D(e){he++,ie&&(te("viewDestroy",ie,ie,ie.element),Y(),ie.triggerEventDestroy(),G(),ie.element.remove(),ne.deactivateButton(ie.name)),ne.activateButton(e),ie=new Se[e](t("
").appendTo(ae),ee),C(),$(),he--}function C(t){(!ie.start||t||ie.start>ge||ge>=ie.end)&&p()&&M(t)}function M(t){he++,ie.start&&(te("viewDestroy",ie,ie,ie.element),Y(),N()),G(),ie.render(ge,t||0),T(),$(),(ie.afterRender||A)(),_(),P(),te("viewRender",ie,ie,ie.element),ie.trigger("viewDisplay",de),he--,z()}function E(){p()&&(Y(),N(),S(),T(),F())}function S(){le=r.contentHeight?r.contentHeight:r.height?r.height-(re?re.height():0)-R(ae):Math.round(ae.width()/Math.max(r.aspectRatio,.5))}function T(){le===e&&S(),he++,ie.setHeight(le),ie.setWidth(ae.width()),he--,se=n.outerWidth()}function x(){if(!he)if(ie.start){var t=++ve;setTimeout(function(){t==ve&&!he&&p()&&se!=(se=n.outerWidth())&&(he++,E(),ie.trigger("windowResize",de),he--)},200)}else v()}function k(){N(),W()}function H(t){N(),F(t)}function F(t){p()&&(ie.setEventData(pe),ie.renderEvents(pe,t),ie.trigger("eventAfterAllRender"))}function N(){ie.triggerEventDestroy(),ie.clearEvents(),ie.clearEventData()}function z(){!r.lazyFetching||ue(ie.visStart,ie.visEnd)?W():F()}function W(){fe(ie.visStart,ie.visEnd)}function O(t){pe=t,F()}function L(t){H(t)}function _(){ne.updateTitle(ie.title)}function P(){var t=new Date;t>=ie.start&&ie.end>t?ne.disableButton("today"):ne.enableButton("today")}function q(t,n,r){ie.select(t,n,r===e?!0:r)}function Y(){ie&&ie.unselect()}function B(){C(-1)}function j(){C(1)}function I(){i(ge,-1),C()}function X(){i(ge,1),C()}function J(){ge=new Date,C()}function V(t,e,n){t instanceof Date?ge=d(t):g(ge,t,e,n),C()}function U(t,n,r){t!==e&&i(ge,t),n!==e&&s(ge,n),r!==e&&l(ge,r),C()}function Z(){return d(ge)}function G(){ae.css({width:"100%",height:ae.height(),overflow:"hidden"})}function $(){ae.css({width:"",height:"",overflow:""})}function Q(){return ie}function K(t,n){return n===e?r[t]:(("height"==t||"contentHeight"==t||"aspectRatio"==t)&&(r[t]=n,E()),e)}function te(t,n){return r[t]?r[t].apply(n||de,Array.prototype.slice.call(arguments,2)):e}var ee=this;ee.options=r,ee.render=u,ee.destroy=h,ee.refetchEvents=k,ee.reportEvents=O,ee.reportEventChange=L,ee.rerenderEvents=H,ee.changeView=y,ee.select=q,ee.unselect=Y,ee.prev=B,ee.next=j,ee.prevYear=I,ee.nextYear=X,ee.today=J,ee.gotoDate=V,ee.incrementDate=U,ee.formatDate=function(t,e){return w(t,e,r)},ee.formatDates=function(t,e,n){return b(t,e,n,r)},ee.getDate=Z,ee.getView=Q,ee.option=K,ee.trigger=te,o.call(ee,r,c);var ne,re,ae,oe,ie,se,le,ce,ue=ee.isFetchNeeded,fe=ee.fetchEvents,de=n[0],ve=0,he=0,ge=new Date,pe=[];g(ge,r.year,r.month,r.date),r.droppable&&t(document).bind("dragstart",function(e,n){var a=e.target,o=t(a);if(!o.parents(".fc").length){var i=r.dropAccept;(t.isFunction(i)?i.call(a,o):o.is(i))&&(ce=a,ie.dragStart(ce,e,n))}}).bind("dragstop",function(t,e){ce&&(ie.dragStop(ce,t,e),ce=null)})}function a(n,r){function a(){v=r.theme?"ui":"fc";var n=r.header;return n?h=t("").append(t("").append(i("left")).append(i("center")).append(i("right"))):e}function o(){h.remove()}function i(e){var a=t("",ue&&(r+=""),t=0;ne>t;t++)e=Ee(0,t),r+="";return r+=""}function v(){var t,e,n,r=le+"-widget-content",a="";for(a+="",t=0;ee>t;t++){for(a+="",ue&&(n=Ee(t,0),a+=""),e=0;ne>e;e++)n=Ee(t,e),a+=h(n);a+=""}return a+=""}function h(t){var e=le+"-widget-content",n=O.start.getMonth(),r=f(new Date),a="",o=["fc-day","fc-"+ke[t.getDay()],e];return t.getMonth()!=n&&o.push("fc-other-month"),+t==+r?o.push("fc-today",le+"-state-highlight"):r>t?o.push("fc-past"):o.push("fc-future"),a+=""}function g(e){Q=e;var n,r,a,o=Q-_.height();"variable"==he("weekMode")?n=r=Math.floor(o/(1==ee?2:6)):(n=Math.floor(o/ee),r=o-n*(ee-1)),J.each(function(e,o){ee>e&&(a=t(o),a.find("> div").css("min-height",(e==ee-1?r:n)-R(a)))})}function p(t){$=t,ie.clear(),se.clear(),te=0,ue&&(te=_.find("th.fc-week-number").outerWidth()),K=Math.floor(($-te)/ne),S(P.slice(0,-1),K)}function y(t){t.click(w).mousedown(Me)}function w(e){if(!he("selectable")){var n=m(t(this).data("date"));ge("dayClick",this,n,!0,e)}}function b(t,e,n){n&&ae.build();for(var r=Te(t,e),a=0;r.length>a;a++){var o=r[a];y(D(o.row,o.leftCol,o.row,o.rightCol))}}function D(t,n,r,a){var o=ae.rect(t,n,r,a,e);return be(o,e)}function C(t){return d(t)}function M(t,e){b(t,l(d(e),1),!0)}function E(){Ce()}function T(t,e,n){var r=Se(t),a=X[r.row*ne+r.col];ge("dayClick",a,t,e,n)}function x(t,e){oe.start(function(t){Ce(),t&&D(t.row,t.col,t.row,t.col)},e)}function k(t,e,n){var r=oe.stop();if(Ce(),r){var a=Ee(r);ge("drop",t,a,!0,e,n)}}function H(t){return d(t.start)}function F(t){return ie.left(t)}function N(t){return ie.right(t)}function z(t){return se.left(t)}function W(t){return se.right(t)}function A(t){return I.eq(t)}var O=this;O.renderBasic=a,O.setHeight=g,O.setWidth=p,O.renderDayOverlay=b,O.defaultSelectionEnd=C,O.renderSelection=M,O.clearSelection=E,O.reportDayClick=T,O.dragStart=x,O.dragStop=k,O.defaultEventEnd=H,O.getHoverListener=function(){return oe},O.colLeft=F,O.colRight=N,O.colContentLeft=z,O.colContentRight=W,O.getIsCellAllDay=function(){return!0},O.allDayRow=A,O.getRowCnt=function(){return ee},O.getColCnt=function(){return ne},O.getColWidth=function(){return K},O.getDaySegmentContainer=function(){return Z},fe.call(O,e,n,r),me.call(O),pe.call(O),G.call(O);var L,_,P,j,I,X,J,V,U,Z,$,Q,K,te,ee,ne,re,ae,oe,ie,se,le,ce,ue,de,ve,he=O.opt,ge=O.trigger,be=O.renderOverlay,Ce=O.clearOverlays,Me=O.daySelectionMousedown,Ee=O.cellToDate,Se=O.dateToCell,Te=O.rangeToSegments,xe=n.formatDate;Y(e.addClass("fc-grid")),ae=new ye(function(e,n){var r,a,o;P.each(function(e,i){r=t(i),a=r.offset().left,e&&(o[1]=a),o=[a],n[e]=o}),o[1]=a+r.outerWidth(),I.each(function(n,i){ee>n&&(r=t(i),a=r.offset().top,n&&(o[1]=a),o=[a],e[n]=o)}),o[1]=a+r.outerHeight()}),oe=new we(ae),ie=new De(function(t){return V.eq(t)}),se=new De(function(t){return U.eq(t)})}function G(){function t(t,e){n.renderDayEvents(t,e)}function e(){n.getDaySegmentContainer().empty()}var n=this;n.renderEvents=t,n.clearEvents=e,de.call(n)}function $(t,e){function n(t,e){e&&l(t,7*e);var n=l(d(t),-((t.getDay()-a("firstDay")+7)%7)),u=l(d(n),7),f=d(n);i(f);var v=d(u);i(v,-1,!0);var h=s();r.title=c(f,l(d(v),-1),a("titleFormat")),r.start=n,r.end=u,r.visStart=f,r.visEnd=v,o(h)}var r=this;r.render=n,K.call(r,t,e,"agendaWeek");var a=r.opt,o=r.renderAgenda,i=r.skipHiddenDays,s=r.getCellsPerWeek,c=e.formatDates}function Q(t,e){function n(t,e){e&&l(t,e),i(t,0>e?-1:1);var n=d(t,!0),c=l(d(n),1);r.title=s(t,a("titleFormat")),r.start=r.visStart=n,r.end=r.visEnd=c,o(1)}var r=this;r.render=n,K.call(r,t,e,"agendaDay");var a=r.opt,o=r.renderAgenda,i=r.skipHiddenDays,s=e.formatDate}function K(n,r,a){function o(t){We=t,i(),K?c():s()}function i(){qe=Ue("theme")?"ui":"fc",Ye=Ue("isRTL"),Be=y(Ue("minTime")),je=y(Ue("maxTime")),Ie=Ue("columnFormat"),Xe=Ue("weekNumbers"),Je=Ue("weekNumberTitle"),Ve="iso"!=Ue("weekNumberCalculation")?"w":"W",Re=Ue("snapMinutes")||Ue("slotMinutes")}function s(){var e,r,a,o,i,s=qe+"-widget-header",l=qe+"-widget-content",f=0==Ue("slotMinutes")%15;for(c(),ce=t("
").appendTo(n),Ue("allDaySlot")?(ue=t("
").appendTo(ce),e="
"),o=r.header[e];return o&&t.each(o.split(" "),function(e){e>0&&a.append("");var o;t.each(this.split(","),function(e,i){if("title"==i)a.append("

 

"),o&&o.addClass(v+"-corner-right"),o=null;else{var s;if(n[i]?s=n[i]:Se[i]&&(s=function(){u.removeClass(v+"-state-hover"),n.changeView(i)}),s){var l=r.theme?P(r.buttonIcons,i):null,c=P(r.buttonText,i),u=t(""+(l?""+"":c)+"").click(function(){u.hasClass(v+"-state-disabled")||s()}).mousedown(function(){u.not("."+v+"-state-active").not("."+v+"-state-disabled").addClass(v+"-state-down")}).mouseup(function(){u.removeClass(v+"-state-down")}).hover(function(){u.not("."+v+"-state-active").not("."+v+"-state-disabled").addClass(v+"-state-hover")},function(){u.removeClass(v+"-state-hover").removeClass(v+"-state-down")}).appendTo(a);Y(u),o||u.addClass(v+"-corner-left"),o=u}}}),o&&o.addClass(v+"-corner-right")}),a}function s(t){h.find("h2").html(t)}function l(t){h.find("span.fc-button-"+t).addClass(v+"-state-active")}function c(t){h.find("span.fc-button-"+t).removeClass(v+"-state-active")}function u(t){h.find("span.fc-button-"+t).addClass(v+"-state-disabled")}function f(t){h.find("span.fc-button-"+t).removeClass(v+"-state-disabled")}var d=this;d.render=a,d.destroy=o,d.updateTitle=s,d.activateButton=l,d.deactivateButton=c,d.disableButton=u,d.enableButton=f;var v,h=t([])}function o(n,r){function a(t,e){return!E||E>t||e>S}function o(t,e){E=t,S=e,W=[];var n=++R,r=F.length;N=r;for(var a=0;r>a;a++)i(F[a],n)}function i(e,r){s(e,function(a){if(r==R){if(a){n.eventDataTransform&&(a=t.map(a,n.eventDataTransform)),e.eventDataTransform&&(a=t.map(a,e.eventDataTransform));for(var o=0;a.length>o;o++)a[o].source=e,w(a[o]);W=W.concat(a)}N--,N||k(W)}})}function s(r,a){var o,i,l=Ee.sourceFetchers;for(o=0;l.length>o;o++){if(i=l[o](r,E,S,a),i===!0)return;if("object"==typeof i)return s(i,a),e}var c=r.events;if(c)t.isFunction(c)?(m(),c(d(E),d(S),function(t){a(t),y()})):t.isArray(c)?a(c):a();else{var u=r.url;if(u){var f,v=r.success,h=r.error,g=r.complete;f=t.isFunction(r.data)?r.data():r.data;var p=t.extend({},f||{}),w=X(r.startParam,n.startParam),b=X(r.endParam,n.endParam);w&&(p[w]=Math.round(+E/1e3)),b&&(p[b]=Math.round(+S/1e3)),m(),t.ajax(t.extend({},Te,r,{data:p,success:function(e){e=e||[];var n=I(v,this,arguments);t.isArray(n)&&(e=n),a(e)},error:function(){I(h,this,arguments),a()},complete:function(){I(g,this,arguments),y()}}))}else a()}}function l(t){t=c(t),t&&(N++,i(t,R))}function c(n){return t.isFunction(n)||t.isArray(n)?n={events:n}:"string"==typeof n&&(n={url:n}),"object"==typeof n?(b(n),F.push(n),n):e}function u(e){F=t.grep(F,function(t){return!D(t,e)}),W=t.grep(W,function(t){return!D(t.source,e)}),k(W)}function f(t){var e,n,r=W.length,a=x().defaultEventEnd,o=t.start-t._start,i=t.end?t.end-(t._end||a(t)):0;for(e=0;r>e;e++)n=W[e],n._id==t._id&&n!=t&&(n.start=new Date(+n.start+o),n.end=t.end?n.end?new Date(+n.end+i):new Date(+a(n)+i):null,n.title=t.title,n.url=t.url,n.allDay=t.allDay,n.className=t.className,n.editable=t.editable,n.color=t.color,n.backgroundColor=t.backgroundColor,n.borderColor=t.borderColor,n.textColor=t.textColor,w(n));w(t),k(W)}function v(t,e){w(t),t.source||(e&&(H.events.push(t),t.source=H),W.push(t)),k(W)}function h(e){if(e){if(!t.isFunction(e)){var n=e+"";e=function(t){return t._id==n}}W=t.grep(W,e,!0);for(var r=0;F.length>r;r++)t.isArray(F[r].events)&&(F[r].events=t.grep(F[r].events,e,!0))}else{W=[];for(var r=0;F.length>r;r++)t.isArray(F[r].events)&&(F[r].events=[])}k(W)}function g(e){return t.isFunction(e)?t.grep(W,e):e?(e+="",t.grep(W,function(t){return t._id==e})):W}function m(){z++||T("loading",null,!0,x())}function y(){--z||T("loading",null,!1,x())}function w(t){var r=t.source||{},a=X(r.ignoreTimezone,n.ignoreTimezone);t._id=t._id||(t.id===e?"_fc"+xe++:t.id+""),t.date&&(t.start||(t.start=t.date),delete t.date),t._start=d(t.start=p(t.start,a)),t.end=p(t.end,a),t.end&&t.end<=t.start&&(t.end=null),t._end=t.end?d(t.end):null,t.allDay===e&&(t.allDay=X(r.allDayDefault,n.allDayDefault)),t.className?"string"==typeof t.className&&(t.className=t.className.split(/\s+/)):t.className=[]}function b(t){t.className?"string"==typeof t.className&&(t.className=t.className.split(/\s+/)):t.className=[];for(var e=Ee.sourceNormalizers,n=0;e.length>n;n++)e[n](t)}function D(t,e){return t&&e&&C(t)==C(e)}function C(t){return("object"==typeof t?t.events||t.url:"")||t}var M=this;M.isFetchNeeded=a,M.fetchEvents=o,M.addEventSource=l,M.removeEventSource=u,M.updateEvent=f,M.renderEvent=v,M.removeEvents=h,M.clientEvents=g,M.normalizeEvent=w;for(var E,S,T=M.trigger,x=M.getView,k=M.reportEvents,H={events:[]},F=[H],R=0,N=0,z=0,W=[],A=0;r.length>A;A++)c(r[A])}function i(t,e,n){return t.setFullYear(t.getFullYear()+e),n||f(t),t}function s(t,e,n){if(+t){var r=t.getMonth()+e,a=d(t);for(a.setDate(1),a.setMonth(r),t.setMonth(r),n||f(t);t.getMonth()!=a.getMonth();)t.setDate(t.getDate()+(a>t?1:-1))}return t}function l(t,e,n){if(+t){var r=t.getDate()+e,a=d(t);a.setHours(9),a.setDate(r),t.setDate(r),n||f(t),c(t,a)}return t}function c(t,e){if(+t)for(;t.getDate()!=e.getDate();)t.setTime(+t+(e>t?1:-1)*Fe)}function u(t,e){return t.setMinutes(t.getMinutes()+e),t}function f(t){return t.setHours(0),t.setMinutes(0),t.setSeconds(0),t.setMilliseconds(0),t}function d(t,e){return e?f(new Date(+t)):new Date(+t)}function v(){var t,e=0;do t=new Date(1970,e++,1);while(t.getHours());return t}function h(t,e){return Math.round((d(t,!0)-d(e,!0))/He)}function g(t,n,r,a){n!==e&&n!=t.getFullYear()&&(t.setDate(1),t.setMonth(0),t.setFullYear(n)),r!==e&&r!=t.getMonth()&&(t.setDate(1),t.setMonth(r)),a!==e&&t.setDate(a)}function p(t,n){return"object"==typeof t?t:"number"==typeof t?new Date(1e3*t):"string"==typeof t?t.match(/^\d+(\.\d+)?$/)?new Date(1e3*parseFloat(t)):(n===e&&(n=!0),m(t,n)||(t?new Date(t):null)):null}function m(t,e){var n=t.match(/^([0-9]{4})(-([0-9]{2})(-([0-9]{2})([T ]([0-9]{2}):([0-9]{2})(:([0-9]{2})(\.([0-9]+))?)?(Z|(([-+])([0-9]{2})(:?([0-9]{2}))?))?)?)?)?$/);if(!n)return null;var r=new Date(n[1],0,1);if(e||!n[13]){var a=new Date(n[1],0,1,9,0);n[3]&&(r.setMonth(n[3]-1),a.setMonth(n[3]-1)),n[5]&&(r.setDate(n[5]),a.setDate(n[5])),c(r,a),n[7]&&r.setHours(n[7]),n[8]&&r.setMinutes(n[8]),n[10]&&r.setSeconds(n[10]),n[12]&&r.setMilliseconds(1e3*Number("0."+n[12])),c(r,a)}else if(r.setUTCFullYear(n[1],n[3]?n[3]-1:0,n[5]||1),r.setUTCHours(n[7]||0,n[8]||0,n[10]||0,n[12]?1e3*Number("0."+n[12]):0),n[14]){var o=60*Number(n[16])+(n[18]?Number(n[18]):0);o*="-"==n[15]?1:-1,r=new Date(+r+1e3*60*o)}return r}function y(t){if("number"==typeof t)return 60*t;if("object"==typeof t)return 60*t.getHours()+t.getMinutes();var e=t.match(/(\d+)(?::(\d+))?\s*(\w+)?/);if(e){var n=parseInt(e[1],10);return e[3]&&(n%=12,"p"==e[3].toLowerCase().charAt(0)&&(n+=12)),60*n+(e[2]?parseInt(e[2],10):0)}}function w(t,e,n){return b(t,null,e,n)}function b(t,e,n,r){r=r||Ce;var a,o,i,s,l=t,c=e,u=n.length,f="";for(a=0;u>a;a++)if(o=n.charAt(a),"'"==o){for(i=a+1;u>i;i++)if("'"==n.charAt(i)){l&&(f+=i==a+1?"'":n.substring(a+1,i),a=i);break}}else if("("==o){for(i=a+1;u>i;i++)if(")"==n.charAt(i)){var d=w(l,n.substring(a+1,i),r);parseInt(d.replace(/\D/,""),10)&&(f+=d),a=i;break}}else if("["==o){for(i=a+1;u>i;i++)if("]"==n.charAt(i)){var v=n.substring(a+1,i),d=w(l,v,r);d!=w(c,v,r)&&(f+=d),a=i;break}}else if("{"==o)l=e,c=t;else if("}"==o)l=t,c=e;else{for(i=u;i>a;i--)if(s=Ne[n.substring(a,i)]){l&&(f+=s(l,r)),a=i-1;break}i==a&&l&&(f+=o)}return f}function D(t){var e,n=new Date(t.getTime());return n.setDate(n.getDate()+4-(n.getDay()||7)),e=n.getTime(),n.setMonth(0),n.setDate(1),Math.floor(Math.round((e-n)/864e5)/7)+1}function C(t){return t.end?M(t.end,t.allDay):l(d(t.start),1)}function M(t,e){return t=d(t),e||t.getHours()||t.getMinutes()?l(t,1):f(t)}function E(n,r,a){n.unbind("mouseover").mouseover(function(n){for(var o,i,s,l=n.target;l!=this;)o=l,l=l.parentNode;(i=o._fci)!==e&&(o._fci=e,s=r[i],a(s.event,s.element,s),t(n.target).trigger(n)),n.stopPropagation()})}function S(e,n,r){for(var a,o=0;e.length>o;o++)a=t(e[o]),a.width(Math.max(0,n-x(a,r)))}function T(e,n,r){for(var a,o=0;e.length>o;o++)a=t(e[o]),a.height(Math.max(0,n-R(a,r)))}function x(t,e){return k(t)+F(t)+(e?H(t):0)}function k(e){return(parseFloat(t.css(e[0],"paddingLeft",!0))||0)+(parseFloat(t.css(e[0],"paddingRight",!0))||0)}function H(e){return(parseFloat(t.css(e[0],"marginLeft",!0))||0)+(parseFloat(t.css(e[0],"marginRight",!0))||0)}function F(e){return(parseFloat(t.css(e[0],"borderLeftWidth",!0))||0)+(parseFloat(t.css(e[0],"borderRightWidth",!0))||0)}function R(t,e){return N(t)+W(t)+(e?z(t):0)}function N(e){return(parseFloat(t.css(e[0],"paddingTop",!0))||0)+(parseFloat(t.css(e[0],"paddingBottom",!0))||0)}function z(e){return(parseFloat(t.css(e[0],"marginTop",!0))||0)+(parseFloat(t.css(e[0],"marginBottom",!0))||0)}function W(e){return(parseFloat(t.css(e[0],"borderTopWidth",!0))||0)+(parseFloat(t.css(e[0],"borderBottomWidth",!0))||0)}function A(){}function O(t,e){return t-e}function L(t){return Math.max.apply(Math,t)}function _(t){return(10>t?"0":"")+t}function P(t,n){if(t[n]!==e)return t[n];for(var r,a=n.split(/(?=[A-Z])/),o=a.length-1;o>=0;o--)if(r=t[a[o].toLowerCase()],r!==e)return r;return t[""]}function q(t){return t.replace(/&/g,"&").replace(//g,">").replace(/'/g,"'").replace(/"/g,""").replace(/\n/g,"
")}function Y(t){t.attr("unselectable","on").css("MozUserSelect","none").bind("selectstart.ui",function(){return!1})}function B(t){t.children().removeClass("fc-first fc-last").filter(":first-child").addClass("fc-first").end().filter(":last-child").addClass("fc-last")}function j(t,e){var n=t.source||{},r=t.color,a=n.color,o=e("eventColor"),i=t.backgroundColor||r||n.backgroundColor||a||e("eventBackgroundColor")||o,s=t.borderColor||r||n.borderColor||a||e("eventBorderColor")||o,l=t.textColor||n.textColor||e("eventTextColor"),c=[];return i&&c.push("background-color:"+i),s&&c.push("border-color:"+s),l&&c.push("color:"+l),c.join(";")}function I(e,n,r){if(t.isFunction(e)&&(e=[e]),e){var a,o;for(a=0;e.length>a;a++)o=e[a].apply(n,r)||o;return o}}function X(){for(var t=0;arguments.length>t;t++)if(arguments[t]!==e)return arguments[t]}function J(t,e){function n(t,e){e&&(s(t,e),t.setDate(1));var n=a("firstDay"),f=d(t,!0);f.setDate(1);var v=s(d(f),1),g=d(f);l(g,-((g.getDay()-n+7)%7)),i(g);var p=d(v);l(p,(7-p.getDay()+n)%7),i(p,-1,!0);var m=c(),y=Math.round(h(p,g)/7);"fixed"==a("weekMode")&&(l(p,7*(6-y)),y=6),r.title=u(f,a("titleFormat")),r.start=f,r.end=v,r.visStart=g,r.visEnd=p,o(y,m,!0)}var r=this;r.render=n,Z.call(r,t,e,"month");var a=r.opt,o=r.renderBasic,i=r.skipHiddenDays,c=r.getCellsPerWeek,u=e.formatDate}function V(t,e){function n(t,e){e&&l(t,7*e);var n=l(d(t),-((t.getDay()-a("firstDay")+7)%7)),u=l(d(n),7),f=d(n);i(f);var v=d(u);i(v,-1,!0);var h=s();r.start=n,r.end=u,r.visStart=f,r.visEnd=v,r.title=c(f,l(d(v),-1),a("titleFormat")),o(1,h,!1)}var r=this;r.render=n,Z.call(r,t,e,"basicWeek");var a=r.opt,o=r.renderBasic,i=r.skipHiddenDays,s=r.getCellsPerWeek,c=e.formatDates}function U(t,e){function n(t,e){e&&l(t,e),i(t,0>e?-1:1);var n=d(t,!0),c=l(d(n),1);r.title=s(t,a("titleFormat")),r.start=r.visStart=n,r.end=r.visEnd=c,o(1,1,!1)}var r=this;r.render=n,Z.call(r,t,e,"basicDay");var a=r.opt,o=r.renderBasic,i=r.skipHiddenDays,s=e.formatDate}function Z(e,n,r){function a(t,e,n){ee=t,ne=e,re=n,o(),j||i(),s()}function o(){le=he("theme")?"ui":"fc",ce=he("columnFormat"),ue=he("weekNumbers"),de=he("weekNumberTitle"),ve="iso"!=he("weekNumberCalculation")?"w":"W"}function i(){Z=t("
").appendTo(e)}function s(){var n=c();L&&L.remove(),L=t(n).appendTo(e),_=L.find("thead"),P=_.find(".fc-day-header"),j=L.find("tbody"),I=j.find("tr"),X=j.find(".fc-day"),J=I.find("td:first-child"),V=I.eq(0).find(".fc-day > div"),U=I.eq(0).find(".fc-day-content > div"),B(_.add(_.find("tr"))),B(I),I.eq(0).addClass("fc-first"),I.filter(":last").addClass("fc-last"),X.each(function(e,n){var r=Ee(Math.floor(e/ne),e%ne);ge("dayRender",O,r,t(n))}),y(X)}function c(){var t=""+u()+v()+"
";return t}function u(){var t,e,n=le+"-widget-header",r="";for(r+="
"+q(de)+""+q(xe(e,ce))+"
"+"
"+q(xe(n,ve))+"
"+"
"+"
",re&&(a+="
"+t.getDate()+"
"),a+="
 
"+""+""+""+"
"+Ue("allDayText")+""+"
"+"
 
",de=t(e).appendTo(ce),ve=de.find("tr"),C(ve.find("td")),ce.append("
"+"
"+"
")):ue=t([]),he=t("
").appendTo(ce),ge=t("
").appendTo(he),be=t("
").appendTo(ge),e="",r=v(),o=u(d(r),je),u(r,Be),Ae=0,a=0;o>r;a++)i=r.getMinutes(),e+=""+""+""+"",u(r,Ue("slotMinutes")),Ae++;e+="
"+(f&&i?" ":on(r,Ue("axisFormat")))+""+"
 
"+"
",Ce=t(e).appendTo(ge),M(Ce.find("td"))}function c(){var e=h();K&&K.remove(),K=t(e).appendTo(n),ee=K.find("thead"),ne=ee.find("th").slice(1,-1),re=K.find("tbody"),ae=re.find("td").slice(0,-1),oe=ae.find("> div"),ie=ae.find(".fc-day-content > div"),se=ae.eq(0),le=oe.eq(0),B(ee.add(ee.find("tr"))),B(re.add(re.find("tr")))}function h(){var t=""+g()+p()+"
";return t}function g(){var t,e,n,r=qe+"-widget-header",a="";for(a+="",Xe?(t=nn(0,0),e=on(t,Ve),Ye?e+=Je:e=Je+e,a+=""+q(e)+""):a+=" ",n=0;We>n;n++)t=nn(0,n),a+=""+q(on(t,Ie))+"";return a+=" "+""+""}function p(){var t,e,n,r,a,o=qe+"-widget-header",i=qe+"-widget-content",s=f(new Date),l="";for(l+=" ",n="",e=0;We>e;e++)t=nn(0,e),a=["fc-col"+e,"fc-"+ke[t.getDay()],i],+t==+s?a.push(qe+"-state-highlight","fc-today"):s>t?a.push("fc-past"):a.push("fc-future"),r=""+"
"+"
"+"
 
"+"
"+"
"+"",n+=r;return l+=n,l+=" "+""+""}function m(t){t===e&&(t=Se),Se=t,sn={};var n=re.position().top,r=he.position().top,a=Math.min(t-n,Ce.height()+r+1);le.height(a-R(se)),ce.css("top",n),he.height(a-r-1),Fe=Ce.find("tr:first").height()+1,Ne=Ue("slotMinutes")/Re,ze=Fe/Ne}function w(e){Ee=e,_e.clear(),Pe.clear();var n=ee.find("th:first");de&&(n=n.add(de.find("th:first"))),n=n.add(Ce.find("th:first")),Te=0,S(n.width("").each(function(e,n){Te=Math.max(Te,t(n).outerWidth())}),Te);var r=K.find(".fc-agenda-gutter");de&&(r=r.add(de.find("th.fc-agenda-gutter")));var a=he[0].clientWidth;He=he.width()-a,He?(S(r,He),r.show().prev().removeClass("fc-last")):r.hide().prev().addClass("fc-last"),xe=Math.floor((a-Te)/We),S(ne.slice(0,-1),xe)}function b(){function t(){he.scrollTop(r)}var e=v(),n=d(e);n.setHours(Ue("firstHour"));var r=_(e,n)+1;t(),setTimeout(t,0)}function D(){b()}function C(t){t.click(E).mousedown(tn)}function M(t){t.click(E).mousedown(U)}function E(t){if(!Ue("selectable")){var e=Math.min(We-1,Math.floor((t.pageX-K.offset().left-Te)/xe)),n=nn(0,e),r=this.parentNode.className.match(/fc-slot(\d+)/);if(r){var a=parseInt(r[1])*Ue("slotMinutes"),o=Math.floor(a/60);n.setHours(o),n.setMinutes(a%60+Be),Ze("dayClick",ae[e],n,!1,t)}else Ze("dayClick",ae[e],n,!0,t)}}function x(t,e,n){n&&Oe.build();for(var r=an(t,e),a=0;r.length>a;a++){var o=r[a];C(k(o.row,o.leftCol,o.row,o.rightCol))}}function k(t,e,n,r){var a=Oe.rect(t,e,n,r,ce);return Ge(a,ce)}function H(t,e){for(var n=0;We>n;n++){var r=nn(0,n),a=l(d(r),1),o=new Date(Math.max(r,t)),i=new Date(Math.min(a,e));if(i>o){var s=Oe.rect(0,n,0,n,ge),c=_(r,o),u=_(r,i);s.top=c,s.height=u-c,M(Ge(s,ge))}}}function F(t){return _e.left(t)}function N(t){return Pe.left(t)}function z(t){return _e.right(t)}function W(t){return Pe.right(t)}function A(t){return Ue("allDaySlot")&&!t.row}function L(t){var e=nn(0,t.col),n=t.row;return Ue("allDaySlot")&&n--,n>=0&&u(e,Be+n*Re),e}function _(t,n){if(t=d(t,!0),u(d(t),Be)>n)return 0;if(n>=u(d(t),je))return Ce.height();var r=Ue("slotMinutes"),a=60*n.getHours()+n.getMinutes()-Be,o=Math.floor(a/r),i=sn[o];return i===e&&(i=sn[o]=Ce.find("tr").eq(o).find("td div")[0].offsetTop),Math.max(0,Math.round(i-1+Fe*(a%r/r)))}function P(){return ve}function j(t){var e=d(t.start);return t.allDay?e:u(e,Ue("defaultEventMinutes"))}function I(t,e){return e?d(t):u(d(t),Ue("slotMinutes"))}function X(t,e,n){n?Ue("allDaySlot")&&x(t,l(d(e),1),!0):J(t,e)}function J(e,n){var r=Ue("selectHelper");if(Oe.build(),r){var a=rn(e).col;if(a>=0&&We>a){var o=Oe.rect(0,a,0,a,ge),i=_(e,e),s=_(e,n);if(s>i){if(o.top=i,o.height=s-i,o.left+=2,o.width-=5,t.isFunction(r)){var l=r(e,n);l&&(o.position="absolute",Me=t(l).css(o).appendTo(ge))}else o.isStart=!0,o.isEnd=!0,Me=t(en({title:"",start:e,end:n,className:["fc-select-helper"],editable:!1},o)),Me.css("opacity",Ue("dragOpacity"));Me&&(M(Me),ge.append(Me),S(Me,o.width,!0),T(Me,o.height,!0))}}}else H(e,n)}function V(){$e(),Me&&(Me.remove(),Me=null)}function U(e){if(1==e.which&&Ue("selectable")){Ke(e);var n;Le.start(function(t,e){if(V(),t&&t.col==e.col&&!A(t)){var r=L(e),a=L(t);n=[r,u(d(r),Re),a,u(d(a),Re)].sort(O),J(n[0],n[3])}else n=null},e),t(document).one("mouseup",function(t){Le.stop(),n&&(+n[0]==+n[1]&&Z(n[0],!1,t),Qe(n[0],n[3],!1,t))})}}function Z(t,e,n){Ze("dayClick",ae[rn(t).col],t,e,n)}function G(t,e){Le.start(function(t){if($e(),t)if(A(t))k(t.row,t.col,t.row,t.col);else{var e=L(t),n=u(d(e),Ue("defaultEventMinutes"));H(e,n)}},e)}function $(t,e,n){var r=Le.stop();$e(),r&&Ze("drop",t,L(r),A(r),e,n)}var Q=this;Q.renderAgenda=o,Q.setWidth=w,Q.setHeight=m,Q.afterRender=D,Q.defaultEventEnd=j,Q.timePosition=_,Q.getIsCellAllDay=A,Q.allDayRow=P,Q.getCoordinateGrid=function(){return Oe},Q.getHoverListener=function(){return Le},Q.colLeft=F,Q.colRight=z,Q.colContentLeft=N,Q.colContentRight=W,Q.getDaySegmentContainer=function(){return ue},Q.getSlotSegmentContainer=function(){return be},Q.getMinMinute=function(){return Be},Q.getMaxMinute=function(){return je},Q.getSlotContainer=function(){return ge},Q.getRowCnt=function(){return 1},Q.getColCnt=function(){return We},Q.getColWidth=function(){return xe},Q.getSnapHeight=function(){return ze},Q.getSnapMinutes=function(){return Re},Q.defaultSelectionEnd=I,Q.renderDayOverlay=x,Q.renderSelection=X,Q.clearSelection=V,Q.reportDayClick=Z,Q.dragStart=G,Q.dragStop=$,fe.call(Q,n,r,a),me.call(Q),pe.call(Q),te.call(Q);var K,ee,ne,re,ae,oe,ie,se,le,ce,ue,de,ve,he,ge,be,Ce,Me,Ee,Se,Te,xe,He,Fe,Re,Ne,ze,We,Ae,Oe,Le,_e,Pe,qe,Ye,Be,je,Ie,Xe,Je,Ve,Ue=Q.opt,Ze=Q.trigger,Ge=Q.renderOverlay,$e=Q.clearOverlays,Qe=Q.reportSelection,Ke=Q.unselect,tn=Q.daySelectionMousedown,en=Q.slotSegHtml,nn=Q.cellToDate,rn=Q.dateToCell,an=Q.rangeToSegments,on=r.formatDate,sn={};Y(n.addClass("fc-agenda")),Oe=new ye(function(e,n){function r(t){return Math.max(l,Math.min(c,t))}var a,o,i;ne.each(function(e,r){a=t(r),o=a.offset().left,e&&(i[1]=o),i=[o],n[e]=i}),i[1]=o+a.outerWidth(),Ue("allDaySlot")&&(a=ve,o=a.offset().top,e[0]=[o,o+a.outerHeight()]);for(var s=ge.offset().top,l=he.offset().top,c=l+he.outerHeight(),u=0;Ae*Ne>u;u++)e.push([r(s+ze*u),r(s+ze*(u+1))])}),Le=new we(Oe),_e=new De(function(t){return oe.eq(t)}),Pe=new De(function(t){return ie.eq(t)})}function te(){function n(t,e){var n,r=t.length,o=[],i=[];for(n=0;r>n;n++)t[n].allDay?o.push(t[n]):i.push(t[n]);y("allDaySlot")&&(te(o,e),k()),s(a(i),e)}function r(){H().empty(),F().empty()}function a(e){var n,r,a,s,l,c=Y(),f=W(),v=z(),h=t.map(e,i),g=[];for(r=0;c>r;r++)for(n=P(0,r),u(n,f),l=o(e,h,n,u(d(n),v-f)),l=ee(l),a=0;l.length>a;a++)s=l[a],s.col=r,g.push(s);return g}function o(t,e,n,r){var a,o,i,s,l,c,u,f,v=[],h=t.length;for(a=0;h>a;a++)o=t[a],i=o.start,s=e[a],s>n&&r>i&&(n>i?(l=d(n),u=!1):(l=i,u=!0),s>r?(c=d(r),f=!1):(c=s,f=!0),v.push({event:o,start:l,end:c,isStart:u,isEnd:f}));return v.sort(ue)}function i(t){return t.end?d(t.end):u(d(t.start),y("defaultEventMinutes"))}function s(n,r){var a,o,i,s,l,u,d,v,h,g,p,m,b,D,C,M,S=n.length,T="",k=F(),H=y("isRTL");for(a=0;S>a;a++)o=n[a],i=o.event,s=A(o.start,o.start),l=A(o.start,o.end),u=L(o.col),d=_(o.col),v=d-u,d-=.025*v,v=d-u,h=v*(o.forwardCoord-o.backwardCoord),y("slotEventOverlap")&&(h=Math.max(2*(h-10),h)),H?(p=d-o.backwardCoord*v,g=p-h):(g=u+o.backwardCoord*v,p=g+h),g=Math.max(g,u),p=Math.min(p,d),h=p-g,o.top=s,o.left=g,o.outerWidth=h,o.outerHeight=l-s,T+=c(i,o);for(k[0].innerHTML=T,m=k.children(),a=0;S>a;a++)o=n[a],i=o.event,b=t(m[a]),D=w("eventRender",i,i,b),D===!1?b.remove():(D&&D!==!0&&(b.remove(),b=t(D).css({position:"absolute",top:o.top,left:o.left}).appendTo(k)),o.element=b,i._id===r?f(i,b,o):b[0]._fci=a,V(i,b));for(E(k,n,f),a=0;S>a;a++)o=n[a],(b=o.element)&&(o.vsides=R(b,!0),o.hsides=x(b,!0),C=b.find(".fc-event-title"),C.length&&(o.contentTop=C[0].offsetTop));for(a=0;S>a;a++)o=n[a],(b=o.element)&&(b[0].style.width=Math.max(0,o.outerWidth-o.hsides)+"px",M=Math.max(0,o.outerHeight-o.vsides),b[0].style.height=M+"px",i=o.event,o.contentTop!==e&&10>M-o.contentTop&&(b.find("div.fc-event-time").text(re(i.start,y("timeFormat"))+" - "+i.title),b.find("div.fc-event-title").remove()),w("eventAfterRender",i,i,b))}function c(t,e){var n="<",r=t.url,a=j(t,y),o=["fc-event","fc-event-vert"];return b(t)&&o.push("fc-event-draggable"),e.isStart&&o.push("fc-event-start"),e.isEnd&&o.push("fc-event-end"),o=o.concat(t.className),t.source&&(o=o.concat(t.source.className||[])),n+=r?"a href='"+q(t.url)+"'":"div",n+=" class='"+o.join(" ")+"'"+" style="+"'"+"position:absolute;"+"top:"+e.top+"px;"+"left:"+e.left+"px;"+a+"'"+">"+"
"+"
"+q(ae(t.start,t.end,y("timeFormat")))+"
"+"
"+q(t.title||"")+"
"+"
"+"
",e.isEnd&&D(t)&&(n+="
=
"),n+=""}function f(t,e,n){var r=e.find("div.fc-event-time");b(t)&&g(t,e,r),n.isEnd&&D(t)&&p(t,e,r),S(t,e)}function v(t,e,n){function r(){c||(e.width(a).height("").draggable("option","grid",null),c=!0)}var a,o,i,s=n.isStart,c=!0,u=N(),f=B(),v=I(),g=X(),p=W();e.draggable({opacity:y("dragOpacity","month"),revertDuration:y("dragRevertDuration"),start:function(n,p){w("eventDragStart",e,t,n,p),Z(t,e),a=e.width(),u.start(function(n,a){if(K(),n){o=!1;var u=P(0,a.col),p=P(0,n.col);i=h(p,u),n.row?s?c&&(e.width(f-10),T(e,v*Math.round((t.end?(t.end-t.start)/Re:y("defaultEventMinutes"))/g)),e.draggable("option","grid",[f,1]),c=!1):o=!0:(Q(l(d(t.start),i),l(C(t),i)),r()),o=o||c&&!i -}else r(),o=!0;e.draggable("option","revert",o)},n,"drag")},stop:function(n,a){if(u.stop(),K(),w("eventDragStop",e,t,n,a),o)r(),e.css("filter",""),U(t,e);else{var s=0;c||(s=Math.round((e.offset().top-J().offset().top)/v)*g+p-(60*t.start.getHours()+t.start.getMinutes())),G(this,t,i,s,c,n,a)}}})}function g(t,e,n){function r(){K(),s&&(f?(n.hide(),e.draggable("option","grid",null),Q(l(d(t.start),b),l(C(t),b))):(a(D),n.css("display",""),e.draggable("option","grid",[T,x])))}function a(e){var r,a=u(d(t.start),e);t.end&&(r=u(d(t.end),e)),n.text(ae(a,r,y("timeFormat")))}var o,i,s,c,f,v,g,p,b,D,M,E=m.getCoordinateGrid(),S=Y(),T=B(),x=I(),k=X();e.draggable({scroll:!1,grid:[T,x],axis:1==S?"y":!1,opacity:y("dragOpacity"),revertDuration:y("dragRevertDuration"),start:function(n,r){w("eventDragStart",e,t,n,r),Z(t,e),E.build(),o=e.position(),i=E.cell(n.pageX,n.pageY),s=c=!0,f=v=O(i),g=p=0,b=0,D=M=0},drag:function(t,n){var a=E.cell(t.pageX,t.pageY);if(s=!!a){if(f=O(a),g=Math.round((n.position.left-o.left)/T),g!=p){var l=P(0,i.col),u=i.col+g;u=Math.max(0,u),u=Math.min(S-1,u);var d=P(0,u);b=h(d,l)}f||(D=Math.round((n.position.top-o.top)/x)*k)}(s!=c||f!=v||g!=p||D!=M)&&(r(),c=s,v=f,p=g,M=D),e.draggable("option","revert",!s)},stop:function(n,a){K(),w("eventDragStop",e,t,n,a),s&&(f||b||D)?G(this,t,b,f?0:D,f,n,a):(s=!0,f=!1,g=0,b=0,D=0,r(),e.css("filter",""),e.css(o),U(t,e))}})}function p(t,e,n){var r,a,o=I(),i=X();e.resizable({handles:{s:".ui-resizable-handle"},grid:o,start:function(n,o){r=a=0,Z(t,e),w("eventResizeStart",this,t,n,o)},resize:function(s,l){r=Math.round((Math.max(o,e.height())-l.originalSize.height)/o),r!=a&&(n.text(ae(t.start,r||t.end?u(M(t),i*r):null,y("timeFormat"))),a=r)},stop:function(n,a){w("eventResizeStop",this,t,n,a),r?$(this,t,0,i*r,n,a):U(t,e)}})}var m=this;m.renderEvents=n,m.clearEvents=r,m.slotSegHtml=c,de.call(m);var y=m.opt,w=m.trigger,b=m.isEventDraggable,D=m.isEventResizable,M=m.eventEnd,S=m.eventElementHandlers,k=m.setHeight,H=m.getDaySegmentContainer,F=m.getSlotSegmentContainer,N=m.getHoverListener,z=m.getMaxMinute,W=m.getMinMinute,A=m.timePosition,O=m.getIsCellAllDay,L=m.colContentLeft,_=m.colContentRight,P=m.cellToDate,Y=m.getColCnt,B=m.getColWidth,I=m.getSnapHeight,X=m.getSnapMinutes,J=m.getSlotContainer,V=m.reportEventElement,U=m.showEvents,Z=m.hideEvents,G=m.eventDrop,$=m.eventResize,Q=m.renderDayOverlay,K=m.clearOverlays,te=m.renderDayEvents,ne=m.calendar,re=ne.formatDate,ae=ne.formatDates;m.draggableDayEvent=v}function ee(t){var e,n=ne(t),r=n[0];if(re(n),r){for(e=0;r.length>e;e++)ae(r[e]);for(e=0;r.length>e;e++)oe(r[e],0,0)}return ie(n)}function ne(t){var e,n,r,a=[];for(e=0;t.length>e;e++){for(n=t[e],r=0;a.length>r&&se(n,a[r]).length;r++);(a[r]||(a[r]=[])).push(n)}return a}function re(t){var e,n,r,a,o;for(e=0;t.length>e;e++)for(n=t[e],r=0;n.length>r;r++)for(a=n[r],a.forwardSegs=[],o=e+1;t.length>o;o++)se(a,t[o],a.forwardSegs)}function ae(t){var n,r,a=t.forwardSegs,o=0;if(t.forwardPressure===e){for(n=0;a.length>n;n++)r=a[n],ae(r),o=Math.max(o,1+r.forwardPressure);t.forwardPressure=o}}function oe(t,n,r){var a,o=t.forwardSegs;if(t.forwardCoord===e)for(o.length?(o.sort(ce),oe(o[0],n+1,r),t.forwardCoord=o[0].backwardCoord):t.forwardCoord=1,t.backwardCoord=t.forwardCoord-(t.forwardCoord-r)/(n+1),a=0;o.length>a;a++)oe(o[a],0,t.forwardCoord)}function ie(t){var e,n,r,a=[];for(e=0;t.length>e;e++)for(n=t[e],r=0;n.length>r;r++)a.push(n[r]);return a}function se(t,e,n){n=n||[];for(var r=0;e.length>r;r++)le(t,e[r])&&n.push(e[r]);return n}function le(t,e){return t.end>e.start&&t.starte;e++)n=t[e],j[n._id]?j[n._id].push(n):j[n._id]=[n]}function v(){j={},I={},J=[]}function g(t){return t.end?d(t.end):q(t)}function p(t,e){J.push({event:t,element:e}),I[t._id]?I[t._id].push(e):I[t._id]=[e]}function m(){t.each(J,function(t,e){_.trigger("eventDestroy",e.event,e.event,e.element)})}function y(t,n){n.click(function(r){return n.hasClass("ui-draggable-dragging")||n.hasClass("ui-resizable-resizing")?e:i("eventClick",this,t,r)}).hover(function(e){i("eventMouseover",this,t,e)},function(e){i("eventMouseout",this,t,e)})}function w(t,e){D(t,e,"show")}function b(t,e){D(t,e,"hide")}function D(t,e,n){var r,a=I[t._id],o=a.length;for(r=0;o>r;r++)e&&a[r][0]==e[0]||a[r][n]()}function C(t,e,n,r,a,o,s){var l=e.allDay,c=e._id;E(j[c],n,r,a),i("eventDrop",t,e,n,r,a,function(){E(j[c],-n,-r,l),B(c)},o,s),B(c)}function M(t,e,n,r,a,o){var s=e._id;S(j[s],n,r),i("eventResize",t,e,n,r,function(){S(j[s],-n,-r),B(s)},a,o),B(s)}function E(t,n,r,a){r=r||0;for(var o,i=t.length,s=0;i>s;s++)o=t[s],a!==e&&(o.allDay=a),u(l(o.start,n,!0),r),o.end&&(o.end=u(l(o.end,n,!0),r)),Y(o,V)}function S(t,e,n){n=n||0;for(var r,a=t.length,o=0;a>o;o++)r=t[o],r.end=u(l(g(r),e,!0),n),Y(r,V)}function T(t){return"object"==typeof t&&(t=t.getDay()),G[t]}function x(){return U}function k(t,e,n){for(e=e||1;G[(t.getDay()+(n?e:0)+7)%7];)l(t,e)}function H(){var t=F.apply(null,arguments),e=R(t),n=N(e);return n}function F(t,e){var n=_.getColCnt(),r=K?-1:1,a=K?n-1:0;"object"==typeof t&&(e=t.col,t=t.row);var o=t*n+(e*r+a);return o}function R(t){var e=_.visStart.getDay();return t+=$[e],7*Math.floor(t/U)+Q[(t%U+U)%U]-e}function N(t){var e=d(_.visStart);return l(e,t),e}function z(t){var e=W(t),n=A(e),r=O(n);return r}function W(t){return h(t,_.visStart)}function A(t){var e=_.visStart.getDay();return t+=e,Math.floor(t/7)*U+$[(t%7+7)%7]-$[e]}function O(t){var e=_.getColCnt(),n=K?-1:1,r=K?e-1:0,a=Math.floor(t/e),o=(t%e+e)%e*n+r;return{row:a,col:o}}function L(t,e){for(var n=_.getRowCnt(),r=_.getColCnt(),a=[],o=W(t),i=W(e),s=A(o),l=A(i)-1,c=0;n>c;c++){var u=c*r,f=u+r-1,d=Math.max(s,u),v=Math.min(l,f);if(v>=d){var h=O(d),g=O(v),p=[h.col,g.col].sort(),m=R(d)==o,y=R(v)+1==i;a.push({row:c,leftCol:p[0],rightCol:p[1],isStart:m,isEnd:y})}}return a}var _=this;_.element=n,_.calendar=r,_.name=a,_.opt=o,_.trigger=i,_.isEventDraggable=s,_.isEventResizable=c,_.setEventData=f,_.clearEventData=v,_.eventEnd=g,_.reportEventElement=p,_.triggerEventDestroy=m,_.eventElementHandlers=y,_.showEvents=w,_.hideEvents=b,_.eventDrop=C,_.eventResize=M;var q=_.defaultEventEnd,Y=r.normalizeEvent,B=r.reportEventChange,j={},I={},J=[],V=r.options;_.isHiddenDay=T,_.skipHiddenDays=k,_.getCellsPerWeek=x,_.dateToCell=z,_.dateToDayOffset=W,_.dayOffsetToCellOffset=A,_.cellOffsetToCell=O,_.cellToDate=H,_.cellToCellOffset=F,_.cellOffsetToDayOffset=R,_.dayOffsetToDate=N,_.rangeToSegments=L;var U,Z=o("hiddenDays")||[],G=[],$=[],Q=[],K=o("isRTL");(function(){o("weekends")===!1&&Z.push(0,6);for(var e=0,n=0;7>e;e++)$[e]=n,G[e]=-1!=t.inArray(e,Z),G[e]||(Q[n]=e,n++);if(U=n,!U)throw"invalid hiddenDays"})()}function de(){function e(t,e){var n=r(t,!1,!0);he(n,function(t,e){N(t.event,e)}),w(n,e),he(n,function(t,e){k("eventAfterRender",t.event,t.event,e)})}function n(t,e,n){var a=r([t],!0,!1),o=[];return he(a,function(t,r){t.row===e&&r.css("top",n),o.push(r[0])}),o}function r(e,n,r){var o,l,c=Z(),d=n?t("
"):c,v=a(e);return i(v),o=s(v),d[0].innerHTML=o,l=d.children(),n&&c.append(l),u(v,l),he(v,function(t,e){t.hsides=x(e,!0)}),he(v,function(t,e){e.width(Math.max(0,t.outerWidth-t.hsides))}),he(v,function(t,e){t.outerHeight=e.outerHeight(!0)}),f(v,r),v}function a(t){for(var e=[],n=0;t.length>n;n++){var r=o(t[n]);e.push.apply(e,r)}return e}function o(t){for(var e=t.start,n=C(t),r=ee(e,n),a=0;r.length>a;a++)r[a].event=t;return r}function i(t){for(var e=T("isRTL"),n=0;t.length>n;n++){var r=t[n],a=(e?r.isEnd:r.isStart)?V:X,o=(e?r.isStart:r.isEnd)?U:J,i=a(r.leftCol),s=o(r.rightCol);r.left=i,r.outerWidth=s-i}}function s(t){for(var e="",n=0;t.length>n;n++)e+=c(t[n]);return e}function c(t){var e="",n=T("isRTL"),r=t.event,a=r.url,o=["fc-event","fc-event-hori"];H(r)&&o.push("fc-event-draggable"),t.isStart&&o.push("fc-event-start"),t.isEnd&&o.push("fc-event-end"),o=o.concat(r.className),r.source&&(o=o.concat(r.source.className||[]));var i=j(r,T);return e+=a?""+"
",!r.allDay&&t.isStart&&(e+=""+q(G(r.start,r.end,T("timeFormat")))+""),e+=""+q(r.title||"")+""+"
",t.isEnd&&F(r)&&(e+="
"+"   "+"
"),e+=""}function u(e,n){for(var r=0;e.length>r;r++){var a=e[r],o=a.event,i=n.eq(r),s=k("eventRender",o,o,i);s===!1?i.remove():(s&&s!==!0&&(s=t(s).css({position:"absolute",left:a.left}),i.replaceWith(s),i=s),a.element=i)}}function f(t,e){var n=v(t),r=y(),a=[];if(e)for(var o=0;r.length>o;o++)r[o].height(n[o]);for(var o=0;r.length>o;o++)a.push(r[o].position().top);he(t,function(t,e){e.css("top",a[t.row]+t.top)})}function v(t){for(var e=P(),n=B(),r=[],a=g(t),o=0;e>o;o++){for(var i=a[o],s=[],l=0;n>l;l++)s.push(0);for(var c=0;i.length>c;c++){var u=i[c];u.top=L(s.slice(u.leftCol,u.rightCol+1));for(var l=u.leftCol;u.rightCol>=l;l++)s[l]=u.top+u.outerHeight}r.push(L(s))}return r}function g(t){var e,n,r,a=P(),o=[];for(e=0;t.length>e;e++)n=t[e],r=n.row,n.element&&(o[r]?o[r].push(n):o[r]=[n]);for(r=0;a>r;r++)o[r]=p(o[r]||[]);return o}function p(t){for(var e=[],n=m(t),r=0;n.length>r;r++)e.push.apply(e,n[r]);return e}function m(t){t.sort(ge);for(var e=[],n=0;t.length>n;n++){for(var r=t[n],a=0;e.length>a&&ve(r,e[a]);a++);e[a]?e[a].push(r):e[a]=[r]}return e}function y(){var t,e=P(),n=[];for(t=0;e>t;t++)n[t]=I(t).find("div.fc-day-content > div");return n}function w(t,e){var n=Z();he(t,function(t,n,r){var a=t.event;a._id===e?b(a,n,t):n[0]._fci=r}),E(n,t,b)}function b(t,e,n){H(t)&&S.draggableDayEvent(t,e,n),n.isEnd&&F(t)&&S.resizableDayEvent(t,e,n),z(t,e)}function D(t,e){var n,r=te();e.draggable({delay:50,opacity:T("dragOpacity"),revertDuration:T("dragRevertDuration"),start:function(a,o){k("eventDragStart",e,t,a,o),A(t,e),r.start(function(r,a,o,i){if(e.draggable("option","revert",!r||!o&&!i),Q(),r){var s=ne(a),c=ne(r);n=h(c,s),$(l(d(t.start),n),l(C(t),n))}else n=0},a,"drag")},stop:function(a,o){r.stop(),Q(),k("eventDragStop",e,t,a,o),n?O(this,t,n,0,t.allDay,a,o):(e.css("filter",""),W(t,e))}})}function M(e,r,a){var o=T("isRTL"),i=o?"w":"e",s=r.find(".ui-resizable-"+i),c=!1;Y(r),r.mousedown(function(t){t.preventDefault()}).click(function(t){c&&(t.preventDefault(),t.stopImmediatePropagation())}),s.mousedown(function(o){function s(n){k("eventResizeStop",this,e,n),t("body").css("cursor",""),u.stop(),Q(),f&&_(this,e,f,0,n),setTimeout(function(){c=!1},0)}if(1==o.which){c=!0;var u=te();P(),B();var f,d,v=r.css("top"),h=t.extend({},e),g=ie(oe(e.start));K(),t("body").css("cursor",i+"-resize").one("mouseup",s),k("eventResizeStart",this,e,o),u.start(function(r,o){if(r){var s=re(o),c=re(r);if(c=Math.max(c,g),f=ae(c)-ae(s)){h.end=l(R(e),f,!0);var u=d;d=n(h,a.row,v),d=t(d),d.find("*").css("cursor",i+"-resize"),u&&u.remove(),A(e)}else d&&(W(e),d.remove(),d=null);Q(),$(e.start,l(C(e),f))}},o)}})}var S=this;S.renderDayEvents=e,S.draggableDayEvent=D,S.resizableDayEvent=M;var T=S.opt,k=S.trigger,H=S.isEventDraggable,F=S.isEventResizable,R=S.eventEnd,N=S.reportEventElement,z=S.eventElementHandlers,W=S.showEvents,A=S.hideEvents,O=S.eventDrop,_=S.eventResize,P=S.getRowCnt,B=S.getColCnt;S.getColWidth;var I=S.allDayRow,X=S.colLeft,J=S.colRight,V=S.colContentLeft,U=S.colContentRight;S.dateToCell;var Z=S.getDaySegmentContainer,G=S.calendar.formatDates,$=S.renderDayOverlay,Q=S.clearOverlays,K=S.clearSelection,te=S.getHoverListener,ee=S.rangeToSegments,ne=S.cellToDate,re=S.cellToCellOffset,ae=S.cellOffsetToDayOffset,oe=S.dateToDayOffset,ie=S.dayOffsetToCellOffset}function ve(t,e){for(var n=0;e.length>n;n++){var r=e[n];if(r.leftCol<=t.rightCol&&r.rightCol>=t.leftCol)return!0}return!1}function he(t,e){for(var n=0;t.length>n;n++){var r=t[n],a=r.element;a&&e(r,a,n)}}function ge(t,e){return e.rightCol-e.leftCol-(t.rightCol-t.leftCol)||e.event.allDay-t.event.allDay||t.event.start-e.event.start||(t.event.title||"").localeCompare(e.event.title)}function pe(){function e(t,e,a){n(),e||(e=l(t,a)),c(t,e,a),r(t,e,a)}function n(t){f&&(f=!1,u(),s("unselect",null,t))}function r(t,e,n,r){f=!0,s("select",null,t,e,n,r)}function a(e){var a=o.cellToDate,s=o.getIsCellAllDay,l=o.getHoverListener(),f=o.reportDayClick;if(1==e.which&&i("selectable")){n(e);var d;l.start(function(t,e){u(),t&&s(t)?(d=[a(e),a(t)].sort(O),c(d[0],d[1],!0)):d=null},e),t(document).one("mouseup",function(t){l.stop(),d&&(+d[0]==+d[1]&&f(d[0],!0,t),r(d[0],d[1],!0,t))})}}var o=this;o.select=e,o.unselect=n,o.reportSelection=r,o.daySelectionMousedown=a;var i=o.opt,s=o.trigger,l=o.defaultSelectionEnd,c=o.renderSelection,u=o.clearSelection,f=!1;i("selectable")&&i("unselectAuto")&&t(document).mousedown(function(e){var r=i("unselectCancel");r&&t(e.target).parents(r).length||n(e)})}function me(){function e(e,n){var r=o.shift();return r||(r=t("
")),r[0].parentNode!=n[0]&&r.appendTo(n),a.push(r.css(e).show()),r}function n(){for(var t;t=a.shift();)o.push(t.hide().unbind())}var r=this;r.renderOverlay=e,r.clearOverlays=n;var a=[],o=[]}function ye(t){var e,n,r=this;r.build=function(){e=[],n=[],t(e,n)},r.cell=function(t,r){var a,o=e.length,i=n.length,s=-1,l=-1;for(a=0;o>a;a++)if(r>=e[a][0]&&e[a][1]>r){s=a;break}for(a=0;i>a;a++)if(t>=n[a][0]&&n[a][1]>t){l=a;break}return s>=0&&l>=0?{row:s,col:l}:null},r.rect=function(t,r,a,o,i){var s=i.offset();return{top:e[t][0]-s.top,left:n[r][0]-s.left,width:n[o][1]-n[r][0],height:e[a][1]-e[t][0]}}}function we(e){function n(t){be(t);var n=e.cell(t.pageX,t.pageY);(!n!=!i||n&&(n.row!=i.row||n.col!=i.col))&&(n?(o||(o=n),a(n,o,n.row-o.row,n.col-o.col)):a(n,o),i=n)}var r,a,o,i,s=this;s.start=function(s,l,c){a=s,o=i=null,e.build(),n(l),r=c||"mousemove",t(document).bind(r,n)},s.stop=function(){return t(document).unbind(r,n),i}}function be(t){t.pageX===e&&(t.pageX=t.originalEvent.pageX,t.pageY=t.originalEvent.pageY)}function De(t){function n(e){return a[e]=a[e]||t(e)}var r=this,a={},o={},i={};r.left=function(t){return o[t]=o[t]===e?n(t).position().left:o[t]},r.right=function(t){return i[t]=i[t]===e?r.left(t)+n(t).width():i[t]},r.clear=function(){a={},o={},i={}}}var Ce={defaultView:"month",aspectRatio:1.35,header:{left:"title",center:"",right:"today prev,next"},weekends:!0,weekNumbers:!1,weekNumberCalculation:"iso",weekNumberTitle:"W",allDayDefault:!0,ignoreTimezone:!0,lazyFetching:!0,startParam:"start",endParam:"end",titleFormat:{month:"MMMM yyyy",week:"MMM d[ yyyy]{ '—'[ MMM] d yyyy}",day:"dddd, MMM d, yyyy"},columnFormat:{month:"ddd",week:"ddd M/d",day:"dddd M/d"},timeFormat:{"":"h(:mm)t"},isRTL:!1,firstDay:0,monthNames:["January","February","March","April","May","June","July","August","September","October","November","December"],monthNamesShort:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],dayNames:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],dayNamesShort:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],buttonText:{prev:"",next:"",prevYear:"«",nextYear:"»",today:"Heute",month:"Monat",week:"Woche",day:"Tag"},theme:!1,buttonIcons:{prev:"circle-triangle-w",next:"circle-triangle-e"},unselectAuto:!0,dropAccept:"*",handleWindowResize:!0},Me={header:{left:"next,prev today",center:"",right:"title"},buttonText:{prev:"",next:"",prevYear:"»",nextYear:"«"},buttonIcons:{prev:"circle-triangle-e",next:"circle-triangle-w"}},Ee=t.fullCalendar={version:"1.6.4"},Se=Ee.views={};t.fn.fullCalendar=function(n){if("string"==typeof n){var a,o=Array.prototype.slice.call(arguments,1);return this.each(function(){var r=t.data(this,"fullCalendar");if(r&&t.isFunction(r[n])){var i=r[n].apply(r,o);a===e&&(a=i),"destroy"==n&&t.removeData(this,"fullCalendar")}}),a!==e?a:this}n=n||{};var i=n.eventSources||[];return delete n.eventSources,n.events&&(i.push(n.events),delete n.events),n=t.extend(!0,{},Ce,n.isRTL||n.isRTL===e&&Ce.isRTL?Me:{},n),this.each(function(e,a){var o=t(a),s=new r(o,n,i);o.data("fullCalendar",s),s.render()}),this},Ee.sourceNormalizers=[],Ee.sourceFetchers=[];var Te={dataType:"json",cache:!1},xe=1;Ee.addDays=l,Ee.cloneDate=d,Ee.parseDate=p,Ee.parseISO8601=m,Ee.parseTime=y,Ee.formatDate=w,Ee.formatDates=b;var ke=["sun","mon","tue","wed","thu","fri","sat"],He=864e5,Fe=36e5,Re=6e4,Ne={s:function(t){return t.getSeconds()},ss:function(t){return _(t.getSeconds())},m:function(t){return t.getMinutes()},mm:function(t){return _(t.getMinutes())},h:function(t){return t.getHours()%12||12},hh:function(t){return _(t.getHours()%12||12)},H:function(t){return t.getHours()},HH:function(t){return _(t.getHours())},d:function(t){return t.getDate()},dd:function(t){return _(t.getDate())},ddd:function(t,e){return e.dayNamesShort[t.getDay()]},dddd:function(t,e){return e.dayNames[t.getDay()]},M:function(t){return t.getMonth()+1},MM:function(t){return _(t.getMonth()+1)},MMM:function(t,e){return e.monthNamesShort[t.getMonth()]},MMMM:function(t,e){return e.monthNames[t.getMonth()]},yy:function(t){return(t.getFullYear()+"").substring(2)},yyyy:function(t){return t.getFullYear()},t:function(t){return 12>t.getHours()?"a":"p"},tt:function(t){return 12>t.getHours()?"am":"pm"},T:function(t){return 12>t.getHours()?"A":"P"},TT:function(t){return 12>t.getHours()?"AM":"PM"},u:function(t){return w(t,"yyyy-MM-dd'T'HH:mm:ss'Z'")},S:function(t){var e=t.getDate();return e>10&&20>e?"th":["st","nd","rd"][e%10-1]||"th"},w:function(t,e){return e.weekNumberCalculation(t)},W:function(t){return D(t)}};Ee.dateFormatters=Ne,Ee.applyAll=I,Se.month=J,Se.basicWeek=V,Se.basicDay=U,n({weekMode:"fixed"}),Se.agendaWeek=$,Se.agendaDay=Q,n({allDaySlot:!0,allDayText:"all-day",firstHour:6,slotMinutes:30,defaultEventMinutes:120,axisFormat:"h(:mm)tt",timeFormat:{agenda:"h:mm{ - h:mm}"},dragOpacity:{agenda:.5},minTime:0,maxTime:24,slotEventOverlap:!0})})(jQuery); diff --git a/www/plugins/fullcalendar-1.6.4/fullcalendar.print.css b/www/plugins/fullcalendar-1.6.4/fullcalendar.print.css deleted file mode 100644 index 43607199d..000000000 --- a/www/plugins/fullcalendar-1.6.4/fullcalendar.print.css +++ /dev/null @@ -1,32 +0,0 @@ -/*! - * FullCalendar v1.6.4 Print Stylesheet - * Docs & License: http://arshaw.com/fullcalendar/ - * (c) 2013 Adam Shaw - */ - -/* - * Include this stylesheet on your page to get a more printer-friendly calendar. - * When including this stylesheet, use the media='print' attribute of the tag. - * Make sure to include this stylesheet IN ADDITION to the regular fullcalendar.css. - */ - - - /* Events ------------------------------------------------------*/ - -.fc-event { - background: #fff !important; - color: #000 !important; - } - -/* for vertical events */ - -.fc-event-bg { - display: none !important; - } - -.fc-event .ui-resizable-handle { - display: none !important; - } - - diff --git a/www/plugins/fullcalendar-1.6.4/gcal.js b/www/plugins/fullcalendar-1.6.4/gcal.js deleted file mode 100644 index 164422762..000000000 --- a/www/plugins/fullcalendar-1.6.4/gcal.js +++ /dev/null @@ -1,107 +0,0 @@ -/*! - * FullCalendar v1.6.4 Google Calendar Plugin - * Docs & License: http://arshaw.com/fullcalendar/ - * (c) 2013 Adam Shaw - */ - -(function($) { - - -var fc = $.fullCalendar; -var formatDate = fc.formatDate; -var parseISO8601 = fc.parseISO8601; -var addDays = fc.addDays; -var applyAll = fc.applyAll; - - -fc.sourceNormalizers.push(function(sourceOptions) { - if (sourceOptions.dataType == 'gcal' || - sourceOptions.dataType === undefined && - (sourceOptions.url || '').match(/^(http|https):\/\/www.google.com\/calendar\/feeds\//)) { - sourceOptions.dataType = 'gcal'; - if (sourceOptions.editable === undefined) { - sourceOptions.editable = false; - } - } -}); - - -fc.sourceFetchers.push(function(sourceOptions, start, end) { - if (sourceOptions.dataType == 'gcal') { - return transformOptions(sourceOptions, start, end); - } -}); - - -function transformOptions(sourceOptions, start, end) { - - var success = sourceOptions.success; - var data = $.extend({}, sourceOptions.data || {}, { - 'start-min': formatDate(start, 'u'), - 'start-max': formatDate(end, 'u'), - 'singleevents': true, - 'max-results': 9999 - }); - - var ctz = sourceOptions.currentTimezone; - if (ctz) { - data.ctz = ctz = ctz.replace(' ', '_'); - } - - return $.extend({}, sourceOptions, { - url: sourceOptions.url.replace(/\/basic$/, '/full') + '?alt=json-in-script&callback=?', - dataType: 'jsonp', - data: data, - startParam: false, - endParam: false, - success: function(data) { - var events = []; - if (data.feed.entry) { - $.each(data.feed.entry, function(i, entry) { - var startStr = entry['gd$when'][0]['startTime']; - var start = parseISO8601(startStr, true); - var end = parseISO8601(entry['gd$when'][0]['endTime'], true); - var allDay = startStr.indexOf('T') == -1; - var url; - $.each(entry.link, function(i, link) { - if (link.type == 'text/html') { - url = link.href; - if (ctz) { - url += (url.indexOf('?') == -1 ? '?' : '&') + 'ctz=' + ctz; - } - } - }); - if (allDay) { - addDays(end, -1); // make inclusive - } - events.push({ - id: entry['gCal$uid']['value'], - title: entry['title']['$t'], - url: url, - start: start, - end: end, - allDay: allDay, - location: entry['gd$where'][0]['valueString'], - description: entry['content']['$t'] - }); - }); - } - var args = [events].concat(Array.prototype.slice.call(arguments, 1)); - var res = applyAll(success, this, args); - if ($.isArray(res)) { - return res; - } - return events; - } - }); - -} - - -// legacy -fc.gcalFeed = function(url, sourceOptions) { - return $.extend({}, sourceOptions, { url: url, dataType: 'gcal' }); -}; - - -})(jQuery); diff --git a/www/plugins/fullcalendar/fullcalendar.css b/www/plugins/fullcalendar/fullcalendar.css deleted file mode 100644 index 77b9093ef..000000000 --- a/www/plugins/fullcalendar/fullcalendar.css +++ /dev/null @@ -1,616 +0,0 @@ -/* - * FullCalendar v1.5.3 Stylesheet - * - * Copyright (c) 2011 Adam Shaw - * Dual licensed under the MIT and GPL licenses, located in - * MIT-LICENSE.txt and GPL-LICENSE.txt respectively. - * - * Date: Mon Feb 6 22:40:40 2012 -0800 - * - */ - - -.fc { - direction: ltr; - text-align: left; - } - -.fc table { - border-collapse: collapse; - border-spacing: 0; - } - -html .fc, -.fc table { - font-size: 1em; - } - -.fc td, -.fc th { - padding: 0; - vertical-align: top; - } - - - -/* Header -------------------------------------------------------------------------*/ - -.fc-header td { - white-space: nowrap; - } - -.fc-header-left { - width: 25%; - text-align: left; - } - -.fc-header-center { - text-align: center; - } - -.fc-header-right { - width: 25%; - text-align: right; - } - -.fc-header-title { - display: inline-block; - vertical-align: top; - } - -.fc-header-title h2 { - margin-top: 0; - white-space: nowrap; - } - -.fc .fc-header-space { - padding-left: 10px; - } - -.fc-header .fc-button { - margin-bottom: 1em; - vertical-align: top; - } - -/* buttons edges butting together */ - -.fc-header .fc-button { - margin-right: -1px; - } - -.fc-header .fc-corner-right { - margin-right: 1px; /* back to normal */ - } - -.fc-header .ui-corner-right { - margin-right: 0; /* back to normal */ - } - -/* button layering (for border precedence) */ - -.fc-header .fc-state-hover, -.fc-header .ui-state-hover { - z-index: 2; - } - -.fc-header .fc-state-down { - z-index: 3; - } - -.fc-header .fc-state-active, -.fc-header .ui-state-active { - z-index: 4; - } - - - -/* Content -------------------------------------------------------------------------*/ - -.fc-content { - clear: both; - } - -.fc-view { - width: 100%; /* needed for view switching (when view is absolute) */ - overflow: hidden; - } - - - -/* Cell Styles -------------------------------------------------------------------------*/ - -.fc-widget-header, /* , usually */ -.fc-widget-content { /* , usually */ - border: 1px solid #ccc; - } - -.fc-state-highlight { /* today cell */ /* TODO: add .fc-today to */ - background: #ffc; - } - -.fc-cell-overlay { /* semi-transparent rectangle while dragging */ - background: #9cf; - opacity: .2; - filter: alpha(opacity=20); /* for IE */ - } - - - -/* Buttons -------------------------------------------------------------------------*/ - -.fc-button { - position: relative; - display: inline-block; - cursor: pointer; - } - -.fc-state-default { /* non-theme */ - border-style: solid; - border-width: 1px 0; - } - -.fc-button-inner { - position: relative; - float: left; - overflow: hidden; - } - -.fc-state-default .fc-button-inner { /* non-theme */ - border-style: solid; - border-width: 0 1px; - } - -.fc-button-content { - position: relative; - float: left; - height: 1.9em; - line-height: 1.9em; - padding: 0 .6em; - white-space: nowrap; - } - -/* icon (for jquery ui) */ - -.fc-button-content .fc-icon-wrap { - position: relative; - float: left; - top: 50%; - } - -.fc-button-content .ui-icon { - position: relative; - float: left; - margin-top: -50%; - *margin-top: 0; - *top: -50%; - } - -/* gloss effect */ - -.fc-state-default .fc-button-effect { - position: absolute; - top: 50%; - left: 0; - } - -.fc-state-default .fc-button-effect span { - position: absolute; - top: -100px; - left: 0; - width: 500px; - height: 100px; - border-width: 100px 0 0 1px; - border-style: solid; - border-color: #fff; - background: #444; - opacity: .09; - filter: alpha(opacity=9); - } - -/* button states (determines colors) */ - -.fc-state-default, -.fc-state-default .fc-button-inner { - border-style: solid; - border-color: #ccc #bbb #aaa; - background: #F3F3F3; - color: #000; - } - -.fc-state-hover, -.fc-state-hover .fc-button-inner { - border-color: #999; - } - -.fc-state-down, -.fc-state-down .fc-button-inner { - border-color: #555; - background: #777; - } - -.fc-state-active, -.fc-state-active .fc-button-inner { - border-color: #555; - background: #777; - color: #fff; - } - -.fc-state-disabled, -.fc-state-disabled .fc-button-inner { - color: #999; - border-color: #ddd; - } - -.fc-state-disabled { - cursor: default; - } - -.fc-state-disabled .fc-button-effect { - display: none; - } - - - -/* Global Event Styles -------------------------------------------------------------------------*/ - -.fc-event { - border-style: solid; - border-width: 0; - font-size: .85em; - cursor: default; - } - -a.fc-event, -.fc-event-draggable { - cursor: pointer; - } - -a.fc-event { - text-decoration: none; - } - -.fc-rtl .fc-event { - text-align: right; - } - -.fc-event-skin { - border-color: #36c; /* default BORDER color */ - background-color: #36c; /* default BACKGROUND color */ - color: #fff; /* default TEXT color */ - } - -.fc-event-inner { - position: relative; - width: 100%; - height: 100%; - border-style: solid; - border-width: 0; - overflow: hidden; - } - -.fc-event-time, -.fc-event-title { - padding: 0 1px; - } - -.fc .ui-resizable-handle { /*** TODO: don't use ui-resizable anymore, change class ***/ - display: block; - position: absolute; - z-index: 99999; - overflow: hidden; /* hacky spaces (IE6/7) */ - font-size: 300%; /* */ - line-height: 50%; /* */ - } - - - -/* Horizontal Events -------------------------------------------------------------------------*/ - -.fc-event-hori { - border-width: 1px 0; - margin-bottom: 1px; - } - -/* resizable */ - -.fc-event-hori .ui-resizable-e { - top: 0 !important; /* importants override pre jquery ui 1.7 styles */ - right: -3px !important; - width: 7px !important; - height: 100% !important; - cursor: e-resize; - } - -.fc-event-hori .ui-resizable-w { - top: 0 !important; - left: -3px !important; - width: 7px !important; - height: 100% !important; - cursor: w-resize; - } - -.fc-event-hori .ui-resizable-handle { - _padding-bottom: 14px; /* IE6 had 0 height */ - } - - - -/* Fake Rounded Corners (for buttons and events) -------------------------------------------------------------*/ - -.fc-corner-left { - margin-left: 1px; - } - -.fc-corner-left .fc-button-inner, -.fc-corner-left .fc-event-inner { - margin-left: -1px; - } - -.fc-corner-right { - margin-right: 1px; - } - -.fc-corner-right .fc-button-inner, -.fc-corner-right .fc-event-inner { - margin-right: -1px; - } - -.fc-corner-top { - margin-top: 1px; - } - -.fc-corner-top .fc-event-inner { - margin-top: -1px; - } - -.fc-corner-bottom { - margin-bottom: 1px; - } - -.fc-corner-bottom .fc-event-inner { - margin-bottom: -1px; - } - - - -/* Fake Rounded Corners SPECIFICALLY FOR EVENTS ------------------------------------------------------------------*/ - -.fc-corner-left .fc-event-inner { - border-left-width: 1px; - } - -.fc-corner-right .fc-event-inner { - border-right-width: 1px; - } - -.fc-corner-top .fc-event-inner { - border-top-width: 1px; - } - -.fc-corner-bottom .fc-event-inner { - border-bottom-width: 1px; - } - - - -/* Reusable Separate-border Table -------------------------------------------------------------*/ - -table.fc-border-separate { - border-collapse: separate; - } - -.fc-border-separate th, -.fc-border-separate td { - border-width: 1px 0 0 1px; - } - -.fc-border-separate th.fc-last, -.fc-border-separate td.fc-last { - border-right-width: 1px; - } - -.fc-border-separate tr.fc-last th, -.fc-border-separate tr.fc-last td { - border-bottom-width: 1px; - } - -.fc-border-separate tbody tr.fc-first td, -.fc-border-separate tbody tr.fc-first th { - border-top-width: 0; - } - -/* Month View, Basic Week View, Basic Day View -------------------------------------------------------------------------*/ - -.fc-grid th { - text-align: center; - } - -.fc-grid .fc-day-number { - float: right; - padding: 0 2px; - } - -.fc-grid .fc-other-month .fc-day-number { - opacity: 0.3; - filter: alpha(opacity=30); /* for IE */ - /* opacity with small font can sometimes look too faded - might want to set the 'color' property instead - making day-numbers bold also fixes the problem */ - } - -.fc-grid .fc-day-content { - clear: both; - padding: 2px 2px 1px; /* distance between events and day edges */ - } - -/* event styles */ - -.fc-grid .fc-event-time { - font-weight: bold; - } - -/* right-to-left */ - -.fc-rtl .fc-grid .fc-day-number { - float: left; - } - -.fc-rtl .fc-grid .fc-event-time { - float: right; - } - - - -/* Agenda Week View, Agenda Day View -------------------------------------------------------------------------*/ - -.fc-agenda table { - border-collapse: separate; - } - -.fc-agenda-days th { - text-align: center; - } - -.fc-agenda .fc-agenda-axis { - width: 50px; - padding: 0 4px; - vertical-align: middle; - text-align: right; - white-space: nowrap; - font-weight: normal; - } - -.fc-agenda .fc-day-content { - padding: 2px 2px 1px; - } - -/* make axis border take precedence */ - -.fc-agenda-days .fc-agenda-axis { - border-right-width: 1px; - } - -.fc-agenda-days .fc-col0 { - border-left-width: 0; - } - -/* all-day area */ - -.fc-agenda-allday th { - border-width: 0 1px; - } - -.fc-agenda-allday .fc-day-content { - min-height: 34px; /* TODO: doesnt work well in quirksmode */ - _height: 34px; - } - -/* divider (between all-day and slots) */ - -.fc-agenda-divider-inner { - height: 2px; - overflow: hidden; - } - -.fc-widget-header .fc-agenda-divider-inner { - background: #eee; - } - -/* slot rows */ - -.fc-agenda-slots th { - border-width: 1px 1px 0; - } - -.fc-agenda-slots td { - border-width: 1px 0 0; - background: none; - } - -.fc-agenda-slots td div { - height: 20px; - } - -.fc-agenda-slots tr.fc-slot0 th, -.fc-agenda-slots tr.fc-slot0 td { - border-top-width: 0; - } - -.fc-agenda-slots tr.fc-minor th, -.fc-agenda-slots tr.fc-minor td { - border-top-style: dotted; - } - -.fc-agenda-slots tr.fc-minor th.ui-widget-header { - *border-top-style: solid; /* doesn't work with background in IE6/7 */ - } - - - -/* Vertical Events -------------------------------------------------------------------------*/ - -.fc-event-vert { - border-width: 0 1px; - } - -.fc-event-vert .fc-event-head, -.fc-event-vert .fc-event-content { - position: relative; - z-index: 2; - width: 100%; - overflow: hidden; - } - -.fc-event-vert .fc-event-time { - white-space: nowrap; - font-size: 10px; - } - -.fc-event-vert .fc-event-bg { /* makes the event lighter w/ a semi-transparent overlay */ - position: absolute; - z-index: 1; - top: 0; - left: 0; - width: 100%; - height: 100%; - background: #fff; - opacity: .3; - filter: alpha(opacity=30); - } - -.fc .ui-draggable-dragging .fc-event-bg, /* TODO: something nicer like .fc-opacity */ -.fc-select-helper .fc-event-bg { - display: none\9; /* for IE6/7/8. nested opacity filters while dragging don't work */ - } - -/* resizable */ - -.fc-event-vert .ui-resizable-s { - bottom: 0 !important; /* importants override pre jquery ui 1.7 styles */ - width: 100% !important; - height: 8px !important; - overflow: hidden !important; - line-height: 8px !important; - font-size: 11px !important; - font-family: monospace; - text-align: center; - cursor: s-resize; - } - -.fc-agenda .ui-resizable-resizing { /* TODO: better selector */ - _overflow: hidden; - } - - diff --git a/www/plugins/fullcalendar/fullcalendar.js b/www/plugins/fullcalendar/fullcalendar.js deleted file mode 100644 index 7ce847525..000000000 --- a/www/plugins/fullcalendar/fullcalendar.js +++ /dev/null @@ -1,5224 +0,0 @@ -/** - * @preserve - * FullCalendar v1.5.3 - * http://arshaw.com/fullcalendar/ - * - * Use fullcalendar.css for basic styling. - * For event drag & drop, requires jQuery UI draggable. - * For event resizing, requires jQuery UI resizable. - * - * Copyright (c) 2011 Adam Shaw - * Dual licensed under the MIT and GPL licenses, located in - * MIT-LICENSE.txt and GPL-LICENSE.txt respectively. - * - * Date: Mon Feb 6 22:40:40 2012 -0800 - * - */ - -(function($, undefined) { - - -var defaults = { - - // display - defaultView: 'month', - aspectRatio: 1.35, - header: { - left: 'title', - center: '', - right: 'today prev,next' - }, - weekends: true, - - // editing - //editable: false, - //disableDragging: false, - //disableResizing: false, - - allDayDefault: true, - ignoreTimezone: true, - - // event ajax - lazyFetching: true, - startParam: 'start', - endParam: 'end', - - // time formats - titleFormat: { - month: 'MMMM yyyy', - week: "MMM d[ yyyy]{ '—'[ MMM] d yyyy}", - day: 'dddd, MMM d, yyyy' - }, - columnFormat: { - month: 'ddd', - week: 'ddd M/d', - day: 'dddd M/d' - }, - timeFormat: { // for event elements - '': 'h(:mm)t' // default - }, - - // locale - isRTL: false, - firstDay: 0, - monthNames: ['January','February','March','April','May','June','July','August','September','October','November','December'], - monthNamesShort: ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'], - dayNames: ['Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday'], - dayNamesShort: ['Sun','Mon','Tue','Wed','Thu','Fri','Sat'], - buttonText: { - prev: ' ◄ ', - next: ' ► ', - prevYear: ' << ', - nextYear: ' >> ', - today: 'today', - month: 'month', - week: 'week', - day: 'day' - }, - - // jquery-ui theming - theme: false, - buttonIcons: { - prev: 'circle-triangle-w', - next: 'circle-triangle-e' - }, - - //selectable: false, - unselectAuto: true, - - dropAccept: '*' - -}; - -// right-to-left defaults -var rtlDefaults = { - header: { - left: 'next,prev today', - center: '', - right: 'title' - }, - buttonText: { - prev: ' ► ', - next: ' ◄ ', - prevYear: ' >> ', - nextYear: ' << ' - }, - buttonIcons: { - prev: 'circle-triangle-e', - next: 'circle-triangle-w' - } -}; - - - -var fc = $.fullCalendar = { version: "1.5.3" }; -var fcViews = fc.views = {}; - - -$.fn.fullCalendar = function(options) { - - - // method calling - if (typeof options == 'string') { - var args = Array.prototype.slice.call(arguments, 1); - var res; - this.each(function() { - var calendar = $.data(this, 'fullCalendar'); - if (calendar && $.isFunction(calendar[options])) { - var r = calendar[options].apply(calendar, args); - if (res === undefined) { - res = r; - } - if (options == 'destroy') { - $.removeData(this, 'fullCalendar'); - } - } - }); - if (res !== undefined) { - return res; - } - return this; - } - - - // would like to have this logic in EventManager, but needs to happen before options are recursively extended - var eventSources = options.eventSources || []; - delete options.eventSources; - if (options.events) { - eventSources.push(options.events); - delete options.events; - } - - - options = $.extend(true, {}, - defaults, - (options.isRTL || options.isRTL===undefined && defaults.isRTL) ? rtlDefaults : {}, - options - ); - - - this.each(function(i, _element) { - var element = $(_element); - var calendar = new Calendar(element, options, eventSources); - element.data('fullCalendar', calendar); // TODO: look into memory leak implications - calendar.render(); - }); - - - return this; - -}; - - -// function for adding/overriding defaults -function setDefaults(d) { - $.extend(true, defaults, d); -} - - - - -function Calendar(element, options, eventSources) { - var t = this; - - - // exports - t.options = options; - t.render = render; - t.destroy = destroy; - t.refetchEvents = refetchEvents; - t.reportEvents = reportEvents; - t.reportEventChange = reportEventChange; - t.rerenderEvents = rerenderEvents; - t.changeView = changeView; - t.select = select; - t.unselect = unselect; - t.prev = prev; - t.next = next; - t.prevYear = prevYear; - t.nextYear = nextYear; - t.today = today; - t.gotoDate = gotoDate; - t.incrementDate = incrementDate; - t.formatDate = function(format, date) { return formatDate(format, date, options) }; - t.formatDates = function(format, date1, date2) { return formatDates(format, date1, date2, options) }; - t.getDate = getDate; - t.getView = getView; - t.option = option; - t.trigger = trigger; - - - // imports - EventManager.call(t, options, eventSources); - var isFetchNeeded = t.isFetchNeeded; - var fetchEvents = t.fetchEvents; - - - // locals - var _element = element[0]; - var header; - var headerElement; - var content; - var tm; // for making theme classes - var currentView; - var viewInstances = {}; - var elementOuterWidth; - var suggestedViewHeight; - var absoluteViewElement; - var resizeUID = 0; - var ignoreWindowResize = 0; - var date = new Date(); - var events = []; - var _dragElement; - - - - /* Main Rendering - -----------------------------------------------------------------------------*/ - - - setYMD(date, options.year, options.month, options.date); - - - function render(inc) { - if (!content) { - initialRender(); - }else{ - calcSize(); - markSizesDirty(); - markEventsDirty(); - renderView(inc); - } - } - - - function initialRender() { - tm = options.theme ? 'ui' : 'fc'; - element.addClass('fc'); - if (options.isRTL) { - element.addClass('fc-rtl'); - } - if (options.theme) { - element.addClass('ui-widget'); - } - content = $("
") - .prependTo(element); - header = new Header(t, options); - headerElement = header.render(); - if (headerElement) { - element.prepend(headerElement); - } - changeView(options.defaultView); - $(window).resize(windowResize); - // needed for IE in a 0x0 iframe, b/c when it is resized, never triggers a windowResize - if (!bodyVisible()) { - lateRender(); - } - } - - - // called when we know the calendar couldn't be rendered when it was initialized, - // but we think it's ready now - function lateRender() { - setTimeout(function() { // IE7 needs this so dimensions are calculated correctly - if (!currentView.start && bodyVisible()) { // !currentView.start makes sure this never happens more than once - renderView(); - } - },0); - } - - - function destroy() { - $(window).unbind('resize', windowResize); - header.destroy(); - content.remove(); - element.removeClass('fc fc-rtl ui-widget'); - } - - - - function elementVisible() { - return _element.offsetWidth !== 0; - } - - - function bodyVisible() { - return $('body')[0].offsetWidth !== 0; - } - - - - /* View Rendering - -----------------------------------------------------------------------------*/ - - // TODO: improve view switching (still weird transition in IE, and FF has whiteout problem) - - function changeView(newViewName) { - if (!currentView || newViewName != currentView.name) { - ignoreWindowResize++; // because setMinHeight might change the height before render (and subsequently setSize) is reached - - unselect(); - - var oldView = currentView; - var newViewElement; - - if (oldView) { - (oldView.beforeHide || noop)(); // called before changing min-height. if called after, scroll state is reset (in Opera) - setMinHeight(content, content.height()); - oldView.element.hide(); - }else{ - setMinHeight(content, 1); // needs to be 1 (not 0) for IE7, or else view dimensions miscalculated - } - content.css('overflow', 'hidden'); - - currentView = viewInstances[newViewName]; - if (currentView) { - currentView.element.show(); - }else{ - currentView = viewInstances[newViewName] = new fcViews[newViewName]( - newViewElement = absoluteViewElement = - $("
") - .appendTo(content), - t // the calendar object - ); - } - - if (oldView) { - header.deactivateButton(oldView.name); - } - header.activateButton(newViewName); - - renderView(); // after height has been set, will make absoluteViewElement's position=relative, then set to null - - content.css('overflow', ''); - if (oldView) { - setMinHeight(content, 1); - } - - if (!newViewElement) { - (currentView.afterShow || noop)(); // called after setting min-height/overflow, so in final scroll state (for Opera) - } - - ignoreWindowResize--; - } - } - - - - function renderView(inc) { - if (elementVisible()) { - ignoreWindowResize++; // because renderEvents might temporarily change the height before setSize is reached - - unselect(); - - if (suggestedViewHeight === undefined) { - calcSize(); - } - - var forceEventRender = false; - if (!currentView.start || inc || date < currentView.start || date >= currentView.end) { - // view must render an entire new date range (and refetch/render events) - currentView.render(date, inc || 0); // responsible for clearing events - setSize(true); - forceEventRender = true; - } - else if (currentView.sizeDirty) { - // view must resize (and rerender events) - currentView.clearEvents(); - setSize(); - forceEventRender = true; - } - else if (currentView.eventsDirty) { - currentView.clearEvents(); - forceEventRender = true; - } - currentView.sizeDirty = false; - currentView.eventsDirty = false; - updateEvents(forceEventRender); - - elementOuterWidth = element.outerWidth(); - - header.updateTitle(currentView.title); - var today = new Date(); - if (today >= currentView.start && today < currentView.end) { - header.disableButton('today'); - }else{ - header.enableButton('today'); - } - - ignoreWindowResize--; - currentView.trigger('viewDisplay', _element); - } - } - - - - /* Resizing - -----------------------------------------------------------------------------*/ - - - function updateSize() { - markSizesDirty(); - if (elementVisible()) { - calcSize(); - setSize(); - unselect(); - currentView.clearEvents(); - currentView.renderEvents(events); - currentView.sizeDirty = false; - } - } - - - function markSizesDirty() { - $.each(viewInstances, function(i, inst) { - inst.sizeDirty = true; - }); - } - - - function calcSize() { - if (options.contentHeight) { - suggestedViewHeight = options.contentHeight; - } - else if (options.height) { - suggestedViewHeight = options.height - (headerElement ? headerElement.height() : 0) - vsides(content); - } - else { - suggestedViewHeight = Math.round(content.width() / Math.max(options.aspectRatio, .5)); - } - } - - - function setSize(dateChanged) { // todo: dateChanged? - ignoreWindowResize++; - currentView.setHeight(suggestedViewHeight, dateChanged); - if (absoluteViewElement) { - absoluteViewElement.css('position', 'relative'); - absoluteViewElement = null; - } - currentView.setWidth(content.width(), dateChanged); - ignoreWindowResize--; - } - - - function windowResize() { - if (!ignoreWindowResize) { - if (currentView.start) { // view has already been rendered - var uid = ++resizeUID; - setTimeout(function() { // add a delay - if (uid == resizeUID && !ignoreWindowResize && elementVisible()) { - if (elementOuterWidth != (elementOuterWidth = element.outerWidth())) { - ignoreWindowResize++; // in case the windowResize callback changes the height - updateSize(); - currentView.trigger('windowResize', _element); - ignoreWindowResize--; - } - } - }, 200); - }else{ - // calendar must have been initialized in a 0x0 iframe that has just been resized - lateRender(); - } - } - } - - - - /* Event Fetching/Rendering - -----------------------------------------------------------------------------*/ - - - // fetches events if necessary, rerenders events if necessary (or if forced) - function updateEvents(forceRender) { - if (!options.lazyFetching || isFetchNeeded(currentView.visStart, currentView.visEnd)) { - refetchEvents(); - } - else if (forceRender) { - rerenderEvents(); - } - } - - - function refetchEvents() { - fetchEvents(currentView.visStart, currentView.visEnd); // will call reportEvents - } - - - // called when event data arrives - function reportEvents(_events) { - events = _events; - rerenderEvents(); - } - - - // called when a single event's data has been changed - function reportEventChange(eventID) { - rerenderEvents(eventID); - } - - - // attempts to rerenderEvents - function rerenderEvents(modifiedEventID) { - markEventsDirty(); - if (elementVisible()) { - currentView.clearEvents(); - currentView.renderEvents(events, modifiedEventID); - currentView.eventsDirty = false; - } - } - - - function markEventsDirty() { - $.each(viewInstances, function(i, inst) { - inst.eventsDirty = true; - }); - } - - - - /* Selection - -----------------------------------------------------------------------------*/ - - - function select(start, end, allDay) { - currentView.select(start, end, allDay===undefined ? true : allDay); - } - - - function unselect() { // safe to be called before renderView - if (currentView) { - currentView.unselect(); - } - } - - - - /* Date - -----------------------------------------------------------------------------*/ - - - function prev() { - renderView(-1); - } - - - function next() { - renderView(1); - } - - - function prevYear() { - addYears(date, -1); - renderView(); - } - - - function nextYear() { - addYears(date, 1); - renderView(); - } - - - function today() { - date = new Date(); - renderView(); - } - - - function gotoDate(year, month, dateOfMonth) { - if (year instanceof Date) { - date = cloneDate(year); // provided 1 argument, a Date - }else{ - setYMD(date, year, month, dateOfMonth); - } - renderView(); - } - - - function incrementDate(years, months, days) { - if (years !== undefined) { - addYears(date, years); - } - if (months !== undefined) { - addMonths(date, months); - } - if (days !== undefined) { - addDays(date, days); - } - renderView(); - } - - - function getDate() { - return cloneDate(date); - } - - - - /* Misc - -----------------------------------------------------------------------------*/ - - - function getView() { - return currentView; - } - - - function option(name, value) { - if (value === undefined) { - return options[name]; - } - if (name == 'height' || name == 'contentHeight' || name == 'aspectRatio') { - options[name] = value; - updateSize(); - } - } - - - function trigger(name, thisObj) { - if (options[name]) { - return options[name].apply( - thisObj || _element, - Array.prototype.slice.call(arguments, 2) - ); - } - } - - - - /* External Dragging - ------------------------------------------------------------------------*/ - - if (options.droppable) { - $(document) - .bind('dragstart', function(ev, ui) { - var _e = ev.target; - var e = $(_e); - if (!e.parents('.fc').length) { // not already inside a calendar - var accept = options.dropAccept; - if ($.isFunction(accept) ? accept.call(_e, e) : e.is(accept)) { - _dragElement = _e; - currentView.dragStart(_dragElement, ev, ui); - } - } - }) - .bind('dragstop', function(ev, ui) { - if (_dragElement) { - currentView.dragStop(_dragElement, ev, ui); - _dragElement = null; - } - }); - } - - -} - -function Header(calendar, options) { - var t = this; - - - // exports - t.render = render; - t.destroy = destroy; - t.updateTitle = updateTitle; - t.activateButton = activateButton; - t.deactivateButton = deactivateButton; - t.disableButton = disableButton; - t.enableButton = enableButton; - - - // locals - var element = $([]); - var tm; - - - - function render() { - tm = options.theme ? 'ui' : 'fc'; - var sections = options.header; - if (sections) { - element = $("") - .append( - $("") - .append(renderSection('left')) - .append(renderSection('center')) - .append(renderSection('right')) - ); - return element; - } - } - - - function destroy() { - element.remove(); - } - - - function renderSection(position) { - var e = $("" + - ""; - for (i=0; i"; // need fc- for setDayID - } - s += - "" + - "" + - ""; - for (i=0; i"; - for (j=0; j" + // need fc- for setDayID - "
" + - (showNumbers ? - "
" : - '' - ) + - "
" + - "
 
" + - "
" + - "
" + - ""; - } - s += - ""; - } - s += - "
" + - "
"); - var buttonStr = options.header[position]; - if (buttonStr) { - $.each(buttonStr.split(' '), function(i) { - if (i > 0) { - e.append(""); - } - var prevButton; - $.each(this.split(','), function(j, buttonName) { - if (buttonName == 'title') { - e.append("

 

"); - if (prevButton) { - prevButton.addClass(tm + '-corner-right'); - } - prevButton = null; - }else{ - var buttonClick; - if (calendar[buttonName]) { - buttonClick = calendar[buttonName]; // calendar method - } - else if (fcViews[buttonName]) { - buttonClick = function() { - button.removeClass(tm + '-state-hover'); // forget why - calendar.changeView(buttonName); - }; - } - if (buttonClick) { - var icon = options.theme ? smartProperty(options.buttonIcons, buttonName) : null; // why are we using smartProperty here? - var text = smartProperty(options.buttonText, buttonName); // why are we using smartProperty here? - var button = $( - "" + - "" + - "" + - (icon ? - "" + - "" + - "" : - text - ) + - "" + - "" + - "" + - "" - ); - if (button) { - button - .click(function() { - if (!button.hasClass(tm + '-state-disabled')) { - buttonClick(); - } - }) - .mousedown(function() { - button - .not('.' + tm + '-state-active') - .not('.' + tm + '-state-disabled') - .addClass(tm + '-state-down'); - }) - .mouseup(function() { - button.removeClass(tm + '-state-down'); - }) - .hover( - function() { - button - .not('.' + tm + '-state-active') - .not('.' + tm + '-state-disabled') - .addClass(tm + '-state-hover'); - }, - function() { - button - .removeClass(tm + '-state-hover') - .removeClass(tm + '-state-down'); - } - ) - .appendTo(e); - if (!prevButton) { - button.addClass(tm + '-corner-left'); - } - prevButton = button; - } - } - } - }); - if (prevButton) { - prevButton.addClass(tm + '-corner-right'); - } - }); - } - return e; - } - - - function updateTitle(html) { - element.find('h2') - .html(html); - } - - - function activateButton(buttonName) { - element.find('span.fc-button-' + buttonName) - .addClass(tm + '-state-active'); - } - - - function deactivateButton(buttonName) { - element.find('span.fc-button-' + buttonName) - .removeClass(tm + '-state-active'); - } - - - function disableButton(buttonName) { - element.find('span.fc-button-' + buttonName) - .addClass(tm + '-state-disabled'); - } - - - function enableButton(buttonName) { - element.find('span.fc-button-' + buttonName) - .removeClass(tm + '-state-disabled'); - } - - -} - -fc.sourceNormalizers = []; -fc.sourceFetchers = []; - -var ajaxDefaults = { - dataType: 'json', - cache: false -}; - -var eventGUID = 1; - - -function EventManager(options, _sources) { - var t = this; - - - // exports - t.isFetchNeeded = isFetchNeeded; - t.fetchEvents = fetchEvents; - t.addEventSource = addEventSource; - t.removeEventSource = removeEventSource; - t.updateEvent = updateEvent; - t.renderEvent = renderEvent; - t.removeEvents = removeEvents; - t.clientEvents = clientEvents; - t.normalizeEvent = normalizeEvent; - - - // imports - var trigger = t.trigger; - var getView = t.getView; - var reportEvents = t.reportEvents; - - - // locals - var stickySource = { events: [] }; - var sources = [ stickySource ]; - var rangeStart, rangeEnd; - var currentFetchID = 0; - var pendingSourceCnt = 0; - var loadingLevel = 0; - var cache = []; - - - for (var i=0; i<_sources.length; i++) { - _addEventSource(_sources[i]); - } - - - - /* Fetching - -----------------------------------------------------------------------------*/ - - - function isFetchNeeded(start, end) { - return !rangeStart || start < rangeStart || end > rangeEnd; - } - - - function fetchEvents(start, end) { - rangeStart = start; - rangeEnd = end; - cache = []; - var fetchID = ++currentFetchID; - var len = sources.length; - pendingSourceCnt = len; - for (var i=0; i)), return null instead - return null; -} - - -function parseISO8601(s, ignoreTimezone) { // ignoreTimezone defaults to false - // derived from http://delete.me.uk/2005/03/iso8601.html - // TODO: for a know glitch/feature, read tests/issue_206_parseDate_dst.html - var m = s.match(/^([0-9]{4})(-([0-9]{2})(-([0-9]{2})([T ]([0-9]{2}):([0-9]{2})(:([0-9]{2})(\.([0-9]+))?)?(Z|(([-+])([0-9]{2})(:?([0-9]{2}))?))?)?)?)?$/); - if (!m) { - return null; - } - var date = new Date(m[1], 0, 1); - if (ignoreTimezone || !m[13]) { - var check = new Date(m[1], 0, 1, 9, 0); - if (m[3]) { - date.setMonth(m[3] - 1); - check.setMonth(m[3] - 1); - } - if (m[5]) { - date.setDate(m[5]); - check.setDate(m[5]); - } - fixDate(date, check); - if (m[7]) { - date.setHours(m[7]); - } - if (m[8]) { - date.setMinutes(m[8]); - } - if (m[10]) { - date.setSeconds(m[10]); - } - if (m[12]) { - date.setMilliseconds(Number("0." + m[12]) * 1000); - } - fixDate(date, check); - }else{ - date.setUTCFullYear( - m[1], - m[3] ? m[3] - 1 : 0, - m[5] || 1 - ); - date.setUTCHours( - m[7] || 0, - m[8] || 0, - m[10] || 0, - m[12] ? Number("0." + m[12]) * 1000 : 0 - ); - if (m[14]) { - var offset = Number(m[16]) * 60 + (m[18] ? Number(m[18]) : 0); - offset *= m[15] == '-' ? 1 : -1; - date = new Date(+date + (offset * 60 * 1000)); - } - } - return date; -} - - -function parseTime(s) { // returns minutes since start of day - if (typeof s == 'number') { // an hour - return s * 60; - } - if (typeof s == 'object') { // a Date object - return s.getHours() * 60 + s.getMinutes(); - } - var m = s.match(/(\d+)(?::(\d+))?\s*(\w+)?/); - if (m) { - var h = parseInt(m[1], 10); - if (m[3]) { - h %= 12; - if (m[3].toLowerCase().charAt(0) == 'p') { - h += 12; - } - } - return h * 60 + (m[2] ? parseInt(m[2], 10) : 0); - } -} - - - -/* Date Formatting ------------------------------------------------------------------------------*/ -// TODO: use same function formatDate(date, [date2], format, [options]) - - -function formatDate(date, format, options) { - return formatDates(date, null, format, options); -} - - -function formatDates(date1, date2, format, options) { - options = options || defaults; - var date = date1, - otherDate = date2, - i, len = format.length, c, - i2, formatter, - res = ''; - for (i=0; ii; i2--) { - if (formatter = dateFormatters[format.substring(i, i2)]) { - if (date) { - res += formatter(date, options); - } - i = i2 - 1; - break; - } - } - if (i2 == i) { - if (date) { - res += c; - } - } - } - } - return res; -}; - - -var dateFormatters = { - s : function(d) { return d.getSeconds() }, - ss : function(d) { return zeroPad(d.getSeconds()) }, - m : function(d) { return d.getMinutes() }, - mm : function(d) { return zeroPad(d.getMinutes()) }, - h : function(d) { return d.getHours() % 12 || 12 }, - hh : function(d) { return zeroPad(d.getHours() % 12 || 12) }, - H : function(d) { return d.getHours() }, - HH : function(d) { return zeroPad(d.getHours()) }, - d : function(d) { return d.getDate() }, - dd : function(d) { return zeroPad(d.getDate()) }, - ddd : function(d,o) { return o.dayNamesShort[d.getDay()] }, - dddd: function(d,o) { return o.dayNames[d.getDay()] }, - M : function(d) { return d.getMonth() + 1 }, - MM : function(d) { return zeroPad(d.getMonth() + 1) }, - MMM : function(d,o) { return o.monthNamesShort[d.getMonth()] }, - MMMM: function(d,o) { return o.monthNames[d.getMonth()] }, - yy : function(d) { return (d.getFullYear()+'').substring(2) }, - yyyy: function(d) { return d.getFullYear() }, - t : function(d) { return d.getHours() < 12 ? 'a' : 'p' }, - tt : function(d) { return d.getHours() < 12 ? 'am' : 'pm' }, - T : function(d) { return d.getHours() < 12 ? 'A' : 'P' }, - TT : function(d) { return d.getHours() < 12 ? 'AM' : 'PM' }, - u : function(d) { return formatDate(d, "yyyy-MM-dd'T'HH:mm:ss'Z'") }, - S : function(d) { - var date = d.getDate(); - if (date > 10 && date < 20) { - return 'th'; - } - return ['st', 'nd', 'rd'][date%10-1] || 'th'; - } -}; - - - -fc.applyAll = applyAll; - - -/* Event Date Math ------------------------------------------------------------------------------*/ - - -function exclEndDay(event) { - if (event.end) { - return _exclEndDay(event.end, event.allDay); - }else{ - return addDays(cloneDate(event.start), 1); - } -} - - -function _exclEndDay(end, allDay) { - end = cloneDate(end); - return allDay || end.getHours() || end.getMinutes() ? addDays(end, 1) : clearTime(end); -} - - -function segCmp(a, b) { - return (b.msLength - a.msLength) * 100 + (a.event.start - b.event.start); -} - - -function segsCollide(seg1, seg2) { - return seg1.end > seg2.start && seg1.start < seg2.end; -} - - - -/* Event Sorting ------------------------------------------------------------------------------*/ - - -// event rendering utilities -function sliceSegs(events, visEventEnds, start, end) { - var segs = [], - i, len=events.length, event, - eventStart, eventEnd, - segStart, segEnd, - isStart, isEnd; - for (i=0; i start && eventStart < end) { - if (eventStart < start) { - segStart = cloneDate(start); - isStart = false; - }else{ - segStart = eventStart; - isStart = true; - } - if (eventEnd > end) { - segEnd = cloneDate(end); - isEnd = false; - }else{ - segEnd = eventEnd; - isEnd = true; - } - segs.push({ - event: event, - start: segStart, - end: segEnd, - isStart: isStart, - isEnd: isEnd, - msLength: segEnd - segStart - }); - } - } - return segs.sort(segCmp); -} - - -// event rendering calculation utilities -function stackSegs(segs) { - var levels = [], - i, len = segs.length, seg, - j, collide, k; - for (i=0; i=0; i--) { - res = obj[parts[i].toLowerCase()]; - if (res !== undefined) { - return res; - } - } - return obj['']; -} - - -function htmlEscape(s) { - return s.replace(/&/g, '&') - .replace(//g, '>') - .replace(/'/g, ''') - .replace(/"/g, '"') - .replace(/\n/g, '
'); -} - - -function cssKey(_element) { - return _element.id + '/' + _element.className + '/' + _element.style.cssText.replace(/(^|;)\s*(top|left|width|height)\s*:[^;]*/ig, ''); -} - - -function disableTextSelection(element) { - element - .attr('unselectable', 'on') - .css('MozUserSelect', 'none') - .bind('selectstart.ui', function() { return false; }); -} - - -/* -function enableTextSelection(element) { - element - .attr('unselectable', 'off') - .css('MozUserSelect', '') - .unbind('selectstart.ui'); -} -*/ - - -function markFirstLast(e) { - e.children() - .removeClass('fc-first fc-last') - .filter(':first-child') - .addClass('fc-first') - .end() - .filter(':last-child') - .addClass('fc-last'); -} - - -function setDayID(cell, date) { - cell.each(function(i, _cell) { - _cell.className = _cell.className.replace(/^fc-\w*/, 'fc-' + dayIDs[date.getDay()]); - // TODO: make a way that doesn't rely on order of classes - }); -} - - -function getSkinCss(event, opt) { - var source = event.source || {}; - var eventColor = event.color; - var sourceColor = source.color; - var optionColor = opt('eventColor'); - var backgroundColor = - event.backgroundColor || - eventColor || - source.backgroundColor || - sourceColor || - opt('eventBackgroundColor') || - optionColor; - var borderColor = - event.borderColor || - eventColor || - source.borderColor || - sourceColor || - opt('eventBorderColor') || - optionColor; - var textColor = - event.textColor || - source.textColor || - opt('eventTextColor'); - var statements = []; - if (backgroundColor) { - statements.push('background-color:' + backgroundColor); - } - if (borderColor) { - statements.push('border-color:' + borderColor); - } - if (textColor) { - statements.push('color:' + textColor); - } - return statements.join(';'); -} - - -function applyAll(functions, thisObj, args) { - if ($.isFunction(functions)) { - functions = [ functions ]; - } - if (functions) { - var i; - var ret; - for (i=0; i" + - "
"; - table = $(s).appendTo(element); - - head = table.find('thead'); - headCells = head.find('th'); - body = table.find('tbody'); - bodyRows = body.find('tr'); - bodyCells = body.find('td'); - bodyFirstCells = bodyCells.filter(':first-child'); - bodyCellTopInners = bodyRows.eq(0).find('div.fc-day-content div'); - - markFirstLast(head.add(head.find('tr'))); // marks first+last tr/th's - markFirstLast(bodyRows); // marks first+last td's - bodyRows.eq(0).addClass('fc-first'); // fc-last is done in updateCells - - dayBind(bodyCells); - - daySegmentContainer = - $("
") - .appendTo(element); - } - - - - function updateCells(firstTime) { - var dowDirty = firstTime || rowCnt == 1; // could the cells' day-of-weeks need updating? - var month = t.start.getMonth(); - var today = clearTime(new Date()); - var cell; - var date; - var row; - - if (dowDirty) { - headCells.each(function(i, _cell) { - cell = $(_cell); - date = indexDate(i); - cell.html(formatDate(date, colFormat)); - setDayID(cell, date); - }); - } - - bodyCells.each(function(i, _cell) { - cell = $(_cell); - date = indexDate(i); - if (date.getMonth() == month) { - cell.removeClass('fc-other-month'); - }else{ - cell.addClass('fc-other-month'); - } - if (+date == +today) { - cell.addClass(tm + '-state-highlight fc-today'); - }else{ - cell.removeClass(tm + '-state-highlight fc-today'); - } - cell.find('div.fc-day-number').text(date.getDate()); - if (dowDirty) { - setDayID(cell, date); - } - }); - - bodyRows.each(function(i, _row) { - row = $(_row); - if (i < rowCnt) { - row.show(); - if (i == rowCnt-1) { - row.addClass('fc-last'); - }else{ - row.removeClass('fc-last'); - } - }else{ - row.hide(); - } - }); - } - - - - function setHeight(height) { - viewHeight = height; - - var bodyHeight = viewHeight - head.height(); - var rowHeight; - var rowHeightLast; - var cell; - - if (opt('weekMode') == 'variable') { - rowHeight = rowHeightLast = Math.floor(bodyHeight / (rowCnt==1 ? 2 : 6)); - }else{ - rowHeight = Math.floor(bodyHeight / rowCnt); - rowHeightLast = bodyHeight - rowHeight * (rowCnt-1); - } - - bodyFirstCells.each(function(i, _cell) { - if (i < rowCnt) { - cell = $(_cell); - setMinHeight( - cell.find('> div'), - (i==rowCnt-1 ? rowHeightLast : rowHeight) - vsides(cell) - ); - } - }); - - } - - - function setWidth(width) { - viewWidth = width; - colContentPositions.clear(); - colWidth = Math.floor(viewWidth / colCnt); - setOuterWidth(headCells.slice(0, -1), colWidth); - } - - - - /* Day clicking and binding - -----------------------------------------------------------*/ - - - function dayBind(days) { - days.click(dayClick) - .mousedown(daySelectionMousedown); - } - - - function dayClick(ev) { - if (!opt('selectable')) { // if selectable, SelectionManager will worry about dayClick - var index = parseInt(this.className.match(/fc\-day(\d+)/)[1]); // TODO: maybe use .data - var date = indexDate(index); - trigger('dayClick', this, date, true, ev); - } - } - - - - /* Semi-transparent Overlay Helpers - ------------------------------------------------------*/ - - - function renderDayOverlay(overlayStart, overlayEnd, refreshCoordinateGrid) { // overlayEnd is exclusive - if (refreshCoordinateGrid) { - coordinateGrid.build(); - } - var rowStart = cloneDate(t.visStart); - var rowEnd = addDays(cloneDate(rowStart), colCnt); - for (var i=0; i" + - "" + - "" + - " "; - for (i=0; i"; // fc- needed for setDayID - } - s += - " " + - "" + - "" + - "" + - "" + - " "; - for (i=0; i" + // fc- needed for setDayID - "
" + - "
" + - "
 
" + - "
" + - "
" + - ""; - } - s += - " " + - "" + - "" + - ""; - dayTable = $(s).appendTo(element); - dayHead = dayTable.find('thead'); - dayHeadCells = dayHead.find('th').slice(1, -1); - dayBody = dayTable.find('tbody'); - dayBodyCells = dayBody.find('td').slice(0, -1); - dayBodyCellInners = dayBodyCells.find('div.fc-day-content div'); - dayBodyFirstCell = dayBodyCells.eq(0); - dayBodyFirstCellStretcher = dayBodyFirstCell.find('> div'); - - markFirstLast(dayHead.add(dayHead.find('tr'))); - markFirstLast(dayBody.add(dayBody.find('tr'))); - - axisFirstCells = dayHead.find('th:first'); - gutterCells = dayTable.find('.fc-agenda-gutter'); - - slotLayer = - $("
") - .appendTo(element); - - if (opt('allDaySlot')) { - - daySegmentContainer = - $("
") - .appendTo(slotLayer); - - s = - "" + - "" + - "" + - "" + - "" + - "" + - "
" + opt('allDayText') + "" + - "
" + - "
 
"; - allDayTable = $(s).appendTo(slotLayer); - allDayRow = allDayTable.find('tr'); - - dayBind(allDayRow.find('td')); - - axisFirstCells = axisFirstCells.add(allDayTable.find('th:first')); - gutterCells = gutterCells.add(allDayTable.find('th.fc-agenda-gutter')); - - slotLayer.append( - "
" + - "
" + - "
" - ); - - }else{ - - daySegmentContainer = $([]); // in jQuery 1.4, we can just do $() - - } - - slotScroller = - $("
") - .appendTo(slotLayer); - - slotContent = - $("
") - .appendTo(slotScroller); - - slotSegmentContainer = - $("
") - .appendTo(slotContent); - - s = - "" + - ""; - d = zeroDate(); - maxd = addMinutes(cloneDate(d), maxMinute); - addMinutes(d, minMinute); - slotCnt = 0; - for (i=0; d < maxd; i++) { - minutes = d.getMinutes(); - s += - "" + - "" + - "" + - ""; - addMinutes(d, opt('slotMinutes')); - slotCnt++; - } - s += - "" + - "
" + - ((!slotNormal || !minutes) ? formatDate(d, opt('axisFormat')) : ' ') + - "" + - "
 
" + - "
"; - slotTable = $(s).appendTo(slotContent); - slotTableFirstInner = slotTable.find('div:first'); - - slotBind(slotTable.find('td')); - - axisFirstCells = axisFirstCells.add(slotTable.find('th:first')); - } - - - - function updateCells() { - var i; - var headCell; - var bodyCell; - var date; - var today = clearTime(new Date()); - for (i=0; i= 0) { - addMinutes(d, minMinute + slotIndex * opt('slotMinutes')); - } - return d; - } - - - function colDate(col) { // returns dates with 00:00:00 - return addDays(cloneDate(t.visStart), col*dis+dit); - } - - - function cellIsAllDay(cell) { - return opt('allDaySlot') && !cell.row; - } - - - function dayOfWeekCol(dayOfWeek) { - return ((dayOfWeek - Math.max(firstDay, nwe) + colCnt) % colCnt)*dis+dit; - } - - - - - // get the Y coordinate of the given time on the given day (both Date objects) - function timePosition(day, time) { // both date objects. day holds 00:00 of current day - day = cloneDate(day, true); - if (time < addMinutes(cloneDate(day), minMinute)) { - return 0; - } - if (time >= addMinutes(cloneDate(day), maxMinute)) { - return slotTable.height(); - } - var slotMinutes = opt('slotMinutes'), - minutes = time.getHours()*60 + time.getMinutes() - minMinute, - slotI = Math.floor(minutes / slotMinutes), - slotTop = slotTopCache[slotI]; - if (slotTop === undefined) { - slotTop = slotTopCache[slotI] = slotTable.find('tr:eq(' + slotI + ') td div')[0].offsetTop; //.position().top; // need this optimization??? - } - return Math.max(0, Math.round( - slotTop - 1 + slotHeight * ((minutes % slotMinutes) / slotMinutes) - )); - } - - - function allDayBounds() { - return { - left: axisWidth, - right: viewWidth - gutterWidth - } - } - - - function getAllDayRow(index) { - return allDayRow; - } - - - function defaultEventEnd(event) { - var start = cloneDate(event.start); - if (event.allDay) { - return start; - } - return addMinutes(start, opt('defaultEventMinutes')); - } - - - - /* Selection - ---------------------------------------------------------------------------------*/ - - - function defaultSelectionEnd(startDate, allDay) { - if (allDay) { - return cloneDate(startDate); - } - return addMinutes(cloneDate(startDate), opt('slotMinutes')); - } - - - function renderSelection(startDate, endDate, allDay) { // only for all-day - if (allDay) { - if (opt('allDaySlot')) { - renderDayOverlay(startDate, addDays(cloneDate(endDate), 1), true); - } - }else{ - renderSlotSelection(startDate, endDate); - } - } - - - function renderSlotSelection(startDate, endDate) { - var helperOption = opt('selectHelper'); - coordinateGrid.build(); - if (helperOption) { - var col = dayDiff(startDate, t.visStart) * dis + dit; - if (col >= 0 && col < colCnt) { // only works when times are on same day - var rect = coordinateGrid.rect(0, col, 0, col, slotContent); // only for horizontal coords - var top = timePosition(startDate, startDate); - var bottom = timePosition(startDate, endDate); - if (bottom > top) { // protect against selections that are entirely before or after visible range - rect.top = top; - rect.height = bottom - top; - rect.left += 2; - rect.width -= 5; - if ($.isFunction(helperOption)) { - var helperRes = helperOption(startDate, endDate); - if (helperRes) { - rect.position = 'absolute'; - rect.zIndex = 8; - selectionHelper = $(helperRes) - .css(rect) - .appendTo(slotContent); - } - }else{ - rect.isStart = true; // conside rect a "seg" now - rect.isEnd = true; // - selectionHelper = $(slotSegHtml( - { - title: '', - start: startDate, - end: endDate, - className: ['fc-select-helper'], - editable: false - }, - rect - )); - selectionHelper.css('opacity', opt('dragOpacity')); - } - if (selectionHelper) { - slotBind(selectionHelper); - slotContent.append(selectionHelper); - setOuterWidth(selectionHelper, rect.width, true); // needs to be after appended - setOuterHeight(selectionHelper, rect.height, true); - } - } - } - }else{ - renderSlotOverlay(startDate, endDate); - } - } - - - function clearSelection() { - clearOverlays(); - if (selectionHelper) { - selectionHelper.remove(); - selectionHelper = null; - } - } - - - function slotSelectionMousedown(ev) { - if (ev.which == 1 && opt('selectable')) { // ev.which==1 means left mouse button - unselect(ev); - var dates; - hoverListener.start(function(cell, origCell) { - clearSelection(); - if (cell && cell.col == origCell.col && !cellIsAllDay(cell)) { - var d1 = cellDate(origCell); - var d2 = cellDate(cell); - dates = [ - d1, - addMinutes(cloneDate(d1), opt('slotMinutes')), - d2, - addMinutes(cloneDate(d2), opt('slotMinutes')) - ].sort(cmp); - renderSlotSelection(dates[0], dates[3]); - }else{ - dates = null; - } - }, ev); - $(document).one('mouseup', function(ev) { - hoverListener.stop(); - if (dates) { - if (+dates[0] == +dates[1]) { - reportDayClick(dates[0], false, ev); - } - reportSelection(dates[0], dates[3], false, ev); - } - }); - } - } - - - function reportDayClick(date, allDay, ev) { - trigger('dayClick', dayBodyCells[dayOfWeekCol(date.getDay())], date, allDay, ev); - } - - - - /* External Dragging - --------------------------------------------------------------------------------*/ - - - function dragStart(_dragElement, ev, ui) { - hoverListener.start(function(cell) { - clearOverlays(); - if (cell) { - if (cellIsAllDay(cell)) { - renderCellOverlay(cell.row, cell.col, cell.row, cell.col); - }else{ - var d1 = cellDate(cell); - var d2 = addMinutes(cloneDate(d1), opt('defaultEventMinutes')); - renderSlotOverlay(d1, d2); - } - } - }, ev); - } - - - function dragStop(_dragElement, ev, ui) { - var cell = hoverListener.stop(); - clearOverlays(); - if (cell) { - trigger('drop', _dragElement, cellDate(cell), cellIsAllDay(cell), ev, ui); - } - } - - -} - -function AgendaEventRenderer() { - var t = this; - - - // exports - t.renderEvents = renderEvents; - t.compileDaySegs = compileDaySegs; // for DayEventRenderer - t.clearEvents = clearEvents; - t.slotSegHtml = slotSegHtml; - t.bindDaySeg = bindDaySeg; - - - // imports - DayEventRenderer.call(t); - var opt = t.opt; - var trigger = t.trigger; - //var setOverflowHidden = t.setOverflowHidden; - var isEventDraggable = t.isEventDraggable; - var isEventResizable = t.isEventResizable; - var eventEnd = t.eventEnd; - var reportEvents = t.reportEvents; - var reportEventClear = t.reportEventClear; - var eventElementHandlers = t.eventElementHandlers; - var setHeight = t.setHeight; - var getDaySegmentContainer = t.getDaySegmentContainer; - var getSlotSegmentContainer = t.getSlotSegmentContainer; - var getHoverListener = t.getHoverListener; - var getMaxMinute = t.getMaxMinute; - var getMinMinute = t.getMinMinute; - var timePosition = t.timePosition; - var colContentLeft = t.colContentLeft; - var colContentRight = t.colContentRight; - var renderDaySegs = t.renderDaySegs; - var resizableDayEvent = t.resizableDayEvent; // TODO: streamline binding architecture - var getColCnt = t.getColCnt; - var getColWidth = t.getColWidth; - var getSlotHeight = t.getSlotHeight; - var getBodyContent = t.getBodyContent; - var reportEventElement = t.reportEventElement; - var showEvents = t.showEvents; - var hideEvents = t.hideEvents; - var eventDrop = t.eventDrop; - var eventResize = t.eventResize; - var renderDayOverlay = t.renderDayOverlay; - var clearOverlays = t.clearOverlays; - var calendar = t.calendar; - var formatDate = calendar.formatDate; - var formatDates = calendar.formatDates; - - - - /* Rendering - ----------------------------------------------------------------------------*/ - - - function renderEvents(events, modifiedEventId) { - reportEvents(events); - var i, len=events.length, - dayEvents=[], - slotEvents=[]; - for (i=0; i" + - "
" + - "
" + - "
" + - htmlEscape(formatDates(event.start, event.end, opt('timeFormat'))) + - "
" + - "
" + - "
" + - "
" + - htmlEscape(event.title) + - "
" + - "
" + - "
" + - "
"; // close inner - if (seg.isEnd && isEventResizable(event)) { - html += - "
=
"; - } - html += - ""; - return html; - } - - - function bindDaySeg(event, eventElement, seg) { - if (isEventDraggable(event)) { - draggableDayEvent(event, eventElement, seg.isStart); - } - if (seg.isEnd && isEventResizable(event)) { - resizableDayEvent(event, eventElement, seg); - } - eventElementHandlers(event, eventElement); - // needs to be after, because resizableDayEvent might stopImmediatePropagation on click - } - - - function bindSlotSeg(event, eventElement, seg) { - var timeElement = eventElement.find('div.fc-event-time'); - if (isEventDraggable(event)) { - draggableSlotEvent(event, eventElement, timeElement); - } - if (seg.isEnd && isEventResizable(event)) { - resizableSlotEvent(event, eventElement, timeElement); - } - eventElementHandlers(event, eventElement); - } - - - - /* Dragging - -----------------------------------------------------------------------------------*/ - - - // when event starts out FULL-DAY - - function draggableDayEvent(event, eventElement, isStart) { - var origWidth; - var revert; - var allDay=true; - var dayDelta; - var dis = opt('isRTL') ? -1 : 1; - var hoverListener = getHoverListener(); - var colWidth = getColWidth(); - var slotHeight = getSlotHeight(); - var minMinute = getMinMinute(); - eventElement.draggable({ - zIndex: 9, - opacity: opt('dragOpacity', 'month'), // use whatever the month view was using - revertDuration: opt('dragRevertDuration'), - start: function(ev, ui) { - trigger('eventDragStart', eventElement, event, ev, ui); - hideEvents(event, eventElement); - origWidth = eventElement.width(); - hoverListener.start(function(cell, origCell, rowDelta, colDelta) { - clearOverlays(); - if (cell) { - //setOverflowHidden(true); - revert = false; - dayDelta = colDelta * dis; - if (!cell.row) { - // on full-days - renderDayOverlay( - addDays(cloneDate(event.start), dayDelta), - addDays(exclEndDay(event), dayDelta) - ); - resetElement(); - }else{ - // mouse is over bottom slots - if (isStart) { - if (allDay) { - // convert event to temporary slot-event - eventElement.width(colWidth - 10); // don't use entire width - setOuterHeight( - eventElement, - slotHeight * Math.round( - (event.end ? ((event.end - event.start) / MINUTE_MS) : opt('defaultEventMinutes')) - / opt('slotMinutes') - ) - ); - eventElement.draggable('option', 'grid', [colWidth, 1]); - allDay = false; - } - }else{ - revert = true; - } - } - revert = revert || (allDay && !dayDelta); - }else{ - resetElement(); - //setOverflowHidden(false); - revert = true; - } - eventElement.draggable('option', 'revert', revert); - }, ev, 'drag'); - }, - stop: function(ev, ui) { - hoverListener.stop(); - clearOverlays(); - trigger('eventDragStop', eventElement, event, ev, ui); - if (revert) { - // hasn't moved or is out of bounds (draggable has already reverted) - resetElement(); - eventElement.css('filter', ''); // clear IE opacity side-effects - showEvents(event, eventElement); - }else{ - // changed! - var minuteDelta = 0; - if (!allDay) { - minuteDelta = Math.round((eventElement.offset().top - getBodyContent().offset().top) / slotHeight) - * opt('slotMinutes') - + minMinute - - (event.start.getHours() * 60 + event.start.getMinutes()); - } - eventDrop(this, event, dayDelta, minuteDelta, allDay, ev, ui); - } - //setOverflowHidden(false); - } - }); - function resetElement() { - if (!allDay) { - eventElement - .width(origWidth) - .height('') - .draggable('option', 'grid', null); - allDay = true; - } - } - } - - - // when event starts out IN TIMESLOTS - - function draggableSlotEvent(event, eventElement, timeElement) { - var origPosition; - var allDay=false; - var dayDelta; - var minuteDelta; - var prevMinuteDelta; - var dis = opt('isRTL') ? -1 : 1; - var hoverListener = getHoverListener(); - var colCnt = getColCnt(); - var colWidth = getColWidth(); - var slotHeight = getSlotHeight(); - eventElement.draggable({ - zIndex: 9, - scroll: false, - grid: [colWidth, slotHeight], - axis: colCnt==1 ? 'y' : false, - opacity: opt('dragOpacity'), - revertDuration: opt('dragRevertDuration'), - start: function(ev, ui) { - trigger('eventDragStart', eventElement, event, ev, ui); - hideEvents(event, eventElement); - origPosition = eventElement.position(); - minuteDelta = prevMinuteDelta = 0; - hoverListener.start(function(cell, origCell, rowDelta, colDelta) { - eventElement.draggable('option', 'revert', !cell); - clearOverlays(); - if (cell) { - dayDelta = colDelta * dis; - if (opt('allDaySlot') && !cell.row) { - // over full days - if (!allDay) { - // convert to temporary all-day event - allDay = true; - timeElement.hide(); - eventElement.draggable('option', 'grid', null); - } - renderDayOverlay( - addDays(cloneDate(event.start), dayDelta), - addDays(exclEndDay(event), dayDelta) - ); - }else{ - // on slots - resetElement(); - } - } - }, ev, 'drag'); - }, - drag: function(ev, ui) { - minuteDelta = Math.round((ui.position.top - origPosition.top) / slotHeight) * opt('slotMinutes'); - if (minuteDelta != prevMinuteDelta) { - if (!allDay) { - updateTimeText(minuteDelta); - } - prevMinuteDelta = minuteDelta; - } - }, - stop: function(ev, ui) { - var cell = hoverListener.stop(); - clearOverlays(); - trigger('eventDragStop', eventElement, event, ev, ui); - if (cell && (dayDelta || minuteDelta || allDay)) { - // changed! - eventDrop(this, event, dayDelta, allDay ? 0 : minuteDelta, allDay, ev, ui); - }else{ - // either no change or out-of-bounds (draggable has already reverted) - resetElement(); - eventElement.css('filter', ''); // clear IE opacity side-effects - eventElement.css(origPosition); // sometimes fast drags make event revert to wrong position - updateTimeText(0); - showEvents(event, eventElement); - } - } - }); - function updateTimeText(minuteDelta) { - var newStart = addMinutes(cloneDate(event.start), minuteDelta); - var newEnd; - if (event.end) { - newEnd = addMinutes(cloneDate(event.end), minuteDelta); - } - timeElement.text(formatDates(newStart, newEnd, opt('timeFormat'))); - } - function resetElement() { - // convert back to original slot-event - if (allDay) { - timeElement.css('display', ''); // show() was causing display=inline - eventElement.draggable('option', 'grid', [colWidth, slotHeight]); - allDay = false; - } - } - } - - - - /* Resizing - --------------------------------------------------------------------------------------*/ - - - function resizableSlotEvent(event, eventElement, timeElement) { - var slotDelta, prevSlotDelta; - var slotHeight = getSlotHeight(); - eventElement.resizable({ - handles: { - s: 'div.ui-resizable-s' - }, - grid: slotHeight, - start: function(ev, ui) { - slotDelta = prevSlotDelta = 0; - hideEvents(event, eventElement); - eventElement.css('z-index', 9); - trigger('eventResizeStart', this, event, ev, ui); - }, - resize: function(ev, ui) { - // don't rely on ui.size.height, doesn't take grid into account - slotDelta = Math.round((Math.max(slotHeight, eventElement.height()) - ui.originalSize.height) / slotHeight); - if (slotDelta != prevSlotDelta) { - timeElement.text( - formatDates( - event.start, - (!slotDelta && !event.end) ? null : // no change, so don't display time range - addMinutes(eventEnd(event), opt('slotMinutes')*slotDelta), - opt('timeFormat') - ) - ); - prevSlotDelta = slotDelta; - } - }, - stop: function(ev, ui) { - trigger('eventResizeStop', this, event, ev, ui); - if (slotDelta) { - eventResize(this, event, 0, opt('slotMinutes')*slotDelta, ev, ui); - }else{ - eventElement.css('z-index', 8); - showEvents(event, eventElement); - // BUG: if event was really short, need to put title back in span - } - } - }); - } - - -} - - -function countForwardSegs(levels) { - var i, j, k, level, segForward, segBack; - for (i=levels.length-1; i>0; i--) { - level = levels[i]; - for (j=0; j"); - var elements; - var segmentContainer = getDaySegmentContainer(); - var i; - var segCnt = segs.length; - var element; - tempContainer[0].innerHTML = daySegHTML(segs); // faster than .html() - elements = tempContainer.children(); - segmentContainer.append(elements); - daySegElementResolve(segs, elements); - daySegCalcHSides(segs); - daySegSetWidths(segs); - daySegCalcHeights(segs); - daySegSetTops(segs, getRowTops(getRowDivs())); - elements = []; - for (i=0; i" + - ""; - if (!event.allDay && seg.isStart) { - html += - "" + - htmlEscape(formatDates(event.start, event.end, opt('timeFormat'))) + - ""; - } - html += - "" + htmlEscape(event.title) + "" + - "
"; - if (seg.isEnd && isEventResizable(event)) { - html += - "
" + - "   " + // makes hit area a lot better for IE6/7 - "
"; - } - html += - ""; - seg.left = left; - seg.outerWidth = right - left; - seg.startCol = leftCol; - seg.endCol = rightCol + 1; // needs to be exclusive - } - return html; - } - - - function daySegElementResolve(segs, elements) { // sets seg.element - var i; - var segCnt = segs.length; - var seg; - var event; - var element; - var triggerRes; - for (i=0; i div'); // optimal selector? - } - return rowDivs; - } - - - function getRowTops(rowDivs) { - var i; - var rowCnt = rowDivs.length; - var tops = []; - for (i=0; i selection for IE - element - .mousedown(function(ev) { // prevent native selection for others - ev.preventDefault(); - }) - .click(function(ev) { - if (isResizing) { - ev.preventDefault(); // prevent link from being visited (only method that worked in IE6) - ev.stopImmediatePropagation(); // prevent fullcalendar eventClick handler from being called - // (eventElementHandlers needs to be bound after resizableDayEvent) - } - }); - - handle.mousedown(function(ev) { - if (ev.which != 1) { - return; // needs to be left mouse button - } - isResizing = true; - var hoverListener = t.getHoverListener(); - var rowCnt = getRowCnt(); - var colCnt = getColCnt(); - var dis = rtl ? -1 : 1; - var dit = rtl ? colCnt-1 : 0; - var elementTop = element.css('top'); - var dayDelta; - var helpers; - var eventCopy = $.extend({}, event); - var minCell = dateCell(event.start); - clearSelection(); - $('body') - .css('cursor', direction + '-resize') - .one('mouseup', mouseup); - trigger('eventResizeStart', this, event, ev); - hoverListener.start(function(cell, origCell) { - if (cell) { - var r = Math.max(minCell.row, cell.row); - var c = cell.col; - if (rowCnt == 1) { - r = 0; // hack for all-day area in agenda views - } - if (r == minCell.row) { - if (rtl) { - c = Math.min(minCell.col, c); - }else{ - c = Math.max(minCell.col, c); - } - } - dayDelta = (r*7 + c*dis+dit) - (origCell.row*7 + origCell.col*dis+dit); - var newEnd = addDays(eventEnd(event), dayDelta, true); - if (dayDelta) { - eventCopy.end = newEnd; - var oldHelpers = helpers; - helpers = renderTempDaySegs(compileDaySegs([eventCopy]), seg.row, elementTop); - helpers.find('*').css('cursor', direction + '-resize'); - if (oldHelpers) { - oldHelpers.remove(); - } - hideEvents(event); - }else{ - if (helpers) { - showEvents(event); - helpers.remove(); - helpers = null; - } - } - clearOverlays(); - renderDayOverlay(event.start, addDays(cloneDate(newEnd), 1)); // coordinate grid already rebuild at hoverListener.start - } - }, ev); - - function mouseup(ev) { - trigger('eventResizeStop', this, event, ev); - $('body').css('cursor', ''); - hoverListener.stop(); - clearOverlays(); - if (dayDelta) { - eventResize(this, event, dayDelta, 0, ev); - // event redraw will clear helpers - } - // otherwise, the drag handler already restored the old events - - setTimeout(function() { // make this happen after the element's click event - isResizing = false; - },0); - } - - }); - } - - -} - -//BUG: unselect needs to be triggered when events are dragged+dropped - -function SelectionManager() { - var t = this; - - - // exports - t.select = select; - t.unselect = unselect; - t.reportSelection = reportSelection; - t.daySelectionMousedown = daySelectionMousedown; - - - // imports - var opt = t.opt; - var trigger = t.trigger; - var defaultSelectionEnd = t.defaultSelectionEnd; - var renderSelection = t.renderSelection; - var clearSelection = t.clearSelection; - - - // locals - var selected = false; - - - - // unselectAuto - if (opt('selectable') && opt('unselectAuto')) { - $(document).mousedown(function(ev) { - var ignore = opt('unselectCancel'); - if (ignore) { - if ($(ev.target).parents(ignore).length) { // could be optimized to stop after first match - return; - } - } - unselect(ev); - }); - } - - - function select(startDate, endDate, allDay) { - unselect(); - if (!endDate) { - endDate = defaultSelectionEnd(startDate, allDay); - } - renderSelection(startDate, endDate, allDay); - reportSelection(startDate, endDate, allDay); - } - - - function unselect(ev) { - if (selected) { - selected = false; - clearSelection(); - trigger('unselect', null, ev); - } - } - - - function reportSelection(startDate, endDate, allDay, ev) { - selected = true; - trigger('select', null, startDate, endDate, allDay, ev); - } - - - function daySelectionMousedown(ev) { // not really a generic manager method, oh well - var cellDate = t.cellDate; - var cellIsAllDay = t.cellIsAllDay; - var hoverListener = t.getHoverListener(); - var reportDayClick = t.reportDayClick; // this is hacky and sort of weird - if (ev.which == 1 && opt('selectable')) { // which==1 means left mouse button - unselect(ev); - var _mousedownElement = this; - var dates; - hoverListener.start(function(cell, origCell) { // TODO: maybe put cellDate/cellIsAllDay info in cell - clearSelection(); - if (cell && cellIsAllDay(cell)) { - dates = [ cellDate(origCell), cellDate(cell) ].sort(cmp); - renderSelection(dates[0], dates[1], true); - }else{ - dates = null; - } - }, ev); - $(document).one('mouseup', function(ev) { - hoverListener.stop(); - if (dates) { - if (+dates[0] == +dates[1]) { - reportDayClick(dates[0], true, ev); - } - reportSelection(dates[0], dates[1], true, ev); - } - }); - } - } - - -} - -function OverlayManager() { - var t = this; - - - // exports - t.renderOverlay = renderOverlay; - t.clearOverlays = clearOverlays; - - - // locals - var usedOverlays = []; - var unusedOverlays = []; - - - function renderOverlay(rect, parent) { - var e = unusedOverlays.shift(); - if (!e) { - e = $("
"); - } - if (e[0].parentNode != parent[0]) { - e.appendTo(parent); - } - usedOverlays.push(e.css(rect).show()); - return e; - } - - - function clearOverlays() { - var e; - while (e = usedOverlays.shift()) { - unusedOverlays.push(e.hide().unbind()); - } - } - - -} - -function CoordinateGrid(buildFunc) { - - var t = this; - var rows; - var cols; - - - t.build = function() { - rows = []; - cols = []; - buildFunc(rows, cols); - }; - - - t.cell = function(x, y) { - var rowCnt = rows.length; - var colCnt = cols.length; - var i, r=-1, c=-1; - for (i=0; i= rows[i][0] && y < rows[i][1]) { - r = i; - break; - } - } - for (i=0; i= cols[i][0] && x < cols[i][1]) { - c = i; - break; - } - } - return (r>=0 && c>=0) ? { row:r, col:c } : null; - }; - - - t.rect = function(row0, col0, row1, col1, originElement) { // row1,col1 is inclusive - var origin = originElement.offset(); - return { - top: rows[row0][0] - origin.top, - left: cols[col0][0] - origin.left, - width: cols[col1][1] - cols[col0][0], - height: rows[row1][1] - rows[row0][0] - }; - }; - -} - -function HoverListener(coordinateGrid) { - - - var t = this; - var bindType; - var change; - var firstCell; - var cell; - - - t.start = function(_change, ev, _bindType) { - change = _change; - firstCell = cell = null; - coordinateGrid.build(); - mouse(ev); - bindType = _bindType || 'mousemove'; - $(document).bind(bindType, mouse); - }; - - - function mouse(ev) { - _fixUIEvent(ev); // see below - var newCell = coordinateGrid.cell(ev.pageX, ev.pageY); - if (!newCell != !cell || newCell && (newCell.row != cell.row || newCell.col != cell.col)) { - if (newCell) { - if (!firstCell) { - firstCell = newCell; - } - change(newCell, firstCell, newCell.row-firstCell.row, newCell.col-firstCell.col); - }else{ - change(newCell, firstCell); - } - cell = newCell; - } - } - - - t.stop = function() { - $(document).unbind(bindType, mouse); - return cell; - }; - - -} - - - -// this fix was only necessary for jQuery UI 1.8.16 (and jQuery 1.7 or 1.7.1) -// upgrading to jQuery UI 1.8.17 (and using either jQuery 1.7 or 1.7.1) fixed the problem -// but keep this in here for 1.8.16 users -// and maybe remove it down the line - -function _fixUIEvent(event) { // for issue 1168 - if (event.pageX === undefined) { - event.pageX = event.originalEvent.pageX; - event.pageY = event.originalEvent.pageY; - } -} -function HorizontalPositionCache(getElement) { - - var t = this, - elements = {}, - lefts = {}, - rights = {}; - - function e(i) { - return elements[i] = elements[i] || getElement(i); - } - - t.left = function(i) { - return lefts[i] = lefts[i] === undefined ? e(i).position().left : lefts[i]; - }; - - t.right = function(i) { - return rights[i] = rights[i] === undefined ? t.left(i) + e(i).width() : rights[i]; - }; - - t.clear = function() { - elements = {}; - lefts = {}; - rights = {}; - }; - -} - -})(jQuery); diff --git a/www/plugins/fullcalendar/fullcalendar.min.js b/www/plugins/fullcalendar/fullcalendar.min.js deleted file mode 100644 index 67d604528..000000000 --- a/www/plugins/fullcalendar/fullcalendar.min.js +++ /dev/null @@ -1,114 +0,0 @@ -/* - - FullCalendar v1.5.3 - http://arshaw.com/fullcalendar/ - - Use fullcalendar.css for basic styling. - For event drag & drop, requires jQuery UI draggable. - For event resizing, requires jQuery UI resizable. - - Copyright (c) 2011 Adam Shaw - Dual licensed under the MIT and GPL licenses, located in - MIT-LICENSE.txt and GPL-LICENSE.txt respectively. - - Date: Mon Feb 6 22:40:40 2012 -0800 - -*/ -(function(m,ma){function wb(a){m.extend(true,Ya,a)}function Yb(a,b,e){function d(k){if(E){u();q();na();S(k)}else f()}function f(){B=b.theme?"ui":"fc";a.addClass("fc");b.isRTL&&a.addClass("fc-rtl");b.theme&&a.addClass("ui-widget");E=m("
").prependTo(a);C=new Zb(X,b);(P=C.render())&&a.prepend(P);y(b.defaultView);m(window).resize(oa);t()||g()}function g(){setTimeout(function(){!n.start&&t()&&S()},0)}function l(){m(window).unbind("resize",oa);C.destroy(); -E.remove();a.removeClass("fc fc-rtl ui-widget")}function j(){return i.offsetWidth!==0}function t(){return m("body")[0].offsetWidth!==0}function y(k){if(!n||k!=n.name){F++;pa();var D=n,Z;if(D){(D.beforeHide||xb)();Za(E,E.height());D.element.hide()}else Za(E,1);E.css("overflow","hidden");if(n=Y[k])n.element.show();else n=Y[k]=new Ja[k](Z=s=m("
").appendTo(E),X);D&&C.deactivateButton(D.name);C.activateButton(k);S();E.css("overflow","");D&& -Za(E,1);Z||(n.afterShow||xb)();F--}}function S(k){if(j()){F++;pa();o===ma&&u();var D=false;if(!n.start||k||r=n.end){n.render(r,k||0);fa(true);D=true}else if(n.sizeDirty){n.clearEvents();fa();D=true}else if(n.eventsDirty){n.clearEvents();D=true}n.sizeDirty=false;n.eventsDirty=false;ga(D);W=a.outerWidth();C.updateTitle(n.title);k=new Date;k>=n.start&&k").append(m("").append(f("left")).append(f("center")).append(f("right")))}function d(){Q.remove()}function f(u){var fa=m("");(u=b.header[u])&&m.each(u.split(" "),function(oa){oa>0&&fa.append("");var ga; -m.each(this.split(","),function(ra,sa){if(sa=="title"){fa.append("

 

");ga&&ga.addClass(q+"-corner-right");ga=null}else{var ha;if(a[sa])ha=a[sa];else if(Ja[sa])ha=function(){na.removeClass(q+"-state-hover");a.changeView(sa)};if(ha){ra=b.theme?jb(b.buttonIcons,sa):null;var da=jb(b.buttonText,sa),na=m(""+(ra?"":da)+"");if(na){na.click(function(){na.hasClass(q+"-state-disabled")||ha()}).mousedown(function(){na.not("."+q+"-state-active").not("."+q+"-state-disabled").addClass(q+"-state-down")}).mouseup(function(){na.removeClass(q+"-state-down")}).hover(function(){na.not("."+q+"-state-active").not("."+q+"-state-disabled").addClass(q+"-state-hover")},function(){na.removeClass(q+"-state-hover").removeClass(q+"-state-down")}).appendTo(fa); -ga||na.addClass(q+"-corner-left");ga=na}}}});ga&&ga.addClass(q+"-corner-right")});return fa}function g(u){Q.find("h2").html(u)}function l(u){Q.find("span.fc-button-"+u).addClass(q+"-state-active")}function j(u){Q.find("span.fc-button-"+u).removeClass(q+"-state-active")}function t(u){Q.find("span.fc-button-"+u).addClass(q+"-state-disabled")}function y(u){Q.find("span.fc-button-"+u).removeClass(q+"-state-disabled")}var S=this;S.render=e;S.destroy=d;S.updateTitle=g;S.activateButton=l;S.deactivateButton= -j;S.disableButton=t;S.enableButton=y;var Q=m([]),q}function $b(a,b){function e(c,z){return!ca||cka}function d(c,z){ca=c;ka=z;L=[];c=++qa;G=z=U.length;for(var H=0;Hl;y--)if(S=dc[e.substring(l,y)]){if(f)Q+=S(f,d);l=y-1;break}if(y==l)if(f)Q+=t}}return Q}function Ua(a){return a.end?ec(a.end,a.allDay):ba(N(a.start),1)}function ec(a,b){a=N(a);return b||a.getHours()||a.getMinutes()?ba(a,1):Ka(a)}function fc(a,b){return(b.msLength-a.msLength)*100+(a.event.start-b.event.start)}function Cb(a,b){return a.end>b.start&&a.starte&&td){y=N(d);Q=false}else{y=y;Q=true}f.push({event:j,start:t,end:y,isStart:S,isEnd:Q,msLength:y-t})}}return f.sort(fc)}function ob(a){var b=[],e,d=a.length,f,g,l,j;for(e=0;e=0;e--){d=a[b[e].toLowerCase()];if(d!== -ma)return d}return a[""]}function Qa(a){return a.replace(/&/g,"&").replace(//g,">").replace(/'/g,"'").replace(/"/g,""").replace(/\n/g,"
")}function Ib(a){return a.id+"/"+a.className+"/"+a.style.cssText.replace(/(^|;)\s*(top|left|width|height)\s*:[^;]*/ig,"")}function qb(a){a.attr("unselectable","on").css("MozUserSelect","none").bind("selectstart.ui",function(){return false})}function ab(a){a.children().removeClass("fc-first fc-last").filter(":first-child").addClass("fc-first").end().filter(":last-child").addClass("fc-last")} -function rb(a,b){a.each(function(e,d){d.className=d.className.replace(/^fc-\w*/,"fc-"+lc[b.getDay()])})}function Jb(a,b){var e=a.source||{},d=a.color,f=e.color,g=b("eventColor"),l=a.backgroundColor||d||e.backgroundColor||f||b("eventBackgroundColor")||g;d=a.borderColor||d||e.borderColor||f||b("eventBorderColor")||g;a=a.textColor||e.textColor||b("eventTextColor");b=[];l&&b.push("background-color:"+l);d&&b.push("border-color:"+d);a&&b.push("color:"+a);return b.join(";")}function $a(a,b,e){if(m.isFunction(a))a= -[a];if(a){var d,f;for(d=0;d";for(aa=0;aa";R+="";for(aa=0;aa";for(V=0;V
"+(I?"
":"")+"
 
";R+=""}R+="";w= -m(R).appendTo(a);K=w.find("thead");i=K.find("th");C=w.find("tbody");P=C.find("tr");E=C.find("td");B=E.filter(":first-child");n=P.eq(0).find("div.fc-day-content div");ab(K.add(K.find("tr")));ab(P);P.eq(0).addClass("fc-first");y(E);Y=m("
").appendTo(a)}function l(w){var I=w||v==1,R=p.start.getMonth(),V=Ka(new Date),ea,aa,va;I&&i.each(function(wa,Ga){ea=m(Ga);aa=ca(wa);ea.html(ya(aa,$));rb(ea,aa)});E.each(function(wa,Ga){ea=m(Ga);aa=ca(wa);aa.getMonth()== -R?ea.removeClass("fc-other-month"):ea.addClass("fc-other-month");+aa==+V?ea.addClass(la+"-state-highlight fc-today"):ea.removeClass(la+"-state-highlight fc-today");ea.find("div.fc-day-number").text(aa.getDate());I&&rb(ea,aa)});P.each(function(wa,Ga){va=m(Ga);if(wa div"),(ea==v-1?R:I)-Sa(V))}})}function t(w){W=w;M.clear();s=Math.floor(W/F);Va(i.slice(0,-1),s)}function y(w){w.click(S).mousedown(X)}function S(w){if(!L("selectable")){var I=parseInt(this.className.match(/fc\-day(\d+)/)[1]);I=ca(I);c("dayClick",this,I,true,w)}}function Q(w,I,R){R&&r.build();R=N(p.visStart);for(var V=ba(N(R),F),ea=0;ea ";for(A=0;A";x+="  ";for(A=0;A
 
";x+=" ";v=m(x).appendTo(a);F=v.find("thead");r=F.find("th").slice(1,-1);J=v.find("tbody");M=J.find("td").slice(0,-1);k=M.find("div.fc-day-content div");D=M.eq(0);Z=D.find("> div");ab(F.add(F.find("tr")));ab(J.add(J.find("tr")));aa=F.find("th:first");va=v.find(".fc-agenda-gutter");ja=m("
").appendTo(a); -if(i("allDaySlot")){ia=m("
").appendTo(ja);x="
"+i("allDayText")+"
 
";la=m(x).appendTo(ja);$=la.find("tr");q($.find("td"));aa=aa.add(la.find("th:first"));va=va.add(la.find("th.fc-agenda-gutter"));ja.append("
")}else ia=m([]);w=m("
").appendTo(ja);I=m("
").appendTo(w);R=m("
").appendTo(I);x="";ta=zb();za=xa(N(ta),bb);xa(ta,La);for(A=tb=0;ta";xa(ta,i("slotMinutes"));tb++}x+="
"+(!Ea||!Da?s(ta,i("axisFormat")):" ")+"
 
";V=m(x).appendTo(I);ea=V.find("div:first");u(V.find("td"));aa=aa.add(V.find("th:first"))}function l(){var h,O,x,A,ta=Ka(new Date);for(h=0;h=0&&xa(O,La+h*i("slotMinutes"));return O}function ua(h){return ba(N(K.visStart),h*Ha+Ia)}function pa(h){return i("allDaySlot")&&!h.row}function U(h){return(h-Math.max(Tb,Sb)+Ba)%Ba*Ha+Ia}function ca(h,O){h=N(h,true);if(O=xa(N(h),bb))return V.height(); -h=i("slotMinutes");O=O.getHours()*60+O.getMinutes()-La;var x=Math.floor(O/h),A=ub[x];if(A===ma)A=ub[x]=V.find("tr:eq("+x+") td div")[0].offsetTop;return Math.max(0,Math.round(A-1+Xa*(O%h/h)))}function ka(){return{left:Ma,right:Ga-vb}}function qa(){return $}function G(h){var O=N(h.start);if(h.allDay)return O;return xa(O,i("defaultEventMinutes"))}function p(h,O){if(O)return N(h);return xa(N(h),i("slotMinutes"))}function L(h,O,x){if(x)i("allDaySlot")&&oa(h,ba(N(O),1),true);else c(h,O)}function c(h,O){var x= -i("selectHelper");Na.build();if(x){var A=Ca(h,K.visStart)*Ha+Ia;if(A>=0&&Ata){A.top=ta;A.height=za-ta;A.left+=2;A.width-=5;if(m.isFunction(x)){if(h=x(h,O)){A.position="absolute";A.zIndex=8;wa=m(h).css(A).appendTo(I)}}else{A.isStart=true;A.isEnd=true;wa=m(o({title:"",start:h,end:O,className:["fc-select-helper"],editable:false},A));wa.css("opacity",i("dragOpacity"))}if(wa){u(wa);I.append(wa);Va(wa,A.width,true);Eb(wa,A.height,true)}}}}else ra(h, -O)}function z(){B();if(wa){wa.remove();wa=null}}function H(h){if(h.which==1&&i("selectable")){Y(h);var O;Ra.start(function(x,A){z();if(x&&x.col==A.col&&!pa(x)){A=na(A);x=na(x);O=[A,xa(N(A),i("slotMinutes")),x,xa(N(x),i("slotMinutes"))].sort(Gb);c(O[0],O[3])}else O=null},h);m(document).one("mouseup",function(x){Ra.stop();if(O){+O[0]==+O[1]&&T(O[0],false,x);n(O[0],O[3],false,x)}})}}function T(h,O,x){C("dayClick",M[U(h.getDay())],h,O,x)}function X(h,O){Ra.start(function(x){B();if(x)if(pa(x))ga(x.row, -x.col,x.row,x.col);else{x=na(x);var A=xa(N(x),i("defaultEventMinutes"));ra(x,A)}},O)}function ya(h,O,x){var A=Ra.stop();B();A&&C("drop",h,na(A),pa(A),O,x)}var K=this;K.renderAgenda=d;K.setWidth=t;K.setHeight=j;K.beforeHide=S;K.afterShow=Q;K.defaultEventEnd=G;K.timePosition=ca;K.dayOfWeekCol=U;K.dateCell=da;K.cellDate=na;K.cellIsAllDay=pa;K.allDayRow=qa;K.allDayBounds=ka;K.getHoverListener=function(){return Ra};K.colContentLeft=sa;K.colContentRight=ha;K.getDaySegmentContainer=function(){return ia}; -K.getSlotSegmentContainer=function(){return R};K.getMinMinute=function(){return La};K.getMaxMinute=function(){return bb};K.getBodyContent=function(){return I};K.getRowCnt=function(){return 1};K.getColCnt=function(){return Ba};K.getColWidth=function(){return db};K.getSlotHeight=function(){return Xa};K.defaultSelectionEnd=p;K.renderDayOverlay=oa;K.renderSelection=L;K.clearSelection=z;K.reportDayClick=T;K.dragStart=X;K.dragStop=ya;Kb.call(K,a,b,e);Lb.call(K);Mb.call(K);sc.call(K);var i=K.opt,C=K.trigger, -P=K.clearEvents,E=K.renderOverlay,B=K.clearOverlays,n=K.reportSelection,Y=K.unselect,W=K.daySelectionMousedown,o=K.slotSegHtml,s=b.formatDate,v,F,r,J,M,k,D,Z,ja,ia,la,$,w,I,R,V,ea,aa,va,wa,Ga,Wb,Ma,db,vb,Xa,Xb,Ba,tb,Na,Ra,cb,ub={},Wa,Tb,Sb,Ub,Ha,Ia,La,bb,Vb;qb(a.addClass("fc-agenda"));Na=new Nb(function(h,O){function x(eb){return Math.max(Ea,Math.min(tc,eb))}var A,ta,za;r.each(function(eb,uc){A=m(uc);ta=A.offset().left;if(eb)za[1]=ta;za=[ta];O[eb]=za});za[1]=ta+A.outerWidth();if(i("allDaySlot")){A= -$;ta=A.offset().top;h[0]=[ta,ta+A.outerHeight()]}for(var Da=I.offset().top,Ea=w.offset().top,tc=Ea+w.outerHeight(),fb=0;fb
"+Qa(W(o.start,o.end,u("timeFormat")))+"
"+Qa(o.title)+"
";if(s.isEnd&&ga(o))v+="
=
"; -v+="";return v}function j(o,s,v){oa(o)&&y(o,s,v.isStart);v.isEnd&&ga(o)&&c(o,s,v);da(o,s)}function t(o,s,v){var F=s.find("div.fc-event-time");oa(o)&&S(o,s,F);v.isEnd&&ga(o)&&Q(o,s,F);da(o,s)}function y(o,s,v){function F(){if(!M){s.width(r).height("").draggable("option","grid",null);M=true}}var r,J,M=true,k,D=u("isRTL")?-1:1,Z=U(),ja=H(),ia=T(),la=ka();s.draggable({zIndex:9,opacity:u("dragOpacity","month"),revertDuration:u("dragRevertDuration"),start:function($,w){fa("eventDragStart", -s,o,$,w);i(o,s);r=s.width();Z.start(function(I,R,V,ea){B();if(I){J=false;k=ea*D;if(I.row)if(v){if(M){s.width(ja-10);Eb(s,ia*Math.round((o.end?(o.end-o.start)/wc:u("defaultEventMinutes"))/u("slotMinutes")));s.draggable("option","grid",[ja,1]);M=false}}else J=true;else{E(ba(N(o.start),k),ba(Ua(o),k));F()}J=J||M&&!k}else{F();J=true}s.draggable("option","revert",J)},$,"drag")},stop:function($,w){Z.stop();B();fa("eventDragStop",s,o,$,w);if(J){F();s.css("filter","");K(o,s)}else{var I=0;M||(I=Math.round((s.offset().top- -X().offset().top)/ia)*u("slotMinutes")+la-(o.start.getHours()*60+o.start.getMinutes()));C(this,o,k,I,M,$,w)}}})}function S(o,s,v){function F(I){var R=xa(N(o.start),I),V;if(o.end)V=xa(N(o.end),I);v.text(W(R,V,u("timeFormat")))}function r(){if(M){v.css("display","");s.draggable("option","grid",[$,w]);M=false}}var J,M=false,k,D,Z,ja=u("isRTL")?-1:1,ia=U(),la=z(),$=H(),w=T();s.draggable({zIndex:9,scroll:false,grid:[$,w],axis:la==1?"y":false,opacity:u("dragOpacity"),revertDuration:u("dragRevertDuration"), -start:function(I,R){fa("eventDragStart",s,o,I,R);i(o,s);J=s.position();D=Z=0;ia.start(function(V,ea,aa,va){s.draggable("option","revert",!V);B();if(V){k=va*ja;if(u("allDaySlot")&&!V.row){if(!M){M=true;v.hide();s.draggable("option","grid",null)}E(ba(N(o.start),k),ba(Ua(o),k))}else r()}},I,"drag")},drag:function(I,R){D=Math.round((R.position.top-J.top)/w)*u("slotMinutes");if(D!=Z){M||F(D);Z=D}},stop:function(I,R){var V=ia.stop();B();fa("eventDragStop",s,o,I,R);if(V&&(k||D||M))C(this,o,k,M?0:D,M,I,R); -else{r();s.css("filter","");s.css(J);F(0);K(o,s)}}})}function Q(o,s,v){var F,r,J=T();s.resizable({handles:{s:"div.ui-resizable-s"},grid:J,start:function(M,k){F=r=0;i(o,s);s.css("z-index",9);fa("eventResizeStart",this,o,M,k)},resize:function(M,k){F=Math.round((Math.max(J,s.height())-k.originalSize.height)/J);if(F!=r){v.text(W(o.start,!F&&!o.end?null:xa(ra(o),u("slotMinutes")*F),u("timeFormat")));r=F}},stop:function(M,k){fa("eventResizeStop",this,o,M,k);if(F)P(this,o,0,u("slotMinutes")*F,M,k);else{s.css("z-index", -8);K(o,s)}}})}var q=this;q.renderEvents=a;q.compileDaySegs=e;q.clearEvents=b;q.slotSegHtml=l;q.bindDaySeg=j;Qb.call(q);var u=q.opt,fa=q.trigger,oa=q.isEventDraggable,ga=q.isEventResizable,ra=q.eventEnd,sa=q.reportEvents,ha=q.reportEventClear,da=q.eventElementHandlers,na=q.setHeight,ua=q.getDaySegmentContainer,pa=q.getSlotSegmentContainer,U=q.getHoverListener,ca=q.getMaxMinute,ka=q.getMinMinute,qa=q.timePosition,G=q.colContentLeft,p=q.colContentRight,L=q.renderDaySegs,c=q.resizableDayEvent,z=q.getColCnt, -H=q.getColWidth,T=q.getSlotHeight,X=q.getBodyContent,ya=q.reportEventElement,K=q.showEvents,i=q.hideEvents,C=q.eventDrop,P=q.eventResize,E=q.renderDayOverlay,B=q.clearOverlays,n=q.calendar,Y=n.formatDate,W=n.formatDates}function vc(a){var b,e,d,f,g,l;for(b=a.length-1;b>0;b--){f=a[b];for(e=0;e"),B=z(),n=i.length,Y;E[0].innerHTML=e(i);E=E.children();B.append(E);d(i,E);l(i);j(i);t(i);Q(i,S(y()));E=[];for(B=0;B
";if(!n.allDay&&B.isStart)k+=""+Qa(T(n.start,n.end,fa("timeFormat")))+"";k+=""+Qa(n.title)+"
";if(B.isEnd&&ra(n))k+="
   
";k+="";B.left=r;B.outerWidth=J-r;B.startCol=v;B.endCol=F+1}return k}function d(i,C){var P,E=i.length,B,n,Y;for(P=0;P div");return P}function S(i){var C,P=i.length,E=[];for(C=0;C"));j[0].parentNode!=l[0]&&j.appendTo(l);d.push(j.css(g).show());return j}function b(){for(var g;g=d.shift();)f.push(g.hide().unbind())}var e=this;e.renderOverlay=a;e.clearOverlays=b;var d=[],f=[]}function Nb(a){var b=this,e,d;b.build=function(){e=[];d=[];a(e,d)};b.cell=function(f,g){var l=e.length,j=d.length, -t,y=-1,S=-1;for(t=0;t=e[t][0]&&g=d[t][0]&&f=0&&S>=0?{row:y,col:S}:null};b.rect=function(f,g,l,j,t){t=t.offset();return{top:e[f][0]-t.top,left:d[g][0]-t.left,width:d[j][1]-d[g][0],height:e[l][1]-e[f][0]}}}function Ob(a){function b(j){xc(j);j=a.cell(j.pageX,j.pageY);if(!j!=!l||j&&(j.row!=l.row||j.col!=l.col)){if(j){g||(g=j);f(j,g,j.row-g.row,j.col-g.col)}else f(j,g);l=j}}var e=this,d,f,g,l;e.start=function(j,t,y){f=j; -g=l=null;a.build();b(t);d=y||"mousemove";m(document).bind(d,b)};e.stop=function(){m(document).unbind(d,b);return l}}function xc(a){if(a.pageX===ma){a.pageX=a.originalEvent.pageX;a.pageY=a.originalEvent.pageY}}function Pb(a){function b(l){return d[l]=d[l]||a(l)}var e=this,d={},f={},g={};e.left=function(l){return f[l]=f[l]===ma?b(l).position().left:f[l]};e.right=function(l){return g[l]=g[l]===ma?e.left(l)+b(l).width():g[l]};e.clear=function(){d={};f={};g={}}}var Ya={defaultView:"month",aspectRatio:1.35, -header:{left:"title",center:"",right:"today prev,next"},weekends:true,allDayDefault:true,ignoreTimezone:true,lazyFetching:true,startParam:"start",endParam:"end",titleFormat:{month:"MMMM yyyy",week:"MMM d[ yyyy]{ '—'[ MMM] d yyyy}",day:"dddd, MMM d, yyyy"},columnFormat:{month:"ddd",week:"ddd M/d",day:"dddd M/d"},timeFormat:{"":"h(:mm)t"},isRTL:false,firstDay:0,monthNames:["January","February","March","April","May","June","July","August","September","October","November","December"],monthNamesShort:["Jan", -"Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],dayNames:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],dayNamesShort:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],buttonText:{prev:" ◄ ",next:" ► ",prevYear:" << ",nextYear:" >> ",today:"today",month:"month",week:"week",day:"day"},theme:false,buttonIcons:{prev:"circle-triangle-w",next:"circle-triangle-e"},unselectAuto:true,dropAccept:"*"},yc= -{header:{left:"next,prev today",center:"",right:"title"},buttonText:{prev:" ► ",next:" ◄ ",prevYear:" >> ",nextYear:" << "},buttonIcons:{prev:"circle-triangle-e",next:"circle-triangle-w"}},Aa=m.fullCalendar={version:"1.5.3"},Ja=Aa.views={};m.fn.fullCalendar=function(a){if(typeof a=="string"){var b=Array.prototype.slice.call(arguments,1),e;this.each(function(){var f=m.data(this,"fullCalendar");if(f&&m.isFunction(f[a])){f=f[a].apply(f, -b);if(e===ma)e=f;a=="destroy"&&m.removeData(this,"fullCalendar")}});if(e!==ma)return e;return this}var d=a.eventSources||[];delete a.eventSources;if(a.events){d.push(a.events);delete a.events}a=m.extend(true,{},Ya,a.isRTL||a.isRTL===ma&&Ya.isRTL?yc:{},a);this.each(function(f,g){f=m(g);g=new Yb(f,a,d);f.data("fullCalendar",g);g.render()});return this};Aa.sourceNormalizers=[];Aa.sourceFetchers=[];var ac={dataType:"json",cache:false},bc=1;Aa.addDays=ba;Aa.cloneDate=N;Aa.parseDate=kb;Aa.parseISO8601= -Bb;Aa.parseTime=mb;Aa.formatDate=Oa;Aa.formatDates=ib;var lc=["sun","mon","tue","wed","thu","fri","sat"],Ab=864E5,cc=36E5,wc=6E4,dc={s:function(a){return a.getSeconds()},ss:function(a){return Pa(a.getSeconds())},m:function(a){return a.getMinutes()},mm:function(a){return Pa(a.getMinutes())},h:function(a){return a.getHours()%12||12},hh:function(a){return Pa(a.getHours()%12||12)},H:function(a){return a.getHours()},HH:function(a){return Pa(a.getHours())},d:function(a){return a.getDate()},dd:function(a){return Pa(a.getDate())}, -ddd:function(a,b){return b.dayNamesShort[a.getDay()]},dddd:function(a,b){return b.dayNames[a.getDay()]},M:function(a){return a.getMonth()+1},MM:function(a){return Pa(a.getMonth()+1)},MMM:function(a,b){return b.monthNamesShort[a.getMonth()]},MMMM:function(a,b){return b.monthNames[a.getMonth()]},yy:function(a){return(a.getFullYear()+"").substring(2)},yyyy:function(a){return a.getFullYear()},t:function(a){return a.getHours()<12?"a":"p"},tt:function(a){return a.getHours()<12?"am":"pm"},T:function(a){return a.getHours()< -12?"A":"P"},TT:function(a){return a.getHours()<12?"AM":"PM"},u:function(a){return Oa(a,"yyyy-MM-dd'T'HH:mm:ss'Z'")},S:function(a){a=a.getDate();if(a>10&&a<20)return"th";return["st","nd","rd"][a%10-1]||"th"}};Aa.applyAll=$a;Ja.month=mc;Ja.basicWeek=nc;Ja.basicDay=oc;wb({weekMode:"fixed"});Ja.agendaWeek=qc;Ja.agendaDay=rc;wb({allDaySlot:true,allDayText:"ganztägig",firstHour:6,slotMinutes:30,defaultEventMinutes:120,axisFormat:"h(:mm)tt",timeFormat:{agenda:"h:mm{ - h:mm}"},dragOpacity:{agenda:0.5},minTime:0, -maxTime:24})})(jQuery); diff --git a/www/plugins/fullcalendar/fullcalendar.print.css b/www/plugins/fullcalendar/fullcalendar.print.css deleted file mode 100644 index e11c18163..000000000 --- a/www/plugins/fullcalendar/fullcalendar.print.css +++ /dev/null @@ -1,61 +0,0 @@ -/* - * FullCalendar v1.5.3 Print Stylesheet - * - * Include this stylesheet on your page to get a more printer-friendly calendar. - * When including this stylesheet, use the media='print' attribute of the tag. - * Make sure to include this stylesheet IN ADDITION to the regular fullcalendar.css. - * - * Copyright (c) 2011 Adam Shaw - * Dual licensed under the MIT and GPL licenses, located in - * MIT-LICENSE.txt and GPL-LICENSE.txt respectively. - * - * Date: Mon Feb 6 22:40:40 2012 -0800 - * - */ - - - /* Events ------------------------------------------------------*/ - -.fc-event-skin { - background: none !important; - color: #000 !important; - } - -/* horizontal events */ - -.fc-event-hori { - border-width: 0 0 1px 0 !important; - border-bottom-style: dotted !important; - border-bottom-color: #000 !important; - padding: 1px 0 0 0 !important; - } - -.fc-event-hori .fc-event-inner { - border-width: 0 !important; - padding: 0 1px !important; - } - -/* vertical events */ - -.fc-event-vert { - border-width: 0 0 0 1px !important; - border-left-style: dotted !important; - border-left-color: #000 !important; - padding: 0 1px 0 0 !important; - } - -.fc-event-vert .fc-event-inner { - border-width: 0 !important; - padding: 1px 0 !important; - } - -.fc-event-bg { - display: none !important; - } - -.fc-event .ui-resizable-handle { - display: none !important; - } - - diff --git a/www/plugins/fullcalendar/gcal.js b/www/plugins/fullcalendar/gcal.js deleted file mode 100644 index e9bbe26d8..000000000 --- a/www/plugins/fullcalendar/gcal.js +++ /dev/null @@ -1,112 +0,0 @@ -/* - * FullCalendar v1.5.3 Google Calendar Plugin - * - * Copyright (c) 2011 Adam Shaw - * Dual licensed under the MIT and GPL licenses, located in - * MIT-LICENSE.txt and GPL-LICENSE.txt respectively. - * - * Date: Mon Feb 6 22:40:40 2012 -0800 - * - */ - -(function($) { - - -var fc = $.fullCalendar; -var formatDate = fc.formatDate; -var parseISO8601 = fc.parseISO8601; -var addDays = fc.addDays; -var applyAll = fc.applyAll; - - -fc.sourceNormalizers.push(function(sourceOptions) { - if (sourceOptions.dataType == 'gcal' || - sourceOptions.dataType === undefined && - (sourceOptions.url || '').match(/^(http|https):\/\/www.google.com\/calendar\/feeds\//)) { - sourceOptions.dataType = 'gcal'; - if (sourceOptions.editable === undefined) { - sourceOptions.editable = false; - } - } -}); - - -fc.sourceFetchers.push(function(sourceOptions, start, end) { - if (sourceOptions.dataType == 'gcal') { - return transformOptions(sourceOptions, start, end); - } -}); - - -function transformOptions(sourceOptions, start, end) { - - var success = sourceOptions.success; - var data = $.extend({}, sourceOptions.data || {}, { - 'start-min': formatDate(start, 'u'), - 'start-max': formatDate(end, 'u'), - 'singleevents': true, - 'max-results': 9999 - }); - - var ctz = sourceOptions.currentTimezone; - if (ctz) { - data.ctz = ctz = ctz.replace(' ', '_'); - } - - return $.extend({}, sourceOptions, { - url: sourceOptions.url.replace(/\/basic$/, '/full') + '?alt=json-in-script&callback=?', - dataType: 'jsonp', - data: data, - startParam: false, - endParam: false, - success: function(data) { - var events = []; - if (data.feed.entry) { - $.each(data.feed.entry, function(i, entry) { - var startStr = entry['gd$when'][0]['startTime']; - var start = parseISO8601(startStr, true); - var end = parseISO8601(entry['gd$when'][0]['endTime'], true); - var allDay = startStr.indexOf('T') == -1; - var url; - $.each(entry.link, function(i, link) { - if (link.type == 'text/html') { - url = link.href; - if (ctz) { - url += (url.indexOf('?') == -1 ? '?' : '&') + 'ctz=' + ctz; - } - } - }); - if (allDay) { - addDays(end, -1); // make inclusive - } - events.push({ - id: entry['gCal$uid']['value'], - title: entry['title']['$t'], - url: url, - start: start, - end: end, - allDay: allDay, - location: entry['gd$where'][0]['valueString'], - description: entry['content']['$t'] - }); - }); - } - var args = [events].concat(Array.prototype.slice.call(arguments, 1)); - var res = applyAll(success, this, args); - if ($.isArray(res)) { - return res; - } - return events; - } - }); - -} - - -// legacy -fc.gcalFeed = function(url, sourceOptions) { - return $.extend({}, sourceOptions, { url: url, dataType: 'gcal' }); -}; - - -})(jQuery); diff --git a/www/plugins/liveimport/payone/payone.php b/www/plugins/liveimport/payone/payone.php index 8c5942d07..211747d22 100644 --- a/www/plugins/liveimport/payone/payone.php +++ b/www/plugins/liveimport/payone/payone.php @@ -498,6 +498,8 @@ protected function GetFile($from, $to, $ssl, $url, $port, $username, $pw, $subdi function Import($config, $app) { $this->app = $app; + /** @var \Psr\Log\LoggerInterface $logger */ + $logger = $this->app->Container->get('Logger'); $csv = []; $index = []; $description = []; @@ -509,7 +511,7 @@ function Import($config, $app) catch (Exception $e) { $filename = ''; } - list($ftphost, $ftpport, $ftpuser, $ftppassword, $ftpdebug, $ftpssl, $ftpsubdir, $sftp) = $this->getFtp($config); + [$ftphost, $ftpport, $ftpuser, $ftppassword, $ftpdebug, $ftpssl, $ftpsubdir, $sftp] = $this->getFtp($config); if($ftphost) { @@ -520,13 +522,13 @@ function Import($config, $app) $folder = $this->app->erp->GetTMP().'payone'; if(!file_exists($folder)) { if(!mkdir($folder) && !is_dir($folder)) { - $this->app->erp->LogFile($folder.' konnte nicht erstellt werden'); + $logger->warning($folder.' konnte nicht erstellt werden'); } } $folder = $folder.'/'.$this->app->Conf->WFdbname; if(!file_exists($folder)) { if(!mkdir($folder) && !is_dir($folder)) { - $this->app->erp->LogFile($folder.' konnte nicht erstellt werden'); + $logger->warning($folder.' konnte nicht erstellt werden'); } } $tofile = $folder.'/'.$filename; @@ -539,7 +541,7 @@ function Import($config, $app) } catch(Exception $e) { $this->fehler[] = $e->getMessage(); - $this->app->erp->LogFile($e->getMessage()); + $logger->error($e->getMessage()); return ''; } try { @@ -547,7 +549,7 @@ function Import($config, $app) } catch(Exception $e) { $this->fehler[] = $e->getMessage(); - $this->app->erp->LogFile($e->getMessage()); + $logger->error($e->getMessage()); return ''; } $list = $connection->scanFilesystem($ftpsubdir); @@ -567,7 +569,7 @@ function Import($config, $app) } catch (Exception $e) { $this->fehler[] = $e->getMessage(); - $this->app->erp->LogFile($e->getMessage()); + $logger->error($e->getMessage()); continue; } } @@ -587,7 +589,7 @@ function Import($config, $app) } catch (Exception $e) { $this->fehler[] = $e->getMessage(); - $this->app->erp->LogFile($e->getMessage()); + $logger->error($e->getMessage()); } } else{ @@ -628,7 +630,7 @@ function Import($config, $app) } catch(Exception $e) { if($ftpdebug) { - $this->app->erp->LogFile(['Error '.$e->getMessage().' in File '.$filename, $line]); + $logger->error('Error '.$e->getMessage().' in File '.$filename, $line); } throw new Exception($e->getMessage().' in File '.$filename, $e->getCode()); } @@ -640,7 +642,7 @@ function Import($config, $app) } catch (Exception $e) { if($ftpdebug) { - $this->app->erp->LogFile(['Error '.$e->getMessage().' in File '.$filename, $line]); + $logger->error('Error '.$e->getMessage().' in File '.$filename, $line); } throw new Exception($e->getMessage().' in File '.$filename, $e->getCode()); } @@ -650,7 +652,7 @@ function Import($config, $app) } catch (Exception $e) { if($ftpdebug) { - $this->app->erp->LogFile(['Error '.$e->getMessage().' in File '.$filename, $line]); + $logger->error('Error '.$e->getMessage().' in File '.$filename, $line); } throw new Exception($e->getMessage().' in File '.$filename, $e->getCode()); } @@ -733,7 +735,7 @@ public function ImportKontoauszug($csv, $konto, $app) $this->checkMissingArrayValues($header, $this->requiredHeaders); } catch(Exception $e) { - $this->app->erp->LogFile(['Error '.$e->getMessage(), $header]); + $this->app->Container->get('Logger')->error('Error '.$e->getMessage(), $header); throw new Exception($e->getMessage().' in '.json_encode($header), $e->getCode()); } diff --git a/www/themes/new/templates/iconbar.tpl b/www/themes/new/templates/iconbar.tpl deleted file mode 100644 index 1734cc16b..000000000 --- a/www/themes/new/templates/iconbar.tpl +++ /dev/null @@ -1,57 +0,0 @@ - -
- - diff --git a/www/themes/new/templates/iconbar_dunkel.tpl b/www/themes/new/templates/iconbar_dunkel.tpl deleted file mode 100644 index ce1d84609..000000000 --- a/www/themes/new/templates/iconbar_dunkel.tpl +++ /dev/null @@ -1,56 +0,0 @@ - -
- -
- - diff --git a/www/themes/new/templates/iconbar_empty.tpl b/www/themes/new/templates/iconbar_empty.tpl deleted file mode 100644 index 36636e7b9..000000000 --- a/www/themes/new/templates/iconbar_empty.tpl +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/www/themes/new/templates/page_smartphone.tpl b/www/themes/new/templates/page_smartphone.tpl deleted file mode 100644 index 5b72a0f4e..000000000 --- a/www/themes/new/templates/page_smartphone.tpl +++ /dev/null @@ -1,58 +0,0 @@ - - - - - - - - -[HTMLTITLE] - - - - - - -
[MESSAGE]
- -[PAGE] -
-
-
- -
- - - - diff --git a/www/widgets/widget.gruppen.php b/www/widgets/widget.gruppen.php index 6591456c8..5e8afa6dc 100644 --- a/www/widgets/widget.gruppen.php +++ b/www/widgets/widget.gruppen.php @@ -54,7 +54,6 @@ function ExtendsForm() // liste zuweisen if($this->app->Secure->POST["projekt"]=="") { - $this->app->erp->LogFile("Standard Projekt laden"); $projekt = $this->app->DB->Select("SELECT standardprojekt FROM firma WHERE id='".$this->app->User->GetFirma()."' LIMIT 1"); $projekt_bevorzugt=$this->app->DB->Select("SELECT projekt_bevorzugen FROM user WHERE id='".$this->app->User->GetID()."' LIMIT 1"); diff --git a/www/widgets/widget.wiedervorlage.php b/www/widgets/widget.wiedervorlage.php index ce159141a..c75dfc963 100644 --- a/www/widgets/widget.wiedervorlage.php +++ b/www/widgets/widget.wiedervorlage.php @@ -81,7 +81,6 @@ function ExtendsForm() if($this->app->Secure->POST["projekt"]=="") { - $this->app->erp->LogFile("Standard Projekt laden"); $projekt = $this->app->DB->Select("SELECT standardprojekt FROM firma WHERE id='".$this->app->User->GetFirma()."' LIMIT 1"); $projekt_bevorzugt=$this->app->DB->Select("SELECT projekt_bevorzugen FROM user WHERE id='".$this->app->User->GetID()."' LIMIT 1"); diff --git a/xentral_autoloader.php b/xentral_autoloader.php deleted file mode 100644 index 7b0633a97..000000000 --- a/xentral_autoloader.php +++ /dev/null @@ -1,194 +0,0 @@ -__DIR__.'/conf/main.conf.php', - 'EasyTable'=>__DIR__.'/phpwf/widgets/easytable.php', - 'FileTable'=>__DIR__.'/phpwf/widgets/filetable.php', - 'DownloadSpoolerTable'=>__DIR__.'/phpwf/widgets/downloadspoolertable.php', - 'HTMLTable'=>__DIR__.'/phpwf/htmltags/class.table.php', - 'image'=>__DIR__.'/www/lib/class.image.php', - 'Location'=>__DIR__.'/www/lib/class.location.php', - 'TemplateParser'=>__DIR__.'/phpwf/plugins/class.templateparser.php', - 'ModuleScriptCache'=>__DIR__.'/phpwf/plugins/class.modulescriptcache.php', - 'Table'=>__DIR__.'/phpwf/widgets/table.php', - 'Remote'=>__DIR__.'/www/lib/class.remote.php', - 'erpAPI'=>__DIR__.'/www/lib/class.erpapi.php', - 'erpooSystem'=>__DIR__.'/www/eproosystem.php', - 'erpAPICustom'=>__DIR__.'/www/lib/class.erpapi_custom.php', - 'RemoteCustom'=>__DIR__.'/www/lib/class.remote_custom.php', - 'YUI'=>__DIR__.'/phpwf/plugins/class.yui.php', - 'User'=>__DIR__.'/phpwf/plugins/class.user.php', - 'Secure'=>__DIR__.'/phpwf/plugins/class.secure.php', - 'Secure2'=>__DIR__.'/phpwf/plugins/class.secure2.php', - 'Acl'=>__DIR__.'/phpwf/plugins/class.acl.php', - 'WawiString'=>__DIR__.'/phpwf/plugins/class.string.php', - 'phpWFAPI'=>__DIR__.'/phpwf/plugins/class.phpwfapi.php', - 'ApplicationCore'=>__DIR__.'/phpwf/class.application_core.php', - 'Application'=>__DIR__.'/phpwf/class.application.php', - 'HttpClient'=>__DIR__.'/www/lib/class.httpclient.php', - 'SMTP'=>__DIR__.'/www/plugins/phpmailer/class.smtp.php', - 'IMAP'=>__DIR__.'/www/lib/imap.inc.php', - 'PHPMailer'=>__DIR__.'/www/plugins/phpmailer/class.phpmailer.php', - 'Help'=>__DIR__.'/www/lib/class.help.php', - 'StringCleaner'=>__DIR__.'/phpwf/plugins/class.stringcleaner.php', - 'Page'=>__DIR__.'/phpwf/plugins/class.page.php', - 'ObjectAPI'=>__DIR__.'/phpwf/plugins/class.objectapi.php', - 'WFMonitor'=>__DIR__.'/phpwf/plugins/class.wfmonitor.php', - 'FormHandler'=>__DIR__.'/phpwf/plugins/class.formhandler.php', - 'DatabaseUpgrade'=>__DIR__.'/phpwf/plugins/class.databaseupgrade.php', - 'WidgetAPI'=>__DIR__.'/phpwf/plugins/class.widgetapi.php', - 'PageBuilder'=>__DIR__.'/phpwf/plugins/class.pagebuilder.php', - 'DB'=>__DIR__.'/phpwf/plugins/class.mysql.php', - 'Printer'=>__DIR__.'/www/lib/class.printer.php', - 'PrinterCustom'=>__DIR__.'/www/lib/class.printer_custom.php', - 'HTMLForm'=>__DIR__.'/phpwf/htmltags/class.form.php', - 'HTMLTextarea'=>__DIR__.'/phpwf/htmltags/class.form.php', - 'BlindField'=>__DIR__.'/phpwf/htmltags/class.form.php', - 'HTMLInput'=>__DIR__.'/phpwf/htmltags/class.form.php', - 'HTMLCheckbox'=>__DIR__.'/phpwf/htmltags/class.form.php', - 'HTMLSelect'=>__DIR__.'/phpwf/htmltags/class.form.php', - 'SimpleList'=>__DIR__.'/phpwf/types/class.simplelist.php', - 'PicosafeLogin'=>__DIR__.'/phpwf/plugins/class.picosafelogin.php', - 'WaWisionOTP'=>__DIR__.'/phpwf/plugins/class.wawision_otp.php', - 'PDF_EPS'=>__DIR__.'/www/lib/pdf/fpdf_final.php', - 'SuperFPDF'=>__DIR__.'/www/lib/dokumente/class.superfpdf.php', - 'Briefpapier'=>__DIR__.'/www/lib/dokumente/class.briefpapier.php', - 'PDF'=>__DIR__.'/www/lib/pdf/fpdf.php', - 'SpeditionPDF'=>__DIR__.'/www/lib/dokumente/class.spedition.php', - 'EtikettenPDF'=>__DIR__.'/www/lib/dokumente/class.etiketten.php', - 'Dokumentenvorlage'=>__DIR__.'/www/lib/dokumente/class.dokumentenvorlage.php', - 'SepaMandat'=>__DIR__.'/www/lib/dokumente/class.sepamandat.php', - 'TransferBase'=>__DIR__.'/www/lib/TransferBase.php', - 'PrinterBase'=>__DIR__.'/www/lib/PrinterBase.php', - 'WikiParser'=>__DIR__.'/www/plugins/class.wikiparser.php', - 'IndexPoint'=>__DIR__.'/www/plugins/class.wikiparser.php', - 'ICS'=>__DIR__.'/www/plugins/class.ics.php', - 'USTID'=>__DIR__.'/www/lib/class.ustid.php', - 'phpprint'=>__DIR__.'/www/plugins/php-print.php', - 'Navigation'=>__DIR__.'/www/lib/class.navigation_edit.php', - 'GoShipment'=>__DIR__.'/www/lib/class.go.php', - 'UPSShipment'=>__DIR__.'/www/lib/class.ups.php', - 'XTEA'=>__DIR__.'/www/lib/class.xtea.php', - 'ShopimporterBase'=>__DIR__.'/www/lib/ShopimporterBase.php', - 'LiveimportBase'=>__DIR__.'/www/plugins/liveimport/LiveimportBase.php', - 'paypal'=>__DIR__.'/www/plugins/liveimport/paypal/paypal.php', - 'DocscanRoot' => __DIR__ . '/www/docscan/classes/DocscanRoot.php', - 'DocscanFile' => __DIR__ . '/www/docscan/classes/DocscanFile.php', - 'DocscanDir' => __DIR__ . '/www/docscan/classes/DocscanDir.php', - 'DocscanAuth' => __DIR__ . '/www/docscan/classes/DocscanAuth.php', - 'ArtikelTabelle' => __DIR__ . '/www/widgets/artikeltable.php', - 'Xentral\Core\LegacyConfig\ConfigLoader'=>__DIR__.'/classes/Core/LegacyConfig/ConfigLoader.php', - 'Xentral\Core\LegacyConfig\Exception\LegacyConfigExceptionInterface'=>__DIR__.'/classes/Core/LegacyConfig/Exception/LegacyConfigExceptionInterface.php', - 'Xentral\Core\LegacyConfig\Exception\InvalidArgumentException'=>__DIR__.'/classes/Core/LegacyConfig/Exception/InvalidArgumentException.php', - 'Xentral\Core\LegacyConfig\Exception\MultiDbConfigNotFoundException'=>__DIR__.'/classes/Core/LegacyConfig/Exception/MultiDbConfigNotFoundException.php', - 'Xentral\Core\LegacyConfig\MultiDbArrayHydrator'=>__DIR__.'/classes/Core/LegacyConfig/MultiDbArrayHydrator.php', - 'Xentral\Core\ErrorHandler\ErrorHandler'=>__DIR__.'/classes/Core/ErrorHandler/ErrorHandler.php', - 'Xentral\Core\ErrorHandler\ErrorPageData'=>__DIR__.'/classes/Core/ErrorHandler/ErrorPageData.php', - 'Xentral\Core\ErrorHandler\ErrorPageRenderer'=>__DIR__.'/classes/Core/ErrorHandler/ErrorPageRenderer.php', - 'Xentral\Core\ErrorHandler\PhpErrorException'=>__DIR__.'/classes/Core/ErrorHandler/PhpErrorException.php', - 'Xentral\Core\Exception\ComponentExceptionInterface'=>__DIR__. '/classes/Core/Exception/ComponentExceptionInterface.php', - 'Xentral\Core\Exception\CoreExceptionInterface'=>__DIR__. '/classes/Core/Exception/CoreExceptionInterface.php', - 'Xentral\Core\Exception\ModuleExceptionInterface'=>__DIR__. '/classes/Core/Exception/ModuleExceptionInterface.php', - 'Xentral\Core\Exception\WidgetExceptionInterface'=>__DIR__. '/classes/Core/Exception/WidgetExceptionInterface.php', - 'Xentral\Core\Exception\XentralExceptionInterface'=>__DIR__. '/classes/Core/Exception/XentralExceptionInterface.php', - 'Xentral\Core\Installer\ClassMapGenerator'=>__DIR__.'/classes/Core/Installer/ClassMapGenerator.php', - 'Xentral\Core\Installer\Installer'=>__DIR__.'/classes/Core/Installer/Installer.php', - 'Xentral\Core\Installer\InstallerCacheConfig'=>__DIR__.'/classes/Core/Installer/InstallerCacheConfig.php', - 'Xentral\Core\Installer\InstallerCacheWriter'=>__DIR__.'/classes/Core/Installer/InstallerCacheWriter.php', - 'Xentral\Core\Installer\Psr4ClassNameResolver'=>__DIR__.'/classes/Core/Installer/Psr4ClassNameResolver.php', - ); - if(isset($classes[$class]) && is_file($classes[$class])) - { - include_once $classes[$class]; - return; - } - if(strpos($class,'Widget') === 0) - { - if(strpos($class,'WidgetGen') === 0) - { - $file = strtolower(substr($class,9)); - if(is_file(__DIR__.'/www/widgets/_gen/widget.gen.'.$file.'.php')) - { - include __DIR__.'/www/widgets/_gen/widget.gen.'.$file.'.php'; - return; - } - } - $file = strtolower(substr($class,6)); - if(is_file(__DIR__.'/www/widgets/widget.'.$file.'.php')) - { - include __DIR__.'/www/widgets/widget.'.$file.'.php'; - return; - } - } - if($class === 'AES') - { - if(version_compare(phpversion(),'7.1', '>=') && is_file(__DIR__.'/www/lib/class.aes2.php')){ - include __DIR__.'/www/lib/class.aes2.php'; - } else{ - include __DIR__ . '/www/lib/class.aes.php'; - } - return; - } - if($class === 'FPDFWAWISION') - { - if(is_file(__DIR__.'/conf/user_defined.php')) - { - include_once __DIR__.'/conf/user_defined.php'; - } - if(!defined('USEFPDF3')){ - define('USEFPDF3', true); - } - if(defined('USEFPDF3') && USEFPDF3) - { - if(is_file(__DIR__ .'/www/lib/pdf/fpdf_3.php')) - { - require_once __DIR__ .'/www/lib/pdf/fpdf_3.php'; - }else { - require_once __DIR__ .'/www/lib/pdf/fpdf.php'; - } - } - else if(defined('USEFPDF2') && USEFPDF2) - { - if(is_file(__DIR__ .'/www/lib/pdf/fpdf_2.php')) - { - require_once __DIR__ .'/www/lib/pdf/fpdf_2.php'; - }else { - require_once __DIR__ .'/www/lib/pdf/fpdf.php'; - } - } else { - require_once __DIR__ .'/www/lib/pdf/fpdf.php'; - } - return; - } - if($class === 'BriefpapierCustom') - { - if(is_file(__DIR__.'/www/lib/dokumente/class.briefpapier_custom.php')) - { - include __DIR__.'/www/lib/dokumente/class.briefpapier_custom.php'; - }else{ - class BriefpapierCustom extends Briefpapier - { - - } - } - } - - if(substr($class, -3) === 'PDF') { - $file = __DIR__.'/www/lib/dokumente/class.'.strtolower(substr($class,0,-3)).'.php'; - if(file_exists($file)) { - include $file; - } - elseif(file_exists(__DIR__.'/www/lib/dokumente/class.'.strtolower($class).'.php')) { - include __DIR__.'/www/lib/dokumente/class.'.strtolower($class).'.php'; - } - } - elseif(substr($class, -9) === 'PDFCustom') { - $file = __DIR__.'/www/lib/dokumente/class.'.strtolower(substr($class,0,-9)).'_custom.php'; - if(file_exists($file)) { - include $file; - } - } -} - -spl_autoload_register('xentral_autoloader');