Server IP : 213.176.29.180  /  Your IP : 18.116.88.132
Web Server : Apache
System : Linux 213.176.29.180.hostiran.name 4.18.0-553.22.1.el8_10.x86_64 #1 SMP Tue Sep 24 05:16:59 EDT 2024 x86_64
User : webtaragh ( 1001)
PHP Version : 7.4.33
Disable Function : NONE
MySQL : OFF  |  cURL : ON  |  WGET : ON  |  Perl : ON  |  Python : ON
Directory (0750) :  /home/webtaragh/public_html/wp-content/../

[  Home  ][  C0mmand  ][  Upload File  ]

Current File : /home/webtaragh/public_html/wp-content/../laminas.tar
laminas-mail/COPYRIGHT.md000064400000000133147361032560011006 0ustar00Copyright (c) 2020 Laminas Project a Series of LF Projects, LLC. (https://getlaminas.org/)
laminas-mail/mkdocs.yml000064400000001626147361032560011127 0ustar00docs_dir: docs/book
site_dir: docs/html
nav:
    - Home: index.md
    - Introduction: intro.md
    - Reference:
        - Messages:
            - "Intro and Usage": message/intro.md
            - "Attachments": message/attachments.md
            - "Character Sets": message/character-sets.md
        - Transports:
            - Usage: transport/intro.md
            - SMTP:
                - "SMTP Options": transport/smtp-options.md
                - "Sending multiple messages": transport/smtp-multiple-send.md
                - Authentication: transport/smtp-authentication.md
            - "File Transport Options": transport/file-options.md
        - "Reading and Storing Mail": read.md
site_name: laminas-mail
site_description: 'Parse, create, store, and send email messages, using a variety of storage and transport protocols.'
repo_url: 'https://github.com/laminas/laminas-mail'
extra:
    project: Components
laminas-mail/src/MessageFactory.php000064400000003207147361032560013335 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-mail for the canonical source repository
 * @copyright https://github.com/laminas/laminas-mail/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-mail/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Mail;

use Traversable;

class MessageFactory
{
    /**
     * @param array|Traversable $options
     * @return Message
     */
    public static function getInstance($options = [])
    {
        if (! is_array($options) && ! $options instanceof Traversable) {
            throw new Exception\InvalidArgumentException(sprintf(
                '"%s" expects an array or Traversable; received "%s"',
                __METHOD__,
                (is_object($options) ? get_class($options) : gettype($options))
            ));
        }

        $message = new Message();

        foreach ($options as $key => $value) {
            $setter = self::getSetterMethod($key);
            if (method_exists($message, $setter)) {
                $message->{$setter}($value);
            }
        }

        return $message;
    }

    /**
     * Generate a setter method name based on a provided key.
     *
     * @param string $key
     * @return string
     */
    private static function getSetterMethod($key)
    {
        return 'set'
            . str_replace(
                ' ',
                '',
                ucwords(
                    strtr(
                        $key,
                        [
                            '-' => ' ',
                            '_' => ' ',
                        ]
                    )
                )
            );
    }
}
laminas-mail/src/Message.php000064400000037227147361032560012016 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-mail for the canonical source repository
 * @copyright https://github.com/laminas/laminas-mail/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-mail/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Mail;

use Laminas\Mail\Header\ContentType;
use Laminas\Mail\Header\Sender;
use Laminas\Mime;
use Traversable;

class Message
{
    /**
     * Content of the message
     *
     * @var string|object|Mime\Message
     */
    protected $body;

    /**
     * @var Headers
     */
    protected $headers;

    /**
     * Message encoding
     *
     * Used to determine whether or not to encode headers; defaults to ASCII.
     *
     * @var string
     */
    protected $encoding = 'ASCII';

    /**
     * Is the message valid?
     *
     * If we don't any From addresses, we're invalid, according to RFC2822.
     *
     * @return bool
     */
    public function isValid()
    {
        $from = $this->getFrom();
        if (! $from instanceof AddressList) {
            return false;
        }
        return (bool) count($from);
    }

    /**
     * Set the message encoding
     *
     * @param  string $encoding
     * @return Message
     */
    public function setEncoding($encoding)
    {
        $this->encoding = $encoding;
        $this->getHeaders()->setEncoding($encoding);
        return $this;
    }

    /**
     * Get the message encoding
     *
     * @return string
     */
    public function getEncoding()
    {
        return $this->encoding;
    }

    /**
     * Compose headers
     *
     * @param  Headers $headers
     * @return Message
     */
    public function setHeaders(Headers $headers)
    {
        $this->headers = $headers;
        $headers->setEncoding($this->getEncoding());
        return $this;
    }

    /**
     * Access headers collection
     *
     * Lazy-loads if not already attached.
     *
     * @return Headers
     */
    public function getHeaders()
    {
        if (null === $this->headers) {
            $this->setHeaders(new Headers());
            $date = Header\Date::fromString('Date: ' . date('r'));
            $this->headers->addHeader($date);
        }
        return $this->headers;
    }

    /**
     * Set (overwrite) From addresses
     *
     * @param  string|Address\AddressInterface|array|AddressList|Traversable $emailOrAddressList
     * @param  string|null $name
     * @return Message
     */
    public function setFrom($emailOrAddressList, $name = null)
    {
        $this->clearHeaderByName('from');
        return $this->addFrom($emailOrAddressList, $name);
    }

    /**
     * Add a "From" address
     *
     * @param  string|Address|array|AddressList|Traversable $emailOrAddressOrList
     * @param  string|null $name
     * @return Message
     */
    public function addFrom($emailOrAddressOrList, $name = null)
    {
        $addressList = $this->getFrom();
        $this->updateAddressList($addressList, $emailOrAddressOrList, $name, __METHOD__);
        return $this;
    }

    /**
     * Retrieve list of From senders
     *
     * @return AddressList
     */
    public function getFrom()
    {
        return $this->getAddressListFromHeader('from', __NAMESPACE__ . '\Header\From');
    }

    /**
     * Overwrite the address list in the To recipients
     *
     * @param  string|Address\AddressInterface|array|AddressList|Traversable $emailOrAddressList
     * @param  null|string $name
     * @return Message
     */
    public function setTo($emailOrAddressList, $name = null)
    {
        $this->clearHeaderByName('to');
        return $this->addTo($emailOrAddressList, $name);
    }

    /**
     * Add one or more addresses to the To recipients
     *
     * Appends to the list.
     *
     * @param  string|Address\AddressInterface|array|AddressList|Traversable $emailOrAddressOrList
     * @param  null|string $name
     * @return Message
     */
    public function addTo($emailOrAddressOrList, $name = null)
    {
        $addressList = $this->getTo();
        $this->updateAddressList($addressList, $emailOrAddressOrList, $name, __METHOD__);
        return $this;
    }

    /**
     * Access the address list of the To header
     *
     * @return AddressList
     */
    public function getTo()
    {
        return $this->getAddressListFromHeader('to', __NAMESPACE__ . '\Header\To');
    }

    /**
     * Set (overwrite) CC addresses
     *
     * @param  string|Address\AddressInterface|array|AddressList|Traversable $emailOrAddressList
     * @param  string|null $name
     * @return Message
     */
    public function setCc($emailOrAddressList, $name = null)
    {
        $this->clearHeaderByName('cc');
        return $this->addCc($emailOrAddressList, $name);
    }

    /**
     * Add a "Cc" address
     *
     * @param  string|Address|array|AddressList|Traversable $emailOrAddressOrList
     * @param  string|null $name
     * @return Message
     */
    public function addCc($emailOrAddressOrList, $name = null)
    {
        $addressList = $this->getCc();
        $this->updateAddressList($addressList, $emailOrAddressOrList, $name, __METHOD__);
        return $this;
    }

    /**
     * Retrieve list of CC recipients
     *
     * @return AddressList
     */
    public function getCc()
    {
        return $this->getAddressListFromHeader('cc', __NAMESPACE__ . '\Header\Cc');
    }

    /**
     * Set (overwrite) BCC addresses
     *
     * @param  string|Address\AddressInterface|array|AddressList|Traversable $emailOrAddressList
     * @param  string|null $name
     * @return Message
     */
    public function setBcc($emailOrAddressList, $name = null)
    {
        $this->clearHeaderByName('bcc');
        return $this->addBcc($emailOrAddressList, $name);
    }

    /**
     * Add a "Bcc" address
     *
     * @param  string|Address|array|AddressList|Traversable $emailOrAddressOrList
     * @param  string|null $name
     * @return Message
     */
    public function addBcc($emailOrAddressOrList, $name = null)
    {
        $addressList = $this->getBcc();
        $this->updateAddressList($addressList, $emailOrAddressOrList, $name, __METHOD__);
        return $this;
    }

    /**
     * Retrieve list of BCC recipients
     *
     * @return AddressList
     */
    public function getBcc()
    {
        return $this->getAddressListFromHeader('bcc', __NAMESPACE__ . '\Header\Bcc');
    }

    /**
     * Overwrite the address list in the Reply-To recipients
     *
     * @param  string|Address\AddressInterface|array|AddressList|Traversable $emailOrAddressList
     * @param  null|string $name
     * @return Message
     */
    public function setReplyTo($emailOrAddressList, $name = null)
    {
        $this->clearHeaderByName('reply-to');
        return $this->addReplyTo($emailOrAddressList, $name);
    }

    /**
     * Add one or more addresses to the Reply-To recipients
     *
     * Appends to the list.
     *
     * @param  string|Address\AddressInterface|array|AddressList|Traversable $emailOrAddressOrList
     * @param  null|string $name
     * @return Message
     */
    public function addReplyTo($emailOrAddressOrList, $name = null)
    {
        $addressList = $this->getReplyTo();
        $this->updateAddressList($addressList, $emailOrAddressOrList, $name, __METHOD__);
        return $this;
    }

    /**
     * Access the address list of the Reply-To header
     *
     * @return AddressList
     */
    public function getReplyTo()
    {
        return $this->getAddressListFromHeader('reply-to', __NAMESPACE__ . '\Header\ReplyTo');
    }

    /**
     * setSender
     *
     * @param mixed $emailOrAddress
     * @param mixed $name
     * @return Message
     */
    public function setSender($emailOrAddress, $name = null)
    {
        /** @var Sender $header */
        $header = $this->getHeaderByName('sender', __NAMESPACE__ . '\Header\Sender');
        $header->setAddress($emailOrAddress, $name);
        return $this;
    }

    /**
     * Retrieve the sender address, if any
     *
     * @return null|Address\AddressInterface
     */
    public function getSender()
    {
        $headers = $this->getHeaders();
        if (! $headers->has('sender')) {
            return null;
        }

        /** @var Sender $header */
        $header = $this->getHeaderByName('sender', __NAMESPACE__ . '\Header\Sender');
        return $header->getAddress();
    }

    /**
     * Set the message subject header value
     *
     * @param  string $subject
     * @return Message
     */
    public function setSubject($subject)
    {
        $headers = $this->getHeaders();
        if (! $headers->has('subject')) {
            $header = new Header\Subject();
            $headers->addHeader($header);
        } else {
            $header = $headers->get('subject');
        }
        $header->setSubject($subject);
        $header->setEncoding($this->getEncoding());
        return $this;
    }

    /**
     * Get the message subject header value
     *
     * @return null|string
     */
    public function getSubject()
    {
        $headers = $this->getHeaders();
        if (! $headers->has('subject')) {
            return;
        }
        $header = $headers->get('subject');
        return $header->getFieldValue();
    }

    /**
     * Set the message body
     *
     * @param  null|string|\Laminas\Mime\Message|object $body
     * @throws Exception\InvalidArgumentException
     * @return Message
     */
    public function setBody($body)
    {
        if (! is_string($body) && $body !== null) {
            if (! is_object($body)) {
                throw new Exception\InvalidArgumentException(sprintf(
                    '%s expects a string or object argument; received "%s"',
                    __METHOD__,
                    gettype($body)
                ));
            }
            if (! $body instanceof Mime\Message) {
                if (! method_exists($body, '__toString')) {
                    throw new Exception\InvalidArgumentException(sprintf(
                        '%s expects object arguments of type %s or implementing __toString();'
                        . ' object of type "%s" received',
                        __METHOD__,
                        Mime\Message::class,
                        get_class($body)
                    ));
                }
            }
        }
        $this->body = $body;

        if (! $this->body instanceof Mime\Message) {
            return $this;
        }

        // Get headers, and set Mime-Version header
        $headers = $this->getHeaders();
        $this->getHeaderByName('mime-version', __NAMESPACE__ . '\Header\MimeVersion');

        // Multipart content headers
        if ($this->body->isMultiPart()) {
            $mime   = $this->body->getMime();

            /** @var ContentType $header */
            $header = $this->getHeaderByName('content-type', __NAMESPACE__ . '\Header\ContentType');
            $header->setType('multipart/mixed');
            $header->addParameter('boundary', $mime->boundary());
            return $this;
        }

        // MIME single part headers
        $parts = $this->body->getParts();
        if (! empty($parts)) {
            $part = array_shift($parts);
            $headers->addHeaders($part->getHeadersArray("\r\n"));
        }
        return $this;
    }

    /**
     * Return the currently set message body
     *
     * @return object|string|Mime\Message
     */
    public function getBody()
    {
        return $this->body;
    }

    /**
     * Get the string-serialized message body text
     *
     * @return string
     */
    public function getBodyText()
    {
        if ($this->body instanceof Mime\Message) {
            return $this->body->generateMessage(Headers::EOL);
        }

        return (string) $this->body;
    }

    /**
     * Retrieve a header by name
     *
     * If not found, instantiates one based on $headerClass.
     *
     * @param  string $headerName
     * @param  string $headerClass
     * @return Header\HeaderInterface|\ArrayIterator header instance or collection of headers
     */
    protected function getHeaderByName($headerName, $headerClass)
    {
        $headers = $this->getHeaders();
        if ($headers->has($headerName)) {
            $header = $headers->get($headerName);
        } else {
            $header = new $headerClass();
            $headers->addHeader($header);
        }
        return $header;
    }

    /**
     * Clear a header by name
     *
     * @param  string $headerName
     */
    protected function clearHeaderByName($headerName)
    {
        $this->getHeaders()->removeHeader($headerName);
    }

    /**
     * Retrieve the AddressList from a named header
     *
     * Used with To, From, Cc, Bcc, and ReplyTo headers. If the header does not
     * exist, instantiates it.
     *
     * @param  string $headerName
     * @param  string $headerClass
     * @throws Exception\DomainException
     * @return AddressList
     */
    protected function getAddressListFromHeader($headerName, $headerClass)
    {
        $header = $this->getHeaderByName($headerName, $headerClass);
        if (! $header instanceof Header\AbstractAddressList) {
            throw new Exception\DomainException(sprintf(
                'Cannot grab address list from header of type "%s"; not an AbstractAddressList implementation',
                get_class($header)
            ));
        }
        return $header->getAddressList();
    }

    /**
     * Update an address list
     *
     * Proxied to this from addFrom, addTo, addCc, addBcc, and addReplyTo.
     *
     * @param  AddressList $addressList
     * @param  string|Address\AddressInterface|array|AddressList|Traversable $emailOrAddressOrList
     * @param  null|string $name
     * @param  string $callingMethod
     * @throws Exception\InvalidArgumentException
     */
    protected function updateAddressList(AddressList $addressList, $emailOrAddressOrList, $name, $callingMethod)
    {
        if ($emailOrAddressOrList instanceof Traversable) {
            foreach ($emailOrAddressOrList as $address) {
                $addressList->add($address);
            }
            return;
        }
        if (is_array($emailOrAddressOrList)) {
            $addressList->addMany($emailOrAddressOrList);
            return;
        }
        if (! is_string($emailOrAddressOrList) && ! $emailOrAddressOrList instanceof Address\AddressInterface) {
            throw new Exception\InvalidArgumentException(sprintf(
                '%s expects a string, AddressInterface, array, AddressList, or Traversable as its first argument;'
                . ' received "%s"',
                $callingMethod,
                (is_object($emailOrAddressOrList) ? get_class($emailOrAddressOrList) : gettype($emailOrAddressOrList))
            ));
        }

        if (is_string($emailOrAddressOrList) && $name === null) {
            $addressList->addFromString($emailOrAddressOrList);
            return;
        }

        $addressList->add($emailOrAddressOrList, $name);
    }

    /**
     * Serialize to string
     *
     * @return string
     */
    public function toString()
    {
        $headers = $this->getHeaders();
        return $headers->toString()
               . Headers::EOL
               . $this->getBodyText();
    }

    /**
     * Instantiate from raw message string
     *
     * @todo   Restore body to Mime\Message
     * @param  string $rawMessage
     * @return Message
     */
    public static function fromString($rawMessage)
    {
        $message = new static();

        /** @var Headers $headers */
        $headers = null;
        $content = null;
        Mime\Decode::splitMessage($rawMessage, $headers, $content, Headers::EOL);
        if ($headers->has('mime-version')) {
            // todo - restore body to mime\message
        }
        $message->setHeaders($headers);
        $message->setBody($content);
        return $message;
    }
}
laminas-mail/src/Module.php000064400000001155147361032560011646 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-mail for the canonical source repository
 * @copyright https://github.com/laminas/laminas-mail/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-mail/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Mail;

class Module
{
    /**
     * Retrieve laminas-mail package configuration for laminas-mvc context.
     *
     * @return array
     */
    public function getConfig()
    {
        $provider = new ConfigProvider();
        return [
            'service_manager' => $provider->getDependencyConfig(),
        ];
    }
}
laminas-mail/src/Address.php000064400000011606147361032560012010 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-mail for the canonical source repository
 * @copyright https://github.com/laminas/laminas-mail/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-mail/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Mail;

use Laminas\Validator\EmailAddress as EmailAddressValidator;
use Laminas\Validator\Hostname;

class Address implements Address\AddressInterface
{
    protected $comment;
    protected $email;
    protected $name;

    /**
     * Create an instance from a string value.
     *
     * Parses a string representing a single address. If it is a valid format,
     * it then creates and returns an instance of itself using the name and
     * email it has parsed from the value.
     *
     * @param string $address
     * @param null|string $comment Comment associated with the address, if any.
     * @throws Exception\InvalidArgumentException
     * @return self
     */
    public static function fromString($address, $comment = null)
    {
        if (! preg_match('/^((?P<name>.*)<(?P<namedEmail>[^>]+)>|(?P<email>.+))$/', $address, $matches)) {
            throw new Exception\InvalidArgumentException('Invalid address format');
        }

        $name = null;
        if (isset($matches['name'])) {
            $name = trim($matches['name']);
        }
        if (empty($name)) {
            $name = null;
        }

        if (isset($matches['namedEmail'])) {
            $email = $matches['namedEmail'];
        }
        if (isset($matches['email'])) {
            $email = $matches['email'];
        }
        $email = trim($email);

        if (preg_match('/\s*<([^<>]+)>\s*/', $email, $matches)) {
            /*
             * Sometimes Laminas fails to parse Hebrew content similar to this:
             *
             * חאלד דג <test@test.com>ש *
             *
             * We need to cut the email out in an attempt to salvage further parsing
             */

            $supposedEmail = $matches[1];
            if (strpos($supposedEmail, '@') !== false) {
                $name = str_replace($matches[0], '', $email);
                $email = $supposedEmail;
            }
        }

        return new static($email, $name, $comment);
    }

    /**
     * Constructor
     *
     * @param  string $email
     * @param  null|string $name
     * @param  null|string $comment
     * @throws Exception\InvalidArgumentException
     */
    public function __construct($email, $name = null, $comment = null)
    {
        $emailAddressValidator = new EmailAddressValidator(Hostname::ALLOW_DNS | Hostname::ALLOW_LOCAL);
        if (! is_string($email) || empty($email)) {
            throw new Exception\InvalidArgumentException('Email must be a valid email address');
        }

        if (preg_match("/[\r\n]/", $email)) {
            throw new Exception\InvalidArgumentException('CRLF injection detected');
        }

        if (! $emailAddressValidator->isValid($email)) {
            $invalidMessages = $emailAddressValidator->getMessages();
            throw new Exception\InvalidArgumentException(array_shift($invalidMessages));
        }

        if (null !== $name) {
            if (! is_string($name)) {
                throw new Exception\InvalidArgumentException('Name must be a string');
            }

            if (preg_match("/[\r\n]/", $name)) {
                throw new Exception\InvalidArgumentException('CRLF injection detected');
            }

            $this->name = $name;
        }

        $this->email = $email;

        if (null !== $comment) {
            $this->comment = $comment;
        }
    }

    /**
     * Retrieve email
     *
     * @return string
     */
    public function getEmail()
    {
        return $this->email;
    }

    /**
     * Retrieve name, if any
     *
     * @return null|string
     */
    public function getName()
    {
        return $this->name;
    }

    /**
     * Retrieve comment, if any
     *
     * @return null|string
     */
    public function getComment()
    {
        return $this->comment;
    }

    /**
     * String representation of address
     *
     * @return string
     */
    public function toString()
    {
        $string = sprintf('<%s>', $this->getEmail());
        $name   = $this->constructName();
        if (null === $name) {
            return $string;
        }

        return sprintf('%s %s', $name, $string);
    }

    /**
     * Constructs the name string
     *
     * If a comment is present, appends the comment (commented using parens) to
     * the name before returning it; otherwise, returns just the name.
     *
     * @return null|string
     */
    private function constructName()
    {
        $name = $this->getName();
        $comment = $this->getComment();

        if ($comment === null || $comment === '') {
            return $name;
        }

        $string = sprintf('%s (%s)', $name, $comment);
        return trim($string);
    }
}
laminas-mail/src/ConfigProvider.php000064400000002061147361032560013336 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-mail for the canonical source repository
 * @copyright https://github.com/laminas/laminas-mail/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-mail/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Mail;

class ConfigProvider
{
    /**
     * Retrieve configuration for laminas-mail package.
     *
     * @return array
     */
    public function __invoke()
    {
        return [
            'dependencies' => $this->getDependencyConfig(),
        ];
    }

    /**
     * Retrieve dependency settings for laminas-mail package.
     *
     * @return array
     */
    public function getDependencyConfig()
    {
        return [
            // Legacy Zend Framework aliases
            'aliases' => [
                \Zend\Mail\Protocol\SmtpPluginManager::class => Protocol\SmtpPluginManager::class,
            ],
            'factories' => [
                Protocol\SmtpPluginManager::class => Protocol\SmtpPluginManagerFactory::class,
            ],
        ];
    }
}
laminas-mail/src/Transport/Smtp.php000064400000023664147361032560013351 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-mail for the canonical source repository
 * @copyright https://github.com/laminas/laminas-mail/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-mail/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Mail\Transport;

use Laminas\Mail\Address;
use Laminas\Mail\Headers;
use Laminas\Mail\Message;
use Laminas\Mail\Protocol;
use Laminas\Mail\Protocol\Exception as ProtocolException;
use Laminas\ServiceManager\ServiceManager;

/**
 * SMTP connection object
 *
 * Loads an instance of Laminas\Mail\Protocol\Smtp and forwards smtp transactions
 */
class Smtp implements TransportInterface
{
    /**
     * @var SmtpOptions
     */
    protected $options;

    /**
     * @var Envelope|null
     */
    protected $envelope;

    /**
     * @var Protocol\Smtp
     */
    protected $connection;

    /**
     * @var bool
     */
    protected $autoDisconnect = true;

    /**
     * @var Protocol\SmtpPluginManager
     */
    protected $plugins;

    /**
     * When did we connect to the server?
     *
     * @var int|null
     */
    protected $connectedTime;

    /**
     * Constructor.
     *
     * @param  SmtpOptions $options Optional
     */
    public function __construct(SmtpOptions $options = null)
    {
        if (! $options instanceof SmtpOptions) {
            $options = new SmtpOptions();
        }
        $this->setOptions($options);
    }

    /**
     * Set options
     *
     * @param  SmtpOptions $options
     * @return Smtp
     */
    public function setOptions(SmtpOptions $options)
    {
        $this->options = $options;
        return $this;
    }

    /**
     * Get options
     *
     * @return SmtpOptions
     */
    public function getOptions()
    {
        return $this->options;
    }

    /**
     * Set options
     *
     * @param  Envelope $envelope
     */
    public function setEnvelope(Envelope $envelope)
    {
        $this->envelope = $envelope;
    }

    /**
     * Get envelope
     *
     * @return Envelope|null
     */
    public function getEnvelope()
    {
        return $this->envelope;
    }

    /**
     * Set plugin manager for obtaining SMTP protocol connection
     *
     * @param  Protocol\SmtpPluginManager $plugins
     * @throws Exception\InvalidArgumentException
     * @return Smtp
     */
    public function setPluginManager(Protocol\SmtpPluginManager $plugins)
    {
        $this->plugins = $plugins;
        return $this;
    }

    /**
     * Get plugin manager for loading SMTP protocol connection
     *
     * @return Protocol\SmtpPluginManager
     */
    public function getPluginManager()
    {
        if (null === $this->plugins) {
            $this->setPluginManager(new Protocol\SmtpPluginManager(new ServiceManager()));
        }
        return $this->plugins;
    }

    /**
     * Set the automatic disconnection when destruct
     *
     * @param  bool $flag
     * @return Smtp
     */
    public function setAutoDisconnect($flag)
    {
        $this->autoDisconnect = (bool) $flag;
        return $this;
    }

    /**
     * Get the automatic disconnection value
     *
     * @return bool
     */
    public function getAutoDisconnect()
    {
        return $this->autoDisconnect;
    }

    /**
     * Return an SMTP connection
     *
     * @param  string $name
     * @param  array|null $options
     * @return Protocol\Smtp
     */
    public function plugin($name, array $options = null)
    {
        return $this->getPluginManager()->get($name, $options);
    }

    /**
     * Class destructor to ensure all open connections are closed
     */
    public function __destruct()
    {
        if (! $this->getConnection() instanceof Protocol\Smtp) {
            return;
        }

        try {
            $this->getConnection()->quit();
        } catch (ProtocolException\ExceptionInterface $e) {
            // ignore
        }

        if ($this->autoDisconnect) {
            $this->getConnection()->disconnect();
        }
    }

    /**
     * Sets the connection protocol instance
     *
     * @param Protocol\AbstractProtocol $connection
     */
    public function setConnection(Protocol\AbstractProtocol $connection)
    {
        $this->connection = $connection;
        if (($connection instanceof Protocol\Smtp)
            && ($this->getOptions()->getConnectionTimeLimit() !== null)
        ) {
            $connection->setUseCompleteQuit(false);
        }
    }

    /**
     * Gets the connection protocol instance
     *
     * @return Protocol\Smtp
     */
    public function getConnection()
    {
        $timeLimit = $this->getOptions()->getConnectionTimeLimit();
        if ($timeLimit !== null
            && $this->connectedTime !== null
            && ((time() - $this->connectedTime) > $timeLimit)
        ) {
            $this->connection = null;
        }
        return $this->connection;
    }

    /**
     * Disconnect the connection protocol instance
     *
     * @return void
     */
    public function disconnect()
    {
        if ($this->getConnection() instanceof Protocol\Smtp) {
            $this->getConnection()->disconnect();
            $this->connectedTime = null;
        }
    }

    /**
     * Send an email via the SMTP connection protocol
     *
     * The connection via the protocol adapter is made just-in-time to allow a
     * developer to add a custom adapter if required before mail is sent.
     *
     * @param Message $message
     * @throws Exception\RuntimeException
     */
    public function send(Message $message)
    {
        // If sending multiple messages per session use existing adapter
        $connection = $this->getConnection();

        if (! ($connection instanceof Protocol\Smtp) || ! $connection->hasSession()) {
            $connection = $this->connect();
        } else {
            // Reset connection to ensure reliable transaction
            $connection->rset();
        }

        // Prepare message
        $from       = $this->prepareFromAddress($message);
        $recipients = $this->prepareRecipients($message);
        $headers    = $this->prepareHeaders($message);
        $body       = $this->prepareBody($message);

        if ((count($recipients) == 0) && (! empty($headers) || ! empty($body))) {
            // Per RFC 2821 3.3 (page 18)
            throw new Exception\RuntimeException(
                sprintf(
                    '%s transport expects at least one recipient if the message has at least one header or body',
                    __CLASS__
                )
            );
        }

        // Set sender email address
        $connection->mail($from);

        // Set recipient forward paths
        foreach ($recipients as $recipient) {
            $connection->rcpt($recipient);
        }

        // Issue DATA command to client
        $connection->data($headers . Headers::EOL . $body);
    }

    /**
     * Retrieve email address for envelope FROM
     *
     * @param  Message $message
     * @throws Exception\RuntimeException
     * @return string
     */
    protected function prepareFromAddress(Message $message)
    {
        if ($this->getEnvelope() && $this->getEnvelope()->getFrom()) {
            return $this->getEnvelope()->getFrom();
        }

        $sender = $message->getSender();
        if ($sender instanceof Address\AddressInterface) {
            return $sender->getEmail();
        }

        $from = $message->getFrom();
        if (! count($from)) {
            // Per RFC 2822 3.6
            throw new Exception\RuntimeException(sprintf(
                '%s transport expects either a Sender or at least one From address in the Message; none provided',
                __CLASS__
            ));
        }

        $from->rewind();
        $sender = $from->current();
        return $sender->getEmail();
    }

    /**
     * Prepare array of email address recipients
     *
     * @param  Message $message
     * @return array
     */
    protected function prepareRecipients(Message $message)
    {
        if ($this->getEnvelope() && $this->getEnvelope()->getTo()) {
            return (array) $this->getEnvelope()->getTo();
        }

        $recipients = [];
        foreach ($message->getTo() as $address) {
            $recipients[] = $address->getEmail();
        }
        foreach ($message->getCc() as $address) {
            $recipients[] = $address->getEmail();
        }
        foreach ($message->getBcc() as $address) {
            $recipients[] = $address->getEmail();
        }

        $recipients = array_unique($recipients);
        return $recipients;
    }

    /**
     * Prepare header string from message
     *
     * @param  Message $message
     * @return string
     */
    protected function prepareHeaders(Message $message)
    {
        $headers = clone $message->getHeaders();
        $headers->removeHeader('Bcc');
        return $headers->toString();
    }

    /**
     * Prepare body string from message
     *
     * @param  Message $message
     * @return string
     */
    protected function prepareBody(Message $message)
    {
        return $message->getBodyText();
    }

    /**
     * Lazy load the connection
     *
     * @return Protocol\Smtp
     */
    protected function lazyLoadConnection()
    {
        // Check if authentication is required and determine required class
        $options          = $this->getOptions();
        $config           = $options->getConnectionConfig();
        $config['host']   = $options->getHost();
        $config['port']   = $options->getPort();

        $this->setConnection($this->plugin($options->getConnectionClass(), $config));

        return $this->connect();
    }

    /**
     * Connect the connection, and pass it helo
     *
     * @return Protocol\Smtp
     */
    protected function connect()
    {
        if (! $this->connection instanceof Protocol\Smtp) {
            return $this->lazyLoadConnection();
        }

        $this->connection->connect();

        $this->connectedTime = time();

        $this->connection->helo($this->getOptions()->getName());

        return $this->connection;
    }
}
laminas-mail/src/Transport/Sendmail.php000064400000023047147361032560014155 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-mail for the canonical source repository
 * @copyright https://github.com/laminas/laminas-mail/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-mail/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Mail\Transport;

use Laminas\Mail;
use Laminas\Mail\Address\AddressInterface;
use Laminas\Mail\Header\HeaderInterface;
use Traversable;

/**
 * Class for sending email via the PHP internal mail() function
 */
class Sendmail implements TransportInterface
{
    /**
     * Config options for sendmail parameters
     *
     * @var string
     */
    protected $parameters;

    /**
     * Callback to use when sending mail; typically, {@link mailHandler()}
     *
     * @var callable
     */
    protected $callable;

    /**
     * error information
     * @var string
     */
    protected $errstr;

    /**
     * @var string
     */
    protected $operatingSystem;

    /**
     * Constructor.
     *
     * @param  null|string|array|Traversable $parameters OPTIONAL (Default: null)
     */
    public function __construct($parameters = null)
    {
        if ($parameters !== null) {
            $this->setParameters($parameters);
        }
        $this->callable = [$this, 'mailHandler'];
    }

    /**
     * Set sendmail parameters
     *
     * Used to populate the additional_parameters argument to mail()
     *
     * @param  null|string|array|Traversable $parameters
     * @throws \Laminas\Mail\Transport\Exception\InvalidArgumentException
     * @return Sendmail
     */
    public function setParameters($parameters)
    {
        if ($parameters === null || is_string($parameters)) {
            $this->parameters = $parameters;
            return $this;
        }

        if (! is_array($parameters) && ! $parameters instanceof Traversable) {
            throw new Exception\InvalidArgumentException(sprintf(
                '%s expects a string, array, or Traversable object of parameters; received "%s"',
                __METHOD__,
                (is_object($parameters) ? get_class($parameters) : gettype($parameters))
            ));
        }

        $string = '';
        foreach ($parameters as $param) {
            $string .= ' ' . $param;
        }

        $this->parameters = trim($string);
        return $this;
    }

    /**
     * Set callback to use for mail
     *
     * Primarily for testing purposes, but could be used to curry arguments.
     *
     * @param  callable $callable
     * @throws \Laminas\Mail\Transport\Exception\InvalidArgumentException
     * @return Sendmail
     */
    public function setCallable($callable)
    {
        if (! is_callable($callable)) {
            throw new Exception\InvalidArgumentException(sprintf(
                '%s expects a callable argument; received "%s"',
                __METHOD__,
                (is_object($callable) ? get_class($callable) : gettype($callable))
            ));
        }
        $this->callable = $callable;
        return $this;
    }

    /**
     * Send a message
     *
     * @param  \Laminas\Mail\Message $message
     */
    public function send(Mail\Message $message)
    {
        $to      = $this->prepareRecipients($message);
        $subject = $this->prepareSubject($message);
        $body    = $this->prepareBody($message);
        $headers = $this->prepareHeaders($message);
        $params  = $this->prepareParameters($message);

        // On *nix platforms, we need to replace \r\n with \n
        // sendmail is not an SMTP server, it is a unix command - it expects LF
        if (! $this->isWindowsOs()) {
            $to      = str_replace("\r\n", "\n", $to);
            $subject = str_replace("\r\n", "\n", $subject);
            $body    = str_replace("\r\n", "\n", $body);
            $headers = str_replace("\r\n", "\n", $headers);
        }

        ($this->callable)($to, $subject, $body, $headers, $params);
    }

    /**
     * Prepare recipients list
     *
     * @param  \Laminas\Mail\Message $message
     * @throws \Laminas\Mail\Transport\Exception\RuntimeException
     * @return string
     */
    protected function prepareRecipients(Mail\Message $message)
    {
        $headers = $message->getHeaders();

        $hasTo = $headers->has('to');
        if (! $hasTo && ! $headers->has('cc') && ! $headers->has('bcc')) {
            throw new Exception\RuntimeException(
                'Invalid email; contains no at least one of "To", "Cc", and "Bcc" header'
            );
        }

        if (! $hasTo) {
            return '';
        }

        /** @var Mail\Header\To $to */
        $to   = $headers->get('to');
        $list = $to->getAddressList();
        if (0 == count($list)) {
            throw new Exception\RuntimeException('Invalid "To" header; contains no addresses');
        }

        // If not on Windows, return normal string
        if (! $this->isWindowsOs()) {
            return $to->getFieldValue(HeaderInterface::FORMAT_ENCODED);
        }

        // Otherwise, return list of emails
        $addresses = [];
        foreach ($list as $address) {
            $addresses[] = $address->getEmail();
        }
        $addresses = implode(', ', $addresses);
        return $addresses;
    }

    /**
     * Prepare the subject line string
     *
     * @param  \Laminas\Mail\Message $message
     * @return string
     */
    protected function prepareSubject(Mail\Message $message)
    {
        $headers = $message->getHeaders();
        if (! $headers->has('subject')) {
            return;
        }
        $header = $headers->get('subject');
        return $header->getFieldValue(HeaderInterface::FORMAT_ENCODED);
    }

    /**
     * Prepare the body string
     *
     * @param  \Laminas\Mail\Message $message
     * @return string
     */
    protected function prepareBody(Mail\Message $message)
    {
        if (! $this->isWindowsOs()) {
            // *nix platforms can simply return the body text
            return $message->getBodyText();
        }

        // On windows, lines beginning with a full stop need to be fixed
        $text = $message->getBodyText();
        $text = str_replace("\n.", "\n..", $text);
        return $text;
    }

    /**
     * Prepare the textual representation of headers
     *
     * @param  \Laminas\Mail\Message $message
     * @return string
     */
    protected function prepareHeaders(Mail\Message $message)
    {
        // Strip the "to" and "subject" headers
        $headers = clone $message->getHeaders();
        $headers->removeHeader('To');
        $headers->removeHeader('Subject');

        /** @var Mail\Header\From $from Sanitize the From header*/
        $from = $headers->get('From');
        if ($from) {
            foreach ($from->getAddressList() as $address) {
                if (strpos($address->getEmail(), '\\"') !== false) {
                    throw new Exception\RuntimeException('Potential code injection in From header');
                }
            }
        }
        return $headers->toString();
    }

    /**
     * Prepare additional_parameters argument
     *
     * Basically, overrides the MAIL FROM envelope with either the Sender or
     * From address.
     *
     * @param  \Laminas\Mail\Message $message
     * @return string
     */
    protected function prepareParameters(Mail\Message $message)
    {
        if ($this->isWindowsOs()) {
            return;
        }

        $parameters = (string) $this->parameters;
        if (preg_match('/(^| )\-f.+/', $parameters)) {
            return $parameters;
        }

        $sender = $message->getSender();
        if ($sender instanceof AddressInterface) {
            $parameters .= ' -f' . \escapeshellarg($sender->getEmail());
            return $parameters;
        }

        $from = $message->getFrom();
        if (count($from)) {
            $from->rewind();
            $sender      = $from->current();
            $parameters .= ' -f' . \escapeshellarg($sender->getEmail());
            return $parameters;
        }

        return $parameters;
    }

    /**
     * Send mail using PHP native mail()
     *
     * @param  string $to
     * @param  string $subject
     * @param  string $message
     * @param  string $headers
     * @param  $parameters
     * @throws \Laminas\Mail\Transport\Exception\RuntimeException
     */
    public function mailHandler($to, $subject, $message, $headers, $parameters)
    {
        set_error_handler([$this, 'handleMailErrors']);
        if ($parameters === null) {
            $result = mail($to, $subject, $message, $headers);
        } else {
            $result = mail($to, $subject, $message, $headers, $parameters);
        }
        restore_error_handler();

        if ($this->errstr !== null || ! $result) {
            $errstr = $this->errstr;
            if (empty($errstr)) {
                $errstr = 'Unknown error';
            }
            throw new Exception\RuntimeException('Unable to send mail: ' . $errstr);
        }
    }

    /**
     * Temporary error handler for PHP native mail().
     *
     * @param int    $errno
     * @param string $errstr
     * @param string $errfile
     * @param string $errline
     * @param array  $errcontext
     * @return bool always true
     */
    public function handleMailErrors($errno, $errstr, $errfile = null, $errline = null, array $errcontext = null)
    {
        $this->errstr = $errstr;
        return true;
    }

    /**
     * Is this a windows OS?
     *
     * @return bool
     */
    protected function isWindowsOs()
    {
        if (! $this->operatingSystem) {
            $this->operatingSystem = strtoupper(substr(PHP_OS, 0, 3));
        }
        return ($this->operatingSystem == 'WIN');
    }
}
laminas-mail/src/Transport/TransportInterface.php000064400000001065147361032560016232 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-mail for the canonical source repository
 * @copyright https://github.com/laminas/laminas-mail/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-mail/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Mail\Transport;

use Laminas\Mail;

/**
 * Interface for mail transports
 */
interface TransportInterface
{
    /**
     * Send a mail message
     *
     * @param \Laminas\Mail\Message $message
     * @return
     */
    public function send(Mail\Message $message);
}
laminas-mail/src/Transport/InMemory.php000064400000001777147361032560014166 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-mail for the canonical source repository
 * @copyright https://github.com/laminas/laminas-mail/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-mail/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Mail\Transport;

use Laminas\Mail\Message;

/**
 * InMemory transport
 *
 * This transport will just store the message in memory.  It is helpful
 * when unit testing, or to prevent sending email when in development or
 * testing.
 */
class InMemory implements TransportInterface
{
    /**
     * @var null|Message
     */
    protected $lastMessage;

    /**
     * Takes the last message and saves it for testing.
     *
     * @param Message $message
     */
    public function send(Message $message)
    {
        $this->lastMessage = $message;
    }

    /**
     * Get the last message sent.
     *
     * @return null|Message
     */
    public function getLastMessage()
    {
        return $this->lastMessage;
    }
}
laminas-mail/src/Transport/SmtpOptions.php000064400000011332147361032560014712 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-mail for the canonical source repository
 * @copyright https://github.com/laminas/laminas-mail/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-mail/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Mail\Transport;

use Laminas\Mail\Exception;
use Laminas\Stdlib\AbstractOptions;

class SmtpOptions extends AbstractOptions
{
    /**
     * @var string Local client hostname
     */
    protected $name = 'localhost';

    /**
     * @var string
     */
    protected $connectionClass = 'smtp';

    /**
     * Connection configuration (passed to the underlying Protocol class)
     *
     * @var array
     */
    protected $connectionConfig = [];

    /**
     * @var string Remote SMTP hostname or IP
     */
    protected $host = '127.0.0.1';

    /**
     * @var int
     */
    protected $port = 25;

    /**
     * The timeout in seconds for the SMTP connection
     * (Use null to disable it)
     *
     * @var int|null
     */
    protected $connectionTimeLimit;

    /**
     * Return the local client hostname
     *
     * @return string
     */
    public function getName()
    {
        return $this->name;
    }

    /**
     * Set the local client hostname or IP
     *
     * @todo   hostname/IP validation
     * @param  string $name
     * @throws \Laminas\Mail\Exception\InvalidArgumentException
     * @return SmtpOptions
     */
    public function setName($name)
    {
        if (! is_string($name) && $name !== null) {
            throw new Exception\InvalidArgumentException(sprintf(
                'Name must be a string or null; argument of type "%s" provided',
                (is_object($name) ? get_class($name) : gettype($name))
            ));
        }
        $this->name = $name;
        return $this;
    }

    /**
     * Get connection class
     *
     * This should be either the class Laminas\Mail\Protocol\Smtp or a class
     * extending it -- typically a class in the Laminas\Mail\Protocol\Smtp\Auth
     * namespace.
     *
     * @return string
     */
    public function getConnectionClass()
    {
        return $this->connectionClass;
    }

    /**
     * Set connection class
     *
     * @param  string $connectionClass the value to be set
     * @throws \Laminas\Mail\Exception\InvalidArgumentException
     * @return SmtpOptions
     */
    public function setConnectionClass($connectionClass)
    {
        if (! is_string($connectionClass) && $connectionClass !== null) {
            throw new Exception\InvalidArgumentException(sprintf(
                'Connection class must be a string or null; argument of type "%s" provided',
                (is_object($connectionClass) ? get_class($connectionClass) : gettype($connectionClass))
            ));
        }
        $this->connectionClass = $connectionClass;
        return $this;
    }

    /**
     * Get connection configuration array
     *
     * @return array
     */
    public function getConnectionConfig()
    {
        return $this->connectionConfig;
    }

    /**
     * Set connection configuration array
     *
     * @param  array $connectionConfig
     * @return SmtpOptions
     */
    public function setConnectionConfig(array $connectionConfig)
    {
        $this->connectionConfig = $connectionConfig;
        return $this;
    }

    /**
     * Get the host name
     *
     * @return string
     */
    public function getHost()
    {
        return $this->host;
    }

    /**
     * Set the SMTP host
     *
     * @todo   hostname/IP validation
     * @param  string $host
     * @return SmtpOptions
     */
    public function setHost($host)
    {
        $this->host = (string) $host;
        return $this;
    }

    /**
     * Get the port the SMTP server runs on
     *
     * @return int
     */
    public function getPort()
    {
        return $this->port;
    }

    /**
     * Set the port the SMTP server runs on
     *
     * @param  int $port
     * @throws \Laminas\Mail\Exception\InvalidArgumentException
     * @return SmtpOptions
     */
    public function setPort($port)
    {
        $port = (int) $port;
        if ($port < 1) {
            throw new Exception\InvalidArgumentException(sprintf(
                'Port must be greater than 1; received "%d"',
                $port
            ));
        }
        $this->port = $port;
        return $this;
    }

    /**
     * @return int|null
     */
    public function getConnectionTimeLimit()
    {
        return $this->connectionTimeLimit;
    }

    /**
     * @param int|null $seconds
     * @return self
     */
    public function setConnectionTimeLimit($seconds)
    {
        $this->connectionTimeLimit = $seconds === null
            ? null
            : (int) $seconds;

        return $this;
    }
}
laminas-mail/src/Transport/FileOptions.php000064400000004551147361032560014653 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-mail for the canonical source repository
 * @copyright https://github.com/laminas/laminas-mail/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-mail/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Mail\Transport;

use Laminas\Mail\Exception;
use Laminas\Stdlib\AbstractOptions;

class FileOptions extends AbstractOptions
{
    /**
     * @var string Path to stored mail files
     */
    protected $path;

    /**
     * @var callable
     */
    protected $callback;

    /**
     * Set path to stored mail files
     *
     * @param  string $path
     * @throws \Laminas\Mail\Exception\InvalidArgumentException
     * @return FileOptions
     */
    public function setPath($path)
    {
        if (! is_dir($path) || ! is_writable($path)) {
            throw new Exception\InvalidArgumentException(sprintf(
                '%s expects a valid path in which to write mail files; received "%s"',
                __METHOD__,
                (string) $path
            ));
        }
        $this->path = $path;
        return $this;
    }

    /**
     * Get path
     *
     * If none is set, uses value from sys_get_temp_dir()
     *
     * @return string
     */
    public function getPath()
    {
        if (null === $this->path) {
            $this->setPath(sys_get_temp_dir());
        }
        return $this->path;
    }

    /**
     * Set callback used to generate a file name
     *
     * @param  callable $callback
     * @throws \Laminas\Mail\Exception\InvalidArgumentException
     * @return FileOptions
     */
    public function setCallback($callback)
    {
        if (! is_callable($callback)) {
            throw new Exception\InvalidArgumentException(sprintf(
                '%s expects a valid callback; received "%s"',
                __METHOD__,
                (is_object($callback) ? get_class($callback) : gettype($callback))
            ));
        }
        $this->callback = $callback;
        return $this;
    }

    /**
     * Get callback used to generate a file name
     *
     * @return callable
     */
    public function getCallback()
    {
        if (null === $this->callback) {
            $this->setCallback(function () {
                return 'LaminasMail_' . time() . '_' . mt_rand() . '.eml';
            });
        }
        return $this->callback;
    }
}
laminas-mail/src/Transport/Envelope.php000064400000002072147361032560014171 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-mail for the canonical source repository
 * @copyright https://github.com/laminas/laminas-mail/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-mail/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Mail\Transport;

use Laminas\Stdlib\AbstractOptions;

class Envelope extends AbstractOptions
{
    /**
     * @var string|null
     */
    protected $from;

    /**
     * @var string|null
     */
    protected $to;

    /**
     * Get MAIL FROM
     *
     * @return string
     */
    public function getFrom()
    {
        return $this->from;
    }

    /**
     * Set MAIL FROM
     *
     * @param  string $from
     */
    public function setFrom($from)
    {
        $this->from = (string) $from;
    }

    /**
     * Get RCPT TO
     *
     * @return string|null
     */
    public function getTo()
    {
        return $this->to;
    }

    /**
     * Set RCPT TO
     *
     * @param  string $to
     */
    public function setTo($to)
    {
        $this->to = $to;
    }
}
laminas-mail/src/Transport/Exception/ExceptionInterface.php000064400000000673147361032560020136 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-mail for the canonical source repository
 * @copyright https://github.com/laminas/laminas-mail/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-mail/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Mail\Transport\Exception;

use Laminas\Mail\Exception\ExceptionInterface as MailException;

interface ExceptionInterface extends MailException
{
}
laminas-mail/src/Transport/Exception/DomainException.php000064400000000765147361032560017447 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-mail for the canonical source repository
 * @copyright https://github.com/laminas/laminas-mail/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-mail/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Mail\Transport\Exception;

use Laminas\Mail\Exception;

/**
 * Exception for Laminas\Mail\Transport component.
 */
class DomainException extends Exception\DomainException implements ExceptionInterface
{
}
laminas-mail/src/Transport/Exception/InvalidArgumentException.php000064400000000775147361032560021332 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-mail for the canonical source repository
 * @copyright https://github.com/laminas/laminas-mail/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-mail/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Mail\Transport\Exception;

use Laminas\Mail\Exception;

/**
 * Exception for Laminas\Mail component.
 */
class InvalidArgumentException extends Exception\InvalidArgumentException implements ExceptionInterface
{
}
laminas-mail/src/Transport/Exception/RuntimeException.php000064400000000755147361032560017662 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-mail for the canonical source repository
 * @copyright https://github.com/laminas/laminas-mail/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-mail/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Mail\Transport\Exception;

use Laminas\Mail\Exception;

/**
 * Exception for Laminas\Mail component.
 */
class RuntimeException extends Exception\RuntimeException implements ExceptionInterface
{
}
laminas-mail/src/Transport/Factory.php000064400000004757147361032560014037 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-mail for the canonical source repository
 * @copyright https://github.com/laminas/laminas-mail/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-mail/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Mail\Transport;

use Laminas\Stdlib\ArrayUtils;
use Traversable;

abstract class Factory
{
    /**
     * @var array Known transport types
     */
    protected static $classMap = [
        'file'      => File::class,
        'inmemory'  => InMemory::class,
        'memory'    => InMemory::class,
        'null'      => InMemory::class,
        'sendmail'  => Sendmail::class,
        'smtp'      => Smtp::class,
    ];

    /**
     * @param array $spec
     * @return TransportInterface
     * @throws Exception\InvalidArgumentException
     * @throws Exception\DomainException
     */
    public static function create($spec = [])
    {
        if ($spec instanceof Traversable) {
            $spec = ArrayUtils::iteratorToArray($spec);
        }

        if (! is_array($spec)) {
            throw new Exception\InvalidArgumentException(sprintf(
                '%s expects an array or Traversable argument; received "%s"',
                __METHOD__,
                (is_object($spec) ? get_class($spec) : gettype($spec))
            ));
        }

        $type = $spec['type'] ?? 'sendmail';

        $normalizedType = strtolower($type);

        if (isset(static::$classMap[$normalizedType])) {
            $type = static::$classMap[$normalizedType];
        }

        if (! class_exists($type)) {
            throw new Exception\DomainException(sprintf(
                '%s expects the "type" attribute to resolve to an existing class; received "%s"',
                __METHOD__,
                $type
            ));
        }

        $transport = new $type();

        if (! $transport instanceof TransportInterface) {
            throw new Exception\DomainException(sprintf(
                '%s expects the "type" attribute to resolve to a valid %s instance; received "%s"',
                __METHOD__,
                TransportInterface::class,
                $type
            ));
        }

        if ($transport instanceof Smtp && isset($spec['options'])) {
            $transport->setOptions(new SmtpOptions($spec['options']));
        }

        if ($transport instanceof File && isset($spec['options'])) {
            $transport->setOptions(new FileOptions($spec['options']));
        }

        return $transport;
    }
}
laminas-mail/src/Transport/File.php000064400000004163147361032560013276 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-mail for the canonical source repository
 * @copyright https://github.com/laminas/laminas-mail/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-mail/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Mail\Transport;

use Laminas\Mail\Message;

/**
 * File transport
 *
 * Class for saving outgoing emails in filesystem
 */
class File implements TransportInterface
{
    /**
     * @var FileOptions
     */
    protected $options;

    /**
     * Last file written to
     *
     * @var string
     */
    protected $lastFile;

    /**
     * Constructor
     *
     * @param  null|FileOptions $options OPTIONAL (Default: null)
     */
    public function __construct(FileOptions $options = null)
    {
        if (! $options instanceof FileOptions) {
            $options = new FileOptions();
        }
        $this->setOptions($options);
    }

    /**
     * @return FileOptions
     */
    public function getOptions()
    {
        return $this->options;
    }

    /**
     * Sets options
     *
     * @param  FileOptions $options
     */
    public function setOptions(FileOptions $options)
    {
        $this->options = $options;
    }

    /**
     * Saves e-mail message to a file
     *
     * @param Message $message
     * @throws Exception\RuntimeException on not writable target directory or
     * on file_put_contents() failure
     */
    public function send(Message $message)
    {
        $options  = $this->options;
        $filename = $options->getCallback()($this);
        $file     = $options->getPath() . DIRECTORY_SEPARATOR . $filename;
        $email    = $message->toString();

        if (false === file_put_contents($file, $email)) {
            throw new Exception\RuntimeException(sprintf(
                'Unable to write mail to file (directory "%s")',
                $options->getPath()
            ));
        }

        $this->lastFile = $file;
    }

    /**
     * Get the name of the last file written to
     *
     * @return string
     */
    public function getLastFile()
    {
        return $this->lastFile;
    }
}
laminas-mail/src/Protocol/Imap.php000064400000064465147361032560013125 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-mail for the canonical source repository
 * @copyright https://github.com/laminas/laminas-mail/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-mail/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Mail\Protocol;

class Imap
{
    use ProtocolTrait;

    /**
     * Default timeout in seconds for initiating session
     */
    public const TIMEOUT_CONNECTION = 30;

    /**
     * @var null|resource
     */
    protected $socket;

    /**
     * counter for request tag
     * @var int
     */
    protected $tagCount = 0;

    /**
     * Public constructor
     *
     * @param  string       $host           hostname or IP address of IMAP server, if given connect() is called
     * @param  int|null     $port           port of IMAP server, null for default (143 or 993 for ssl)
     * @param  string|bool  $ssl            use ssl? 'SSL', 'TLS' or false
     * @param  bool         $novalidatecert set to true to skip SSL certificate validation
     * @throws \Laminas\Mail\Protocol\Exception\ExceptionInterface
     */
    public function __construct($host = '', $port = null, $ssl = false, $novalidatecert = false)
    {
        $this->setNoValidateCert($novalidatecert);

        if ($host) {
            $this->connect($host, $port, $ssl);
        }
    }

    /**
     * Public destructor
     */
    public function __destruct()
    {
        $this->logout();
    }

    /**
     * Open connection to IMAP server
     *
     * @param  string      $host  hostname or IP address of IMAP server
     * @param  int|null    $port  of IMAP server, default is 143 (993 for ssl)
     * @param  string|bool $ssl   use 'SSL', 'TLS' or false
     * @throws Exception\RuntimeException
     * @return void
     */
    public function connect($host, $port = null, $ssl = false)
    {
        $transport = 'tcp';
        $isTls = false;

        if ($ssl) {
            $ssl = strtolower($ssl);
        }

        switch ($ssl) {
            case 'ssl':
                $transport = 'ssl';
                if (! $port) {
                    $port = 993;
                }
                break;
            case 'tls':
                $isTls = true;
                // break intentionally omitted
            default:
                if (! $port) {
                    $port = 143;
                }
        }

        $this->socket = $this->setupSocket($transport, $host, $port, self::TIMEOUT_CONNECTION);

        if (! $this->assumedNextLine('* OK')) {
            throw new Exception\RuntimeException('host doesn\'t allow connection');
        }

        if ($isTls) {
            $result = $this->requestAndResponse('STARTTLS');
            $result = $result && stream_socket_enable_crypto($this->socket, true, $this->getCryptoMethod());
            if (! $result) {
                throw new Exception\RuntimeException('cannot enable TLS');
            }
        }
    }

    /**
     * get the next line from socket with error checking, but nothing else
     *
     * @throws Exception\RuntimeException
     * @return string next line
     */
    protected function nextLine()
    {
        $line = fgets($this->socket);
        if ($line === false) {
            throw new Exception\RuntimeException('cannot read - connection closed?');
        }

        return $line;
    }

    /**
     * get next line and assume it starts with $start. some requests give a simple
     * feedback so we can quickly check if we can go on.
     *
     * @param  string $start the first bytes we assume to be in the next line
     * @return bool line starts with $start
     */
    protected function assumedNextLine($start)
    {
        $line = $this->nextLine();
        return strpos($line, $start) === 0;
    }

    /**
     * get next line and split the tag. that's the normal case for a response line
     *
     * @param  string $tag tag of line is returned by reference
     * @return string next line
     */
    protected function nextTaggedLine(&$tag)
    {
        $line = $this->nextLine();

        // separate tag from line
        list($tag, $line) = explode(' ', $line, 2);

        return $line;
    }

    /**
     * split a given line in tokens. a token is literal of any form or a list
     *
     * @param  string $line line to decode
     * @return array tokens, literals are returned as string, lists as array
     */
    protected function decodeLine($line)
    {
        $tokens = [];
        $stack = [];

        /*
            We start to decode the response here. The understood tokens are:
                literal
                "literal" or also "lit\\er\"al"
                {bytes}<NL>literal
                (literals*)
            All tokens are returned in an array. Literals in braces (the last understood
            token in the list) are returned as an array of tokens. I.e. the following response:
                "foo" baz {3}<NL>bar ("f\\\"oo" bar)
            would be returned as:
                array('foo', 'baz', 'bar', array('f\\\"oo', 'bar'));

            // TODO: add handling of '[' and ']' to parser for easier handling of response text
        */
        //  replace any trailing <NL> including spaces with a single space
        $line = rtrim($line) . ' ';
        while (($pos = strpos($line, ' ')) !== false) {
            $token = substr($line, 0, $pos);
            if (! strlen($token)) {
                continue;
            }
            while ($token[0] == '(') {
                array_push($stack, $tokens);
                $tokens = [];
                $token = substr($token, 1);
            }
            if ($token[0] == '"') {
                if (preg_match('%^\(*"((.|\\\\|\\")*?)" *%', $line, $matches)) {
                    $tokens[] = $matches[1];
                    $line = substr($line, strlen($matches[0]));
                    continue;
                }
            }
            if ($token[0] == '{') {
                $endPos = strpos($token, '}');
                $chars = substr($token, 1, $endPos - 1);
                if (is_numeric($chars)) {
                    $token = '';
                    while (strlen($token) < $chars) {
                        $token .= $this->nextLine();
                    }
                    $line = '';
                    if (strlen($token) > $chars) {
                        $line = substr($token, $chars);
                        $token = substr($token, 0, $chars);
                    } else {
                        $line .= $this->nextLine();
                    }
                    $tokens[] = $token;
                    $line = trim($line) . ' ';
                    continue;
                }
            }
            if ($stack && $token[strlen($token) - 1] == ')') {
                // closing braces are not separated by spaces, so we need to count them
                $braces = strlen($token);
                $token = rtrim($token, ')');
                // only count braces if more than one
                $braces -= strlen($token) + 1;
                // only add if token had more than just closing braces
                if (rtrim($token) != '') {
                    $tokens[] = rtrim($token);
                }
                $token = $tokens;
                $tokens = array_pop($stack);
                // special handline if more than one closing brace
                while ($braces-- > 0) {
                    $tokens[] = $token;
                    $token = $tokens;
                    $tokens = array_pop($stack);
                }
            }
            $tokens[] = $token;
            $line = substr($line, $pos + 1);
        }

        // maybe the server forgot to send some closing braces
        while ($stack) {
            $child = $tokens;
            $tokens = array_pop($stack);
            $tokens[] = $child;
        }

        return $tokens;
    }

    /**
     * read a response "line" (could also be more than one real line if response has {..}<NL>)
     * and do a simple decode
     *
     * @param  array|string  $tokens    decoded tokens are returned by reference, if $dontParse
     *                                  is true the unparsed line is returned here
     * @param  string        $wantedTag check for this tag for response code. Default '*' is
     *                                  continuation tag.
     * @param  bool          $dontParse if true only the unparsed line is returned $tokens
     * @return bool if returned tag matches wanted tag
     */
    public function readLine(&$tokens = [], $wantedTag = '*', $dontParse = false)
    {
        $tag  = null;                         // define $tag variable before first use
        $line = $this->nextTaggedLine($tag); // get next tag
        if (! $dontParse) {
            $tokens = $this->decodeLine($line);
        } else {
            $tokens = $line;
        }

        // if tag is wanted tag we might be at the end of a multiline response
        return $tag == $wantedTag;
    }

    /**
     * read all lines of response until given tag is found (last line of response)
     *
     * @param  string       $tag       the tag of your request
     * @param  bool         $dontParse if true every line is returned unparsed instead of
     *                                 the decoded tokens
     * @return null|bool|array tokens if success, false if error, null if bad request
     */
    public function readResponse($tag, $dontParse = false)
    {
        $lines = [];
        $tokens = null; // define $tokens variable before first use
        while (! $this->readLine($tokens, $tag, $dontParse)) {
            $lines[] = $tokens;
        }

        if ($dontParse) {
            // last to chars are still needed for response code
            $tokens = [substr($tokens, 0, 2)];
        }

        // last line has response code
        if ($tokens[0] == 'OK') {
            return $lines ? $lines : true;
        } elseif ($tokens[0] == 'NO') {
            return false;
        }
    }

    /**
     * send a request
     *
     * @param  string $command your request command
     * @param  array  $tokens  additional parameters to command, use escapeString() to prepare
     * @param  string $tag     provide a tag otherwise an autogenerated is returned
     * @throws Exception\RuntimeException
     */
    public function sendRequest($command, $tokens = [], &$tag = null)
    {
        if (! $tag) {
            ++$this->tagCount;
            $tag = 'TAG' . $this->tagCount;
        }

        $line = $tag . ' ' . $command;

        foreach ($tokens as $token) {
            if (is_array($token)) {
                if (fwrite($this->socket, $line . ' ' . $token[0] . "\r\n") === false) {
                    throw new Exception\RuntimeException('cannot write - connection closed?');
                }
                if (! $this->assumedNextLine('+ ')) {
                    throw new Exception\RuntimeException('cannot send literal string');
                }
                $line = $token[1];
            } else {
                $line .= ' ' . $token;
            }
        }

        if (fwrite($this->socket, $line . "\r\n") === false) {
            throw new Exception\RuntimeException('cannot write - connection closed?');
        }
    }

    /**
     * send a request and get response at once
     *
     * @param  string $command   command as in sendRequest()
     * @param  array  $tokens    parameters as in sendRequest()
     * @param  bool   $dontParse if true unparsed lines are returned instead of tokens
     * @return mixed response as in readResponse()
     */
    public function requestAndResponse($command, $tokens = [], $dontParse = false)
    {
        $tag = null; // define $tag variable before first use
        $this->sendRequest($command, $tokens, $tag);
        $response = $this->readResponse($tag, $dontParse);

        return $response;
    }

    /**
     * escape one or more literals i.e. for sendRequest
     *
     * @param  string|array $string the literal/-s
     * @return string|array escape literals, literals with newline ar returned
     *                      as array('{size}', 'string');
     */
    public function escapeString($string)
    {
        if (func_num_args() < 2) {
            if (strpos($string, "\n") !== false) {
                return ['{' . strlen($string) . '}', $string];
            }

            return '"' . str_replace(['\\', '"'], ['\\\\', '\\"'], $string) . '"';
        }

        $result = [];
        foreach (func_get_args() as $string) {
            $result[] = $this->escapeString($string);
        }
        return $result;
    }

    /**
     * escape a list with literals or lists
     *
     * @param  array $list list with literals or lists as PHP array
     * @return string escaped list for imap
     */
    public function escapeList($list)
    {
        $result = [];
        foreach ($list as $v) {
            if (! is_array($v)) {
                $result[] = $v;
                continue;
            }
            $result[] = $this->escapeList($v);
        }
        return '(' . implode(' ', $result) . ')';
    }

    /**
     * Login to IMAP server.
     *
     * @param  string $user      username
     * @param  string $password  password
     * @return bool success
     */
    public function login($user, $password)
    {
        return $this->requestAndResponse('LOGIN', $this->escapeString($user, $password), true);
    }

    /**
     * logout of imap server
     *
     * @return bool success
     */
    public function logout()
    {
        $result = false;
        if ($this->socket) {
            try {
                $result = $this->requestAndResponse('LOGOUT', [], true);
            } catch (Exception\ExceptionInterface $e) {
                // ignoring exception
            }
            fclose($this->socket);
            $this->socket = null;
        }
        return $result;
    }

    /**
     * Get capabilities from IMAP server
     *
     * @return array list of capabilities
     * @throws \Laminas\Mail\Protocol\Exception\ExceptionInterface
     */
    public function capability()
    {
        $response = $this->requestAndResponse('CAPABILITY');

        if (! $response) {
            return [];
        }

        $capabilities = [];
        foreach ($response as $line) {
            $capabilities = array_merge($capabilities, $line);
        }
        return $capabilities;
    }

    /**
     * Examine and select have the same response. The common code for both
     * is in this method
     *
     * @param  string $command can be 'EXAMINE' or 'SELECT' and this is used as command
     * @param  string $box which folder to change to or examine
     * @return bool|array false if error, array with returned information
     *                    otherwise (flags, exists, recent, uidvalidity)
     * @throws \Laminas\Mail\Protocol\Exception\ExceptionInterface
     */
    public function examineOrSelect($command = 'EXAMINE', $box = 'INBOX')
    {
        $tag = null; // define $tag variable before first use
        $this->sendRequest($command, [$this->escapeString($box)], $tag);

        $result = [];
        $tokens = null; // define $tokens variable before first use
        while (! $this->readLine($tokens, $tag)) {
            if ($tokens[0] == 'FLAGS') {
                array_shift($tokens);
                $result['flags'] = $tokens;
                continue;
            }
            switch ($tokens[1]) {
                case 'EXISTS':
                case 'RECENT':
                    $result[strtolower($tokens[1])] = $tokens[0];
                    break;
                case '[UIDVALIDITY':
                    $result['uidvalidity'] = (int) $tokens[2];
                    break;
                default:
                    // ignore
            }
        }

        if ($tokens[0] != 'OK') {
            return false;
        }
        return $result;
    }

    /**
     * change folder
     *
     * @param  string $box change to this folder
     * @return bool|array see examineOrselect()
     * @throws \Laminas\Mail\Protocol\Exception\ExceptionInterface
     */
    public function select($box = 'INBOX')
    {
        return $this->examineOrSelect('SELECT', $box);
    }

    /**
     * examine folder
     *
     * @param  string $box examine this folder
     * @return bool|array see examineOrselect()
     * @throws \Laminas\Mail\Protocol\Exception\ExceptionInterface
     */
    public function examine($box = 'INBOX')
    {
        return $this->examineOrSelect('EXAMINE', $box);
    }

    /**
     * fetch one or more items of one or more messages
     *
     * @param  string|array $items items to fetch from message(s) as string (if only one item)
     *                             or array of strings
     * @param  int|array    $from  message for items or start message if $to !== null
     * @param  int|null     $to    if null only one message ($from) is fetched, else it's the
     *                             last message, INF means last message available
     * @param  bool         $uid   set to true if passing a unique id
     * @throws Exception\RuntimeException
     * @return string|array if only one item of one message is fetched it's returned as string
     *                      if items of one message are fetched it's returned as (name => value)
     *                      if one items of messages are fetched it's returned as (msgno => value)
     *                      if items of messages are fetched it's returned as (msgno => (name => value))
     */
    public function fetch($items, $from, $to = null, $uid = false)
    {
        if (is_array($from)) {
            $set = implode(',', $from);
        } elseif ($to === null) {
            $set = (int) $from;
        } elseif ($to === INF) {
            $set = (int) $from . ':*';
        } else {
            $set = (int) $from . ':' . (int) $to;
        }

        $items = (array) $items;
        $itemList = $this->escapeList($items);

        $tag = null;  // define $tag variable before first use
        $this->sendRequest(($uid ? 'UID ' : '') . 'FETCH', [$set, $itemList], $tag);

        $result = [];
        $tokens = null; // define $tokens variable before first use
        while (! $this->readLine($tokens, $tag)) {
            // ignore other responses
            if ($tokens[1] != 'FETCH') {
                continue;
            }

            // find array key of UID value; try the last elements, or search for it
            if ($uid) {
                $count = count($tokens[2]);
                if ($tokens[2][$count - 2] == 'UID') {
                    $uidKey = $count - 1;
                } else {
                    $uidKey = array_search('UID', $tokens[2]) + 1;
                }
            }

            // ignore other messages
            if ($to === null && ! is_array($from) && ($uid ? $tokens[2][$uidKey] != $from : $tokens[0] != $from)) {
                continue;
            }

            // if we only want one item we return that one directly
            if (count($items) == 1) {
                if ($tokens[2][0] == $items[0]) {
                    $data = $tokens[2][1];
                } elseif ($uid && $tokens[2][2] == $items[0]) {
                    $data = $tokens[2][3];
                } else {
                    // maybe the server send an other field we didn't wanted
                    $count = count($tokens[2]);
                    // we start with 2, because 0 was already checked
                    for ($i = 2; $i < $count; $i += 2) {
                        if ($tokens[2][$i] != $items[0]) {
                            continue;
                        }
                        $data = $tokens[2][$i + 1];
                        break;
                    }
                }
            } else {
                $data = [];
                while (key($tokens[2]) !== null) {
                    $data[current($tokens[2])] = next($tokens[2]);
                    next($tokens[2]);
                }
            }

            // if we want only one message we can ignore everything else and just return
            if ($to === null && ! is_array($from) && ($uid ? $tokens[2][$uidKey] == $from : $tokens[0] == $from)) {
                // we still need to read all lines
                while (! $this->readLine($tokens, $tag)) {
                }
                return $data;
            }
            $result[$tokens[0]] = $data;
        }

        if ($to === null && ! is_array($from)) {
            throw new Exception\RuntimeException('the single id was not found in response');
        }

        return $result;
    }

    /**
     * get mailbox list
     *
     * this method can't be named after the IMAP command 'LIST', as list is a reserved keyword
     *
     * @param  string $reference mailbox reference for list
     * @param  string $mailbox   mailbox name match with wildcards
     * @return array mailboxes that matched $mailbox as array(globalName => array('delim' => .., 'flags' => ..))
     * @throws \Laminas\Mail\Protocol\Exception\ExceptionInterface
     */
    public function listMailbox($reference = '', $mailbox = '*')
    {
        $result = [];
        $list = $this->requestAndResponse('LIST', $this->escapeString($reference, $mailbox));
        if (! $list || $list === true) {
            return $result;
        }

        foreach ($list as $item) {
            if (count($item) != 4 || $item[0] != 'LIST') {
                continue;
            }
            $result[$item[3]] = ['delim' => $item[2], 'flags' => $item[1]];
        }

        return $result;
    }

    /**
     * set flags
     *
     * @param  array       $flags  flags to set, add or remove - see $mode
     * @param  int         $from   message for items or start message if $to !== null
     * @param  int|null    $to     if null only one message ($from) is fetched, else it's the
     *                             last message, INF means last message available
     * @param  string|null $mode   '+' to add flags, '-' to remove flags, everything else sets the flags as given
     * @param  bool        $silent if false the return values are the new flags for the wanted messages
     * @return bool|array new flags if $silent is false, else true or false depending on success
     * @throws \Laminas\Mail\Protocol\Exception\ExceptionInterface
     */
    public function store(array $flags, $from, $to = null, $mode = null, $silent = true)
    {
        $item = 'FLAGS';
        if ($mode == '+' || $mode == '-') {
            $item = $mode . $item;
        }
        if ($silent) {
            $item .= '.SILENT';
        }

        $flags = $this->escapeList($flags);
        $set = (int) $from;
        if ($to !== null) {
            $set .= ':' . ($to == INF ? '*' : (int) $to);
        }

        $result = $this->requestAndResponse('STORE', [$set, $item, $flags], $silent);

        if ($silent) {
            return (bool) $result;
        }

        $tokens = $result;
        $result = [];
        foreach ($tokens as $token) {
            if ($token[1] != 'FETCH' || $token[2][0] != 'FLAGS') {
                continue;
            }
            $result[$token[0]] = $token[2][1];
        }

        return $result;
    }

    /**
     * append a new message to given folder
     *
     * @param string $folder  name of target folder
     * @param string $message full message content
     * @param array  $flags   flags for new message
     * @param string $date    date for new message
     * @return bool success
     * @throws \Laminas\Mail\Protocol\Exception\ExceptionInterface
     */
    public function append($folder, $message, $flags = null, $date = null)
    {
        $tokens = [];
        $tokens[] = $this->escapeString($folder);
        if ($flags !== null) {
            $tokens[] = $this->escapeList($flags);
        }
        if ($date !== null) {
            $tokens[] = $this->escapeString($date);
        }
        $tokens[] = $this->escapeString($message);

        return $this->requestAndResponse('APPEND', $tokens, true);
    }

    /**
     * copy message set from current folder to other folder
     *
     * @param string   $folder destination folder
     * @param $from
     * @param int|null $to     if null only one message ($from) is fetched, else it's the
     *                         last message, INF means last message available
     * @return bool success
     */
    public function copy($folder, $from, $to = null)
    {
        $set = (int) $from;
        if ($to !== null) {
            $set .= ':' . ($to == INF ? '*' : (int) $to);
        }

        return $this->requestAndResponse('COPY', [$set, $this->escapeString($folder)], true);
    }

    /**
     * create a new folder (and parent folders if needed)
     *
     * @param string $folder folder name
     * @return bool success
     */
    public function create($folder)
    {
        return $this->requestAndResponse('CREATE', [$this->escapeString($folder)], true);
    }

    /**
     * rename an existing folder
     *
     * @param string $old old name
     * @param string $new new name
     * @return bool success
     */
    public function rename($old, $new)
    {
        return $this->requestAndResponse('RENAME', $this->escapeString($old, $new), true);
    }

    /**
     * remove a folder
     *
     * @param string $folder folder name
     * @return bool success
     */
    public function delete($folder)
    {
        return $this->requestAndResponse('DELETE', [$this->escapeString($folder)], true);
    }

    /**
     * subscribe to a folder
     *
     * @param string $folder folder name
     * @return bool success
     */
    public function subscribe($folder)
    {
        return $this->requestAndResponse('SUBSCRIBE', [$this->escapeString($folder)], true);
    }

    /**
     * permanently remove messages
     *
     * @return bool success
     */
    public function expunge()
    {
        // TODO: parse response?
        return $this->requestAndResponse('EXPUNGE');
    }

    /**
     * send noop
     *
     * @return bool success
     */
    public function noop()
    {
        // TODO: parse response
        return $this->requestAndResponse('NOOP');
    }

    /**
     * do a search request
     *
     * This method is currently marked as internal as the API might change and is not
     * safe if you don't take precautions.
     *
     * @param array $params
     * @return array message ids
     */
    public function search(array $params)
    {
        $response = $this->requestAndResponse('SEARCH', $params);
        if (! $response) {
            return $response;
        }

        foreach ($response as $ids) {
            if ($ids[0] == 'SEARCH') {
                array_shift($ids);
                return $ids;
            }
        }
        return [];
    }
}
laminas-mail/src/Protocol/Smtp.php000064400000034630147361032560013151 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-mail for the canonical source repository
 * @copyright https://github.com/laminas/laminas-mail/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-mail/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Mail\Protocol;

use Generator;
use Laminas\Mail\Headers;

/**
 * SMTP implementation of Laminas\Mail\Protocol\AbstractProtocol
 *
 * Minimum implementation according to RFC2821: EHLO, MAIL FROM, RCPT TO, DATA,
 * RSET, NOOP, QUIT
 */
class Smtp extends AbstractProtocol
{
    use ProtocolTrait;

    /**
     * RFC 5322 section-2.2.3 specifies maximum of 998 bytes per line.
     * This may not be exceeded.
     * @see https://tools.ietf.org/html/rfc5322#section-2.2.3
     */
    public const SMTP_LINE_LIMIT = 998;

    /**
     * The transport method for the socket
     *
     * @var string
     */
    protected $transport = 'tcp';

    /**
     * Indicates that a session is requested to be secure
     *
     * @var string
     */
    protected $secure;

    /**
     * Indicates an smtp session has been started by the HELO command
     *
     * @var bool
     */
    protected $sess = false;

    /**
     * Indicates an smtp AUTH has been issued and authenticated
     *
     * @var bool
     */
    protected $auth = false;

    /**
     * Indicates a MAIL command has been issued
     *
     * @var bool
     */
    protected $mail = false;

    /**
     * Indicates one or more RCTP commands have been issued
     *
     * @var bool
     */
    protected $rcpt = false;

    /**
     * Indicates that DATA has been issued and sent
     *
     * @var bool
     */
    protected $data = null;

    /**
     * Whether or not send QUIT command
     *
     * @var bool
     */
    protected $useCompleteQuit = true;

    /**
     * Constructor.
     *
     * The first argument may be an array of all options. If so, it must include
     * the 'host' and 'port' keys in order to ensure that all required values
     * are present.
     *
     * @param  string|array $host
     * @param  null|int $port
     * @param  null|array   $config
     * @throws Exception\InvalidArgumentException
     */
    public function __construct($host = '127.0.0.1', $port = null, array $config = null)
    {
        // Did we receive a configuration array?
        if (is_array($host)) {
            // Merge config array with principal array, if provided
            if (is_array($config)) {
                $config = array_replace_recursive($host, $config);
            } else {
                $config = $host;
            }

            // Look for a host key; if none found, use default value
            if (isset($config['host'])) {
                $host = $config['host'];
            } else {
                $host = '127.0.0.1';
            }

            // Look for a port key; if none found, use default value
            if (isset($config['port'])) {
                $port = $config['port'];
            } else {
                $port = null;
            }
        }

        // If we don't have a config array, initialize it
        if (null === $config) {
            $config = [];
        }

        if (isset($config['ssl'])) {
            switch (strtolower($config['ssl'])) {
                case 'tls':
                    $this->secure = 'tls';
                    break;

                case 'ssl':
                    $this->transport = 'ssl';
                    $this->secure = 'ssl';
                    if ($port === null) {
                        $port = 465;
                    }
                    break;

                case '':
                    // fall-through
                case 'none':
                    break;

                default:
                    throw new Exception\InvalidArgumentException($config['ssl'] . ' is unsupported SSL type');
            }
        }

        if (array_key_exists('use_complete_quit', $config)) {
            $this->setUseCompleteQuit($config['use_complete_quit']);
        }

        // If no port has been specified then check the master PHP ini file. Defaults to 25 if the ini setting is null.
        if ($port === null) {
            if (($port = ini_get('smtp_port')) == '') {
                $port = 25;
            }
        }

        if (array_key_exists('novalidatecert', $config)) {
            $this->setNoValidateCert($config['novalidatecert']);
        }

        parent::__construct($host, $port);
    }

    /**
     * Set whether or not send QUIT command
     *
     * @param bool $useCompleteQuit use complete quit
     * @return bool
     */
    public function setUseCompleteQuit($useCompleteQuit)
    {
        return $this->useCompleteQuit = (bool) $useCompleteQuit;
    }

    /**
     * Read $data as lines terminated by "\n"
     *
     * @param string $data
     * @param int $chunkSize
     * @return Generator|string[]
     * @author Elan Ruusamäe <glen@pld-linux.org>
     */
    private static function chunkedReader(string $data, int $chunkSize = 4096): Generator
    {
        if (($fp = fopen("php://temp", "r+")) === false) {
            throw new Exception\RuntimeException('cannot fopen');
        }
        if (fwrite($fp, $data) === false) {
            throw new Exception\RuntimeException('cannot fwrite');
        }
        rewind($fp);

        $line = null;
        while (($buffer = fgets($fp, $chunkSize)) !== false) {
            $line .= $buffer;

            // This is optimization to avoid calling length() in a loop.
            // We need to match a condition that is when:
            // 1. maximum was read from fgets, which is $chunkSize-1
            // 2. last byte of the buffer is not \n
            //
            // to access last byte of buffer, we can do
            // - $buffer[strlen($buffer)-1]
            // and when maximum is read from fgets, then:
            // - strlen($buffer) === $chunkSize-1
            // - strlen($buffer)-1 === $chunkSize-2
            // which means this is also true:
            // - $buffer[strlen($buffer)-1] === $buffer[$chunkSize-2]
            //
            // the null coalesce works, as string offset can never be null
            $lastByte = $buffer[$chunkSize - 2] ?? null;

            // partial read, continue loop to read again to complete the line
            // compare \n first as that's usually false
            if ($lastByte !== "\n" && $lastByte !== null) {
                continue;
            }

            yield $line;
            $line = null;
        }

        if ($line !== null) {
            yield $line;
        }

        fclose($fp);
    }

    /**
     * Whether or not send QUIT command
     *
     * @return bool
     */
    public function useCompleteQuit()
    {
        return $this->useCompleteQuit;
    }

    /**
     * Connect to the server with the parameters given in the constructor.
     *
     * @return bool
     */
    public function connect()
    {
        $this->socket = $this->setupSocket(
            $this->transport,
            $this->host,
            $this->port,
            self::TIMEOUT_CONNECTION
        );
        return true;
    }

    /**
     * Initiate HELO/EHLO sequence and set flag to indicate valid smtp session
     *
     * @param  string $host The client hostname or IP address (default: 127.0.0.1)
     * @throws Exception\RuntimeException
     */
    public function helo($host = '127.0.0.1')
    {
        // Respect RFC 2821 and disallow HELO attempts if session is already initiated.
        if ($this->sess === true) {
            throw new Exception\RuntimeException('Cannot issue HELO to existing session');
        }

        // Validate client hostname
        if (! $this->validHost->isValid($host)) {
            throw new Exception\RuntimeException(implode(', ', $this->validHost->getMessages()));
        }

        // Initiate helo sequence
        $this->_expect(220, 300); // Timeout set for 5 minutes as per RFC 2821 4.5.3.2
        $this->ehlo($host);

        // If a TLS session is required, commence negotiation
        if ($this->secure == 'tls') {
            $this->_send('STARTTLS');
            $this->_expect(220, 180);
            if (! stream_socket_enable_crypto($this->socket, true, $this->getCryptoMethod())) {
                throw new Exception\RuntimeException('Unable to connect via TLS');
            }
            $this->ehlo($host);
        }

        $this->startSession();
        $this->auth();
    }

    /**
     * Returns the perceived session status
     *
     * @return bool
     */
    public function hasSession()
    {
        return $this->sess;
    }

    /**
     * Send EHLO or HELO depending on capabilities of smtp host
     *
     * @param  string $host The client hostname or IP address (default: 127.0.0.1)
     * @throws \Exception|Exception\ExceptionInterface
     */
    protected function ehlo($host)
    {
        // Support for older, less-compliant remote servers. Tries multiple attempts of EHLO or HELO.
        try {
            $this->_send('EHLO ' . $host);
            $this->_expect(250, 300); // Timeout set for 5 minutes as per RFC 2821 4.5.3.2
        } catch (Exception\ExceptionInterface $e) {
            $this->_send('HELO ' . $host);
            $this->_expect(250, 300); // Timeout set for 5 minutes as per RFC 2821 4.5.3.2
        }
    }

    /**
     * Issues MAIL command
     *
     * @param  string $from Sender mailbox
     * @throws Exception\RuntimeException
     */
    public function mail($from)
    {
        if ($this->sess !== true) {
            throw new Exception\RuntimeException('A valid session has not been started');
        }

        $this->_send('MAIL FROM:<' . $from . '>');
        $this->_expect(250, 300); // Timeout set for 5 minutes as per RFC 2821 4.5.3.2

        // Set mail to true, clear recipients and any existing data flags as per 4.1.1.2 of RFC 2821
        $this->mail = true;
        $this->rcpt = false;
        $this->data = false;
    }

    /**
     * Issues RCPT command
     *
     * @param  string $to Receiver(s) mailbox
     * @throws Exception\RuntimeException
     */
    public function rcpt($to)
    {
        if ($this->mail !== true) {
            throw new Exception\RuntimeException('No sender reverse path has been supplied');
        }

        // Set rcpt to true, as per 4.1.1.3 of RFC 2821
        $this->_send('RCPT TO:<' . $to . '>');
        $this->_expect([250, 251], 300); // Timeout set for 5 minutes as per RFC 2821 4.5.3.2
        $this->rcpt = true;
    }

    /**
     * Issues DATA command
     *
     * @param  string $data
     * @throws Exception\RuntimeException
     */
    public function data($data)
    {
        // Ensure recipients have been set
        if ($this->rcpt !== true) { // Per RFC 2821 3.3 (page 18)
            throw new Exception\RuntimeException('No recipient forward path has been supplied');
        }

        $this->_send('DATA');
        $this->_expect(354, 120); // Timeout set for 2 minutes as per RFC 2821 4.5.3.2

        $reader = self::chunkedReader($data);
        foreach ($reader as $line) {
            $line = rtrim($line, "\r\n");
            if (isset($line[0]) && $line[0] === '.') {
                // Escape lines prefixed with a '.'
                $line = '.' . $line;
            }

            if (strlen($line) > self::SMTP_LINE_LIMIT) {
                // Long lines are "folded" by inserting "<CR><LF><SPACE>"
                // https://tools.ietf.org/html/rfc5322#section-2.2.3
                // Add "-1" to stay within limits,
                // because Headers::FOLDING includes a byte for space character after \r\n
                $chunks = chunk_split($line, self::SMTP_LINE_LIMIT - 1, Headers::FOLDING);
                $line = substr($chunks, 0, -strlen(Headers::FOLDING));
            }

            $this->_send($line);
        }

        $this->_send('.');
        $this->_expect(250, 600); // Timeout set for 10 minutes as per RFC 2821 4.5.3.2
        $this->data = true;
    }

    /**
     * Issues the RSET command end validates answer
     *
     * Can be used to restore a clean smtp communication state when a
     * transaction has been cancelled or commencing a new transaction.
     */
    public function rset()
    {
        $this->_send('RSET');
        // MS ESMTP doesn't follow RFC, see https://zendframework.com/issues/browse/ZF-1377
        $this->_expect([250, 220]);

        $this->mail = false;
        $this->rcpt = false;
        $this->data = false;
    }

    /**
     * Issues the NOOP command end validates answer
     *
     * Not used by Laminas\Mail, could be used to keep a connection alive or check if it is still open.
     *
     */
    public function noop()
    {
        $this->_send('NOOP');
        $this->_expect(250, 300); // Timeout set for 5 minutes as per RFC 2821 4.5.3.2
    }

    /**
     * Issues the VRFY command end validates answer
     *
     * Not used by Laminas\Mail.
     *
     * @param  string $user User Name or eMail to verify
     */
    public function vrfy($user)
    {
        $this->_send('VRFY ' . $user);
        $this->_expect([250, 251, 252], 300); // Timeout set for 5 minutes as per RFC 2821 4.5.3.2
    }

    /**
     * Issues the QUIT command and clears the current session
     *
     */
    public function quit()
    {
        if ($this->sess) {
            $this->auth = false;

            if ($this->useCompleteQuit()) {
                $this->_send('QUIT');
                $this->_expect(221, 300); // Timeout set for 5 minutes as per RFC 2821 4.5.3.2
            }

            $this->stopSession();
        }
    }

    /**
     * Default authentication method
     *
     * This default method is implemented by AUTH adapters to properly authenticate to a remote host.
     *
     * @throws Exception\RuntimeException
     */
    public function auth()
    {
        if ($this->auth === true) {
            throw new Exception\RuntimeException('Already authenticated for this session');
        }
    }

    /**
     * Closes connection
     *
     */
    public function disconnect()
    {
        $this->_disconnect();
    }

    // @codingStandardsIgnoreStart
    /**
     * Disconnect from remote host and free resource
     */
    protected function _disconnect()
    {
        // @codingStandardsIgnoreEnd

        // Make sure the session gets closed
        $this->quit();
        parent::_disconnect();
    }

    /**
     * Start mail session
     *
     */
    protected function startSession()
    {
        $this->sess = true;
    }

    /**
     * Stop mail session
     *
     */
    protected function stopSession()
    {
        $this->sess = false;
    }
}
laminas-mail/src/Protocol/Pop3.php000064400000025116147361032560013046 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-mail for the canonical source repository
 * @copyright https://github.com/laminas/laminas-mail/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-mail/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Mail\Protocol;

use Laminas\Stdlib\ErrorHandler;

class Pop3
{
    use ProtocolTrait;

    /**
     * Default timeout in seconds for initiating session
     */
    public const TIMEOUT_CONNECTION = 30;

    /**
     * saves if server supports top
     * @var null|bool
     */
    public $hasTop = null;

    /**
     * @var null|resource
     */
    protected $socket;

    /**
     * greeting timestamp for apop
     * @var null|string
     */
    protected $timestamp;

    /**
     * Public constructor
     *
     * @param  string      $host           hostname or IP address of POP3 server, if given connect() is called
     * @param  int|null    $port           port of POP3 server, null for default (110 or 995 for ssl)
     * @param  bool|string $ssl            use ssl? 'SSL', 'TLS' or false
     * @param  bool        $novalidatecert set to true to skip SSL certificate validation
     */
    public function __construct($host = '', $port = null, $ssl = false, $novalidatecert = false)
    {
        $this->setNoValidateCert($novalidatecert);

        if ($host) {
            $this->connect($host, $port, $ssl);
        }
    }

    /**
     * Public destructor
     */
    public function __destruct()
    {
        $this->logout();
    }

    /**
     * Open connection to POP3 server
     *
     * @param  string      $host  hostname or IP address of POP3 server
     * @param  int|null    $port  of POP3 server, default is 110 (995 for ssl)
     * @param  string|bool $ssl   use 'SSL', 'TLS' or false
     * @throws Exception\RuntimeException
     * @return string welcome message
     */
    public function connect($host, $port = null, $ssl = false)
    {
        $transport = 'tcp';
        $isTls = false;

        if ($ssl) {
            $ssl = strtolower($ssl);
        }

        switch ($ssl) {
            case 'ssl':
                $transport = 'ssl';
                if (! $port) {
                    $port = 995;
                }
                break;
            case 'tls':
                $isTls = true;
                // break intentionally omitted
            default:
                if (! $port) {
                    $port = 110;
                }
        }

        $this->socket = $this->setupSocket($transport, $host, $port, self::TIMEOUT_CONNECTION);

        $welcome = $this->readResponse();

        strtok($welcome, '<');
        $this->timestamp = strtok('>');
        if (! strpos($this->timestamp, '@')) {
            $this->timestamp = null;
        } else {
            $this->timestamp = '<' . $this->timestamp . '>';
        }

        if ($isTls) {
            $this->request('STLS');
            $result = stream_socket_enable_crypto($this->socket, true, $this->getCryptoMethod());
            if (! $result) {
                throw new Exception\RuntimeException('cannot enable TLS');
            }
        }

        return $welcome;
    }

    /**
     * Send a request
     *
     * @param string $request your request without newline
     * @throws Exception\RuntimeException
     */
    public function sendRequest($request)
    {
        ErrorHandler::start();
        $result = fwrite($this->socket, $request . "\r\n");
        $error  = ErrorHandler::stop();
        if (! $result) {
            throw new Exception\RuntimeException('send failed - connection closed?', 0, $error);
        }
    }

    /**
     * read a response
     *
     * @param  bool $multiline response has multiple lines and should be read until "<nl>.<nl>"
     * @throws Exception\RuntimeException
     * @return string response
     */
    public function readResponse($multiline = false)
    {
        ErrorHandler::start();
        $result = fgets($this->socket);
        $error  = ErrorHandler::stop();
        if (! is_string($result)) {
            throw new Exception\RuntimeException('read failed - connection closed?', 0, $error);
        }

        $result = trim($result);
        if (strpos($result, ' ')) {
            list($status, $message) = explode(' ', $result, 2);
        } else {
            $status = $result;
            $message = '';
        }

        if ($status != '+OK') {
            throw new Exception\RuntimeException('last request failed');
        }

        if ($multiline) {
            $message = '';
            $line = fgets($this->socket);
            while ($line && rtrim($line, "\r\n") != '.') {
                if ($line[0] == '.') {
                    $line = substr($line, 1);
                }
                $message .= $line;
                $line = fgets($this->socket);
            }
        }

        return $message;
    }

    /**
     * Send request and get response
     *
     * @see sendRequest()
     * @see readResponse()
     * @param  string $request    request
     * @param  bool   $multiline  multiline response?
     * @return string             result from readResponse()
     */
    public function request($request, $multiline = false)
    {
        $this->sendRequest($request);
        return $this->readResponse($multiline);
    }

    /**
     * End communication with POP3 server (also closes socket)
     */
    public function logout()
    {
        if ($this->socket) {
            try {
                $this->request('QUIT');
            } catch (Exception\ExceptionInterface $e) {
                // ignore error - we're closing the socket anyway
            }

            fclose($this->socket);
            $this->socket = null;
        }
    }

    /**
     * Get capabilities from POP3 server
     *
     * @return array list of capabilities
     */
    public function capa()
    {
        $result = $this->request('CAPA', true);
        return explode("\n", $result);
    }

    /**
     * Login to POP3 server. Can use APOP
     *
     * @param  string $user     username
     * @param  string $password password
     * @param  bool   $tryApop  should APOP be tried?
     */
    public function login($user, $password, $tryApop = true)
    {
        if ($tryApop && $this->timestamp) {
            try {
                $this->request("APOP $user " . md5($this->timestamp . $password));
                return;
            } catch (Exception\ExceptionInterface $e) {
                // ignore
            }
        }

        $this->request("USER $user");
        $this->request("PASS $password");
    }

    /**
     * Make STAT call for message count and size sum
     *
     * @param  int $messages  out parameter with count of messages
     * @param  int $octets    out parameter with size in octets of messages
     */
    public function status(&$messages, &$octets)
    {
        $messages = 0;
        $octets = 0;
        $result = $this->request('STAT');

        list($messages, $octets) = explode(' ', $result);
    }

    /**
     * Make LIST call for size of message(s)
     *
     * @param  int|null $msgno number of message, null for all
     * @return int|array size of given message or list with array(num => size)
     */
    public function getList($msgno = null)
    {
        if ($msgno !== null) {
            $result = $this->request("LIST $msgno");

            list(, $result) = explode(' ', $result);
            return (int) $result;
        }

        $result = $this->request('LIST', true);
        $messages = [];
        $line = strtok($result, "\n");
        while ($line) {
            list($no, $size) = explode(' ', trim($line));
            $messages[(int) $no] = (int) $size;
            $line = strtok("\n");
        }

        return $messages;
    }

    /**
     * Make UIDL call for getting a uniqueid
     *
     * @param  int|null $msgno number of message, null for all
     * @return string|array uniqueid of message or list with array(num => uniqueid)
     */
    public function uniqueid($msgno = null)
    {
        if ($msgno !== null) {
            $result = $this->request("UIDL $msgno");

            list(, $result) = explode(' ', $result);
            return $result;
        }

        $result = $this->request('UIDL', true);

        $result = explode("\n", $result);
        $messages = [];
        foreach ($result as $line) {
            if (! $line) {
                continue;
            }
            list($no, $id) = explode(' ', trim($line), 2);
            $messages[(int) $no] = $id;
        }

        return $messages;
    }

    /**
     * Make TOP call for getting headers and maybe some body lines
     * This method also sets hasTop - before it it's not known if top is supported
     *
     * The fallback makes normal RETR call, which retrieves the whole message. Additional
     * lines are not removed.
     *
     * @param  int  $msgno    number of message
     * @param  int  $lines    number of wanted body lines (empty line is inserted after header lines)
     * @param  bool $fallback fallback with full retrieve if top is not supported
     * @throws Exception\RuntimeException
     * @throws Exception\ExceptionInterface
     * @return string message headers with wanted body lines
     */
    public function top($msgno, $lines = 0, $fallback = false)
    {
        if ($this->hasTop === false) {
            if ($fallback) {
                return $this->retrieve($msgno);
            }

            throw new Exception\RuntimeException('top not supported and no fallback wanted');
        }
        $this->hasTop = true;

        $lines = (! $lines || $lines < 1) ? 0 : (int) $lines;

        try {
            $result = $this->request("TOP $msgno $lines", true);
        } catch (Exception\ExceptionInterface $e) {
            $this->hasTop = false;
            if ($fallback) {
                $result = $this->retrieve($msgno);
            } else {
                throw $e;
            }
        }

        return $result;
    }

    /**
     * Make a RETR call for retrieving a full message with headers and body
     *
     * @param  int $msgno  message number
     * @return string message
     */
    public function retrieve($msgno)
    {
        $result = $this->request("RETR $msgno", true);
        return $result;
    }

    /**
     * Make a NOOP call, maybe needed for keeping the server happy
     */
    public function noop()
    {
        $this->request('NOOP');
    }

    /**
     * Make a DELE count to remove a message
     *
     * @param $msgno
     */
    public function delete($msgno)
    {
        $this->request("DELE $msgno");
    }

    /**
     * Make RSET call, which rollbacks delete requests
     */
    public function undelete()
    {
        $this->request('RSET');
    }
}
laminas-mail/src/Protocol/ProtocolTrait.php000064400000006426147361032560015035 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-mail for the canonical source repository
 * @copyright https://github.com/laminas/laminas-mail/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-mail/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Mail\Protocol;

use Laminas\Stdlib\ErrorHandler;

/**
 * https://bugs.php.net/bug.php?id=69195
 */
trait ProtocolTrait
{
    /**
     * If set to true, do not validate the SSL certificate
     * @var null|bool
     */
    protected $novalidatecert;

    public function getCryptoMethod(): int
    {
        // Allow the best TLS version(s) we can
        $cryptoMethod = STREAM_CRYPTO_METHOD_TLS_CLIENT;

        // PHP 5.6.7 dropped inclusion of TLS 1.1 and 1.2 in STREAM_CRYPTO_METHOD_TLS_CLIENT
        // so add them back in manually if we can
        if (defined('STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT')) {
            $cryptoMethod |= STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT;
            $cryptoMethod |= STREAM_CRYPTO_METHOD_TLSv1_1_CLIENT;
        }

        return $cryptoMethod;
    }

    /**
     * Do not validate SSL certificate
     *
     * @todo Update to return self when minimum supported PHP version is 7.4+
     * @param  bool $novalidatecert Set to true to disable certificate validation
     * @return $this
     */
    public function setNoValidateCert(bool $novalidatecert)
    {
        $this->novalidatecert = $novalidatecert;
        return $this;
    }

    /**
     * Should we validate SSL certificate?
     *
     * @return bool
     */
    public function validateCert(): bool
    {
        return ! $this->novalidatecert;
    }

    /**
     * Prepare socket options
     *
     * @return array
     */
    private function prepareSocketOptions(): array
    {
        return $this->novalidatecert
            ? [
                'ssl' => [
                    'verify_peer_name' => false,
                    'verify_peer'      => false,
                ],
            ]
            : [];
    }

    /**
     * Setup connection socket
     *
     * @param  string   $host hostname or IP address of IMAP server
     * @param  int|null $port of IMAP server, default is 143 (993 for ssl)
     * @param  int      $timeout timeout in seconds for initiating session
     * @return resource The socket created.
     * @throws Exception\RuntimeException If unable to connect to host.
     */
    protected function setupSocket(
        string $transport,
        string $host,
        ?int $port,
        int $timeout
    ) {
        ErrorHandler::start();
        $socket = stream_socket_client(
            sprintf('%s://%s:%d', $transport, $host, $port),
            $errno,
            $errstr,
            $timeout,
            STREAM_CLIENT_CONNECT,
            stream_context_create($this->prepareSocketOptions())
        );
        $error = ErrorHandler::stop();

        if (! $socket) {
            throw new Exception\RuntimeException(sprintf(
                'cannot connect to host%s',
                $error ? sprintf('; error = %s (errno = %d )', $error->getMessage(), $error->getCode()) : ''
            ), 0, $error);
        }

        if (false === stream_set_timeout($socket, $timeout)) {
            throw new Exception\RuntimeException('Could not set stream timeout');
        }

        return $socket;
    }
}
laminas-mail/src/Protocol/AbstractProtocol.php000064400000022146147361032560015512 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-mail for the canonical source repository
 * @copyright https://github.com/laminas/laminas-mail/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-mail/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Mail\Protocol;

use Laminas\Validator;

/**
 * Provides low-level methods for concrete adapters to communicate with a
 * remote mail server and track requests and responses.
 *
 * @todo Implement proxy settings
 */
abstract class AbstractProtocol
{
    /**
     * Mail default EOL string
     */
    public const EOL = "\r\n";

    /**
     * Default timeout in seconds for initiating session
     */
    public const TIMEOUT_CONNECTION = 30;

    /**
     * Maximum of the transaction log
     * @var int
     */
    protected $maximumLog = 64;

    /**
     * Hostname or IP address of remote server
     * @var string
     */
    protected $host;

    /**
     * Port number of connection
     * @var int
     */
    protected $port;

    /**
     * Instance of Laminas\Validator\ValidatorChain to check hostnames
     * @var \Laminas\Validator\ValidatorChain
     */
    protected $validHost;

    /**
     * Socket connection resource
     * @var null|resource
     */
    protected $socket;

    /**
     * Last request sent to server
     * @var string
     */
    protected $request;

    /**
     * Array of server responses to last request
     * @var array
     */
    protected $response;

    /**
     * Log of mail requests and server responses for a session
     * @var array
     */
    private $log = [];

    /**
     * Constructor.
     *
     * @param  string  $host OPTIONAL Hostname of remote connection (default: 127.0.0.1)
     * @param  int $port OPTIONAL Port number (default: null)
     * @throws Exception\RuntimeException
     */
    public function __construct($host = '127.0.0.1', $port = null)
    {
        $this->validHost = new Validator\ValidatorChain();
        $this->validHost->attach(new Validator\Hostname(Validator\Hostname::ALLOW_ALL));

        if (! $this->validHost->isValid($host)) {
            throw new Exception\RuntimeException(implode(', ', $this->validHost->getMessages()));
        }

        $this->host = $host;
        $this->port = $port;
    }

    /**
     * Class destructor to cleanup open resources
     *
     */
    public function __destruct()
    {
        $this->_disconnect();
    }

    /**
     * Set the maximum log size
     *
     * @param int $maximumLog Maximum log size
     */
    public function setMaximumLog($maximumLog)
    {
        $this->maximumLog = (int) $maximumLog;
    }

    /**
     * Get the maximum log size
     *
     * @return int the maximum log size
     */
    public function getMaximumLog()
    {
        return $this->maximumLog;
    }

    /**
     * Create a connection to the remote host
     *
     * Concrete adapters for this class will implement their own unique connect
     * scripts, using the _connect() method to create the socket resource.
     */
    abstract public function connect();

    /**
     * Retrieve the last client request
     *
     * @return string
     */
    public function getRequest()
    {
        return $this->request;
    }

    /**
     * Retrieve the last server response
     *
     * @return array
     */
    public function getResponse()
    {
        return $this->response;
    }

    /**
     * Retrieve the transaction log
     *
     * @return string
     */
    public function getLog()
    {
        return implode('', $this->log);
    }

    /**
     * Reset the transaction log
     *
     */
    public function resetLog()
    {
        $this->log = [];
    }

    // @codingStandardsIgnoreStart
    /**
     * Add the transaction log
     *
     * @param  string $value new transaction
     */
    protected function _addLog($value)
    {
        // @codingStandardsIgnoreEnd
        if ($this->maximumLog >= 0 && count($this->log) >= $this->maximumLog) {
            array_shift($this->log);
        }

        $this->log[] = $value;
    }

    // @codingStandardsIgnoreStart
    /**
     * Connect to the server using the supplied transport and target
     *
     * An example $remote string may be 'tcp://mail.example.com:25' or 'ssh://hostname.com:2222'
     *
     * @deprecated Since 1.12.0. Implementations should use the ProtocolTrait::setupSocket() method instead.
     * @todo Remove for 3.0.0.
     * @param  string $remote Remote
     * @throws Exception\RuntimeException
     * @return bool
     */
    protected function _connect($remote)
    {
		// @codingStandardsIgnoreEnd
        $errorNum = 0;
        $errorStr = '';

        // open connection
        set_error_handler(
            function ($error, $message = '') {
                throw new Exception\RuntimeException(sprintf('Could not open socket: %s', $message), $error);
            },
            E_WARNING
        );
        $this->socket = stream_socket_client($remote, $errorNum, $errorStr, self::TIMEOUT_CONNECTION);
        restore_error_handler();

        if ($this->socket === false) {
            if ($errorNum == 0) {
                $errorStr = 'Could not open socket';
            }
            throw new Exception\RuntimeException($errorStr);
        }

        if (($result = stream_set_timeout($this->socket, self::TIMEOUT_CONNECTION)) === false) {
            throw new Exception\RuntimeException('Could not set stream timeout');
        }

        return $result;
    }

    // @codingStandardsIgnoreStart
    /**
     * Disconnect from remote host and free resource
     *
     */
    protected function _disconnect()
    {
        // @codingStandardsIgnoreEnd
        if (is_resource($this->socket)) {
            fclose($this->socket);
        }
    }

    // @codingStandardsIgnoreStart
    /**
     * Send the given request followed by a LINEEND to the server.
     *
     * @param  string $request
     * @throws Exception\RuntimeException
     * @return int|bool Number of bytes written to remote host
     */
    protected function _send($request)
    {
        // @codingStandardsIgnoreEnd
        if (! is_resource($this->socket)) {
            throw new Exception\RuntimeException('No connection has been established to ' . $this->host);
        }

        $this->request = $request;

        $result = fwrite($this->socket, $request . self::EOL);

        // Save request to internal log
        $this->_addLog($request . self::EOL);

        if ($result === false) {
            throw new Exception\RuntimeException('Could not send request to ' . $this->host);
        }

        return $result;
    }

    // @codingStandardsIgnoreStart
    /**
     * Get a line from the stream.
     *
     * @param  int $timeout Per-request timeout value if applicable
     * @throws Exception\RuntimeException
     * @return string
     */
    protected function _receive($timeout = null)
    {
        // @codingStandardsIgnoreEnd
        if (! is_resource($this->socket)) {
            throw new Exception\RuntimeException('No connection has been established to ' . $this->host);
        }

        // Adapters may wish to supply per-commend timeouts according to appropriate RFC
        if ($timeout !== null) {
            stream_set_timeout($this->socket, $timeout);
        }

        // Retrieve response
        $response = fgets($this->socket, 1024);

        // Save request to internal log
        $this->_addLog($response);

        // Check meta data to ensure connection is still valid
        $info = stream_get_meta_data($this->socket);

        if (! empty($info['timed_out'])) {
            throw new Exception\RuntimeException($this->host . ' has timed out');
        }

        if ($response === false) {
            throw new Exception\RuntimeException('Could not read from ' . $this->host);
        }

        return $response;
    }

    // @codingStandardsIgnoreStart
    /**
     * Parse server response for successful codes
     *
     * Read the response from the stream and check for expected return code.
     * Throws a Laminas\Mail\Protocol\Exception\ExceptionInterface if an unexpected code is returned.
     *
     * @param  string|array $code One or more codes that indicate a successful response
     * @param  int $timeout Per-request timeout value if applicable
     * @throws Exception\RuntimeException
     * @return string Last line of response string
     */
    protected function _expect($code, $timeout = null)
    {
        // @codingStandardsIgnoreEnd
        $this->response = [];
        $errMsg = '';

        if (! is_array($code)) {
            $code = [$code];
        }

        do {
            $this->response[] = $result = $this->_receive($timeout);
            list($cmd, $more, $msg) = preg_split('/([\s-]+)/', $result, 2, PREG_SPLIT_DELIM_CAPTURE);

            if ($errMsg !== '') {
                $errMsg .= ' ' . $msg;
            } elseif ($cmd === null || ! in_array($cmd, $code)) {
                $errMsg = $msg;
            }

        // The '-' message prefix indicates an information string instead of a response string.
        } while (strpos($more, '-') === 0);

        if ($errMsg !== '') {
            throw new Exception\RuntimeException($errMsg);
        }

        return $msg;
    }
}
laminas-mail/src/Protocol/Smtp/Auth/Plain.php000064400000005347147361032560015120 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-mail for the canonical source repository
 * @copyright https://github.com/laminas/laminas-mail/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-mail/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Mail\Protocol\Smtp\Auth;

use Laminas\Mail\Protocol\Smtp;

/**
 * Performs PLAIN authentication
 */
class Plain extends Smtp
{
    /**
     * PLAIN username
     *
     * @var string
     */
    protected $username;

    /**
     * PLAIN password
     *
     * @var string
     */
    protected $password;

    /**
     * Constructor.
     *
     * @param  string $host   (Default: 127.0.0.1)
     * @param  int    $port   (Default: null)
     * @param  array  $config Auth-specific parameters
     */
    public function __construct($host = '127.0.0.1', $port = null, $config = null)
    {
        // Did we receive a configuration array?
        $origConfig = $config;
        if (is_array($host)) {
            // Merge config array with principal array, if provided
            if (is_array($config)) {
                $config = array_replace_recursive($host, $config);
            } else {
                $config = $host;
            }
        }

        if (is_array($config)) {
            if (isset($config['username'])) {
                $this->setUsername($config['username']);
            }
            if (isset($config['password'])) {
                $this->setPassword($config['password']);
            }
        }

        // Call parent with original arguments
        parent::__construct($host, $port, $origConfig);
    }

    /**
     * Perform PLAIN authentication with supplied credentials
     *
     */
    public function auth()
    {
        // Ensure AUTH has not already been initiated.
        parent::auth();

        $this->_send('AUTH PLAIN');
        $this->_expect(334);
        $this->_send(base64_encode("\0" . $this->getUsername() . "\0" . $this->getPassword()));
        $this->_expect(235);
        $this->auth = true;
    }

    /**
     * Set value for username
     *
     * @param  string $username
     * @return Plain
     */
    public function setUsername($username)
    {
        $this->username = $username;
        return $this;
    }

    /**
     * Get username
     *
     * @return string
     */
    public function getUsername()
    {
        return $this->username;
    }

    /**
     * Set value for password
     *
     * @param  string $password
     * @return Plain
     */
    public function setPassword($password)
    {
        $this->password = $password;
        return $this;
    }

    /**
     * Get password
     *
     * @return string
     */
    public function getPassword()
    {
        return $this->password;
    }
}
laminas-mail/src/Protocol/Smtp/Auth/Login.php000064400000005432147361032560015120 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-mail for the canonical source repository
 * @copyright https://github.com/laminas/laminas-mail/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-mail/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Mail\Protocol\Smtp\Auth;

use Laminas\Mail\Protocol\Smtp;

/**
 * Performs LOGIN authentication
 */
class Login extends Smtp
{
    /**
     * LOGIN username
     *
     * @var string
     */
    protected $username;

    /**
     * LOGIN password
     *
     * @var string
     */
    protected $password;

    /**
     * Constructor.
     *
     * @param  string $host   (Default: 127.0.0.1)
     * @param  int    $port   (Default: null)
     * @param  array  $config Auth-specific parameters
     */
    public function __construct($host = '127.0.0.1', $port = null, $config = null)
    {
        // Did we receive a configuration array?
        $origConfig = $config;
        if (is_array($host)) {
            // Merge config array with principal array, if provided
            if (is_array($config)) {
                $config = array_replace_recursive($host, $config);
            } else {
                $config = $host;
            }
        }

        if (is_array($config)) {
            if (isset($config['username'])) {
                $this->setUsername($config['username']);
            }
            if (isset($config['password'])) {
                $this->setPassword($config['password']);
            }
        }

        // Call parent with original arguments
        parent::__construct($host, $port, $origConfig);
    }

    /**
     * Perform LOGIN authentication with supplied credentials
     *
     */
    public function auth()
    {
        // Ensure AUTH has not already been initiated.
        parent::auth();

        $this->_send('AUTH LOGIN');
        $this->_expect(334);
        $this->_send(base64_encode($this->getUsername()));
        $this->_expect(334);
        $this->_send(base64_encode($this->getPassword()));
        $this->_expect(235);
        $this->auth = true;
    }

    /**
     * Set value for username
     *
     * @param  string $username
     * @return Login
     */
    public function setUsername($username)
    {
        $this->username = $username;
        return $this;
    }

    /**
     * Get username
     *
     * @return string
     */
    public function getUsername()
    {
        return $this->username;
    }

    /**
     * Set value for password
     *
     * @param  string $password
     * @return Login
     */
    public function setPassword($password)
    {
        $this->password = $password;
        return $this;
    }

    /**
     * Get password
     *
     * @return string
     */
    public function getPassword()
    {
        return $this->password;
    }
}
laminas-mail/src/Protocol/Smtp/Auth/Crammd5.php000064400000006501147361032560015336 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-mail for the canonical source repository
 * @copyright https://github.com/laminas/laminas-mail/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-mail/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Mail\Protocol\Smtp\Auth;

use Laminas\Crypt\Hmac;
use Laminas\Mail\Protocol\Smtp;

/**
 * Performs CRAM-MD5 authentication
 */
class Crammd5 extends Smtp
{
    /**
     * @var string
     */
    protected $username;

    /**
     * @var string
     */
    protected $password;

    /**
     * Constructor.
     *
     * All parameters may be passed as an array to the first argument of the
     * constructor. If so,
     *
     * @param  string|array $host   (Default: 127.0.0.1)
     * @param  null|int     $port   (Default: null)
     * @param  null|array   $config Auth-specific parameters
     */
    public function __construct($host = '127.0.0.1', $port = null, $config = null)
    {
        // Did we receive a configuration array?
        $origConfig = $config;
        if (is_array($host)) {
            // Merge config array with principal array, if provided
            if (is_array($config)) {
                $config = array_replace_recursive($host, $config);
            } else {
                $config = $host;
            }
        }

        if (is_array($config)) {
            if (isset($config['username'])) {
                $this->setUsername($config['username']);
            }
            if (isset($config['password'])) {
                $this->setPassword($config['password']);
            }
        }

        // Call parent with original arguments
        parent::__construct($host, $port, $origConfig);
    }

    /**
     * Performs CRAM-MD5 authentication with supplied credentials
     */
    public function auth()
    {
        // Ensure AUTH has not already been initiated.
        parent::auth();

        $this->_send('AUTH CRAM-MD5');
        $challenge = $this->_expect(334);
        $challenge = base64_decode($challenge);
        $digest = $this->hmacMd5($this->getPassword(), $challenge);
        $this->_send(base64_encode($this->getUsername() . ' ' . $digest));
        $this->_expect(235);
        $this->auth = true;
    }

    /**
     * Set value for username
     *
     * @param  string $username
     * @return Crammd5
     */
    public function setUsername($username)
    {
        $this->username = $username;
        return $this;
    }

    /**
     * Get username
     *
     * @return string
     */
    public function getUsername()
    {
        return $this->username;
    }

    /**
     * Set value for password
     *
     * @param  string $password
     * @return Crammd5
     */
    public function setPassword($password)
    {
        $this->password = $password;
        return $this;
    }

    /**
     * Get password
     *
     * @return string
     */
    public function getPassword()
    {
        return $this->password;
    }

    /**
     * Prepare CRAM-MD5 response to server's ticket
     *
     * @param  string $key   Challenge key (usually password)
     * @param  string $data  Challenge data
     * @param  int    $block Length of blocks (deprecated; unused)
     * @return string
     */
    protected function hmacMd5($key, $data, $block = 64)
    {
        return Hmac::compute($key, 'md5', $data);
    }
}
laminas-mail/src/Protocol/Exception/ExceptionInterface.php000064400000000672147361032560017742 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-mail for the canonical source repository
 * @copyright https://github.com/laminas/laminas-mail/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-mail/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Mail\Protocol\Exception;

use Laminas\Mail\Exception\ExceptionInterface as MailException;

interface ExceptionInterface extends MailException
{
}
laminas-mail/src/Protocol/Exception/InvalidArgumentException.php000064400000000774147361032560021136 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-mail for the canonical source repository
 * @copyright https://github.com/laminas/laminas-mail/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-mail/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Mail\Protocol\Exception;

use Laminas\Mail\Exception;

/**
 * Exception for Laminas\Mail component.
 */
class InvalidArgumentException extends Exception\InvalidArgumentException implements ExceptionInterface
{
}
laminas-mail/src/Protocol/Exception/RuntimeException.php000064400000000754147361032560017466 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-mail for the canonical source repository
 * @copyright https://github.com/laminas/laminas-mail/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-mail/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Mail\Protocol\Exception;

use Laminas\Mail\Exception;

/**
 * Exception for Laminas\Mail component.
 */
class RuntimeException extends Exception\RuntimeException implements ExceptionInterface
{
}
laminas-mail/src/Protocol/SmtpPluginManager.php000064400000007240147361032560015620 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-mail for the canonical source repository
 * @copyright https://github.com/laminas/laminas-mail/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-mail/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Mail\Protocol;

use Laminas\ServiceManager\AbstractPluginManager;
use Laminas\ServiceManager\Exception\InvalidServiceException;
use Laminas\ServiceManager\Factory\InvokableFactory;

/**
 * Plugin manager implementation for SMTP extensions.
 *
 * Enforces that SMTP extensions retrieved are instances of Smtp. Additionally,
 * it registers a number of default extensions available.
 */
class SmtpPluginManager extends AbstractPluginManager
{
    /**
     * Service aliases
     */
    protected $aliases = [
        'crammd5' => Smtp\Auth\Crammd5::class,
        'cramMd5' => Smtp\Auth\Crammd5::class,
        'CramMd5' => Smtp\Auth\Crammd5::class,
        'cramMD5' => Smtp\Auth\Crammd5::class,
        'CramMD5' => Smtp\Auth\Crammd5::class,
        'login'   => Smtp\Auth\Login::class,
        'Login'   => Smtp\Auth\Login::class,
        'plain'   => Smtp\Auth\Plain::class,
        'Plain'   => Smtp\Auth\Plain::class,
        'smtp'    => Smtp::class,
        'Smtp'    => Smtp::class,
        'SMTP'    => Smtp::class,

        // Legacy Zend Framework aliases
        \Zend\Mail\Protocol\Smtp\Auth\Crammd5::class => Smtp\Auth\Crammd5::class,
        \Zend\Mail\Protocol\Smtp\Auth\Login::class => Smtp\Auth\Login::class,
        \Zend\Mail\Protocol\Smtp\Auth\Plain::class => Smtp\Auth\Plain::class,
        \Zend\Mail\Protocol\Smtp::class => Smtp::class,

        // v2 normalized FQCNs
        'zendmailprotocolsmtpauthcrammd5' => Smtp\Auth\Crammd5::class,
        'zendmailprotocolsmtpauthlogin' => Smtp\Auth\Login::class,
        'zendmailprotocolsmtpauthplain' => Smtp\Auth\Plain::class,
        'zendmailprotocolsmtp' => Smtp::class,
    ];

    /**
     * Service factories
     *
     * @var array
     */
    protected $factories = [
        Smtp\Auth\Crammd5::class => InvokableFactory::class,
        Smtp\Auth\Login::class   => InvokableFactory::class,
        Smtp\Auth\Plain::class   => InvokableFactory::class,
        Smtp::class              => InvokableFactory::class,

        // v2 normalized service names

        'laminasmailprotocolsmtpauthcrammd5' => InvokableFactory::class,
        'laminasmailprotocolsmtpauthlogin'   => InvokableFactory::class,
        'laminasmailprotocolsmtpauthplain'   => InvokableFactory::class,
        'laminasmailprotocolsmtp'            => InvokableFactory::class,
    ];

    /**
     * Plugins must be an instance of the Smtp class
     *
     * @var string
     */
    protected $instanceOf = Smtp::class;

    /**
     * Validate a retrieved plugin instance (v3).
     *
     * @param object $plugin
     * @throws InvalidServiceException
     */
    public function validate($plugin)
    {
        if (! $plugin instanceof $this->instanceOf) {
            throw new InvalidServiceException(sprintf(
                'Plugin of type %s is invalid; must extend %s',
                (is_object($plugin) ? get_class($plugin) : gettype($plugin)),
                $this->instanceOf
            ));
        }
    }

    /**
     * Validate a retrieved plugin instance (v2).
     *
     * @param object $plugin
     * @throws Exception\InvalidArgumentException
     */
    public function validatePlugin($plugin)
    {
        try {
            $this->validate($plugin);
        } catch (InvalidServiceException $e) {
            throw new Exception\InvalidArgumentException(
                $e->getMessage(),
                $e->getCode(),
                $e
            );
        }
    }
}
laminas-mail/src/Protocol/SmtpPluginManagerFactory.php000064400000002650147361032560017150 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-mail for the canonical source repository
 * @copyright https://github.com/laminas/laminas-mail/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-mail/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Mail\Protocol;

use Interop\Container\ContainerInterface;
use Laminas\ServiceManager\FactoryInterface;
use Laminas\ServiceManager\ServiceLocatorInterface;

class SmtpPluginManagerFactory implements FactoryInterface
{
    /**
     * laminas-servicemanager v2 support for invocation options.
     *
     * @param array
     */
    protected $creationOptions;

    /**
     * {@inheritDoc}
     *
     * @return SmtpPluginManager
     */
    public function __invoke(ContainerInterface $container, $name, array $options = null)
    {
        return new SmtpPluginManager($container, $options ?: []);
    }

    /**
     * {@inheritDoc}
     *
     * @return SmtpPluginManager
     */
    public function createService(ServiceLocatorInterface $container, $name = null, $requestedName = null)
    {
        return $this($container, $requestedName ?: SmtpPluginManager::class, $this->creationOptions);
    }

    /**
     * laminas-servicemanager v2 support for invocation options.
     *
     * @param array $options
     * @return void
     */
    public function setCreationOptions(array $options)
    {
        $this->creationOptions = $options;
    }
}
laminas-mail/src/Header/InReplyTo.php000064400000000674147361032560013503 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-mail for the canonical source repository
 * @copyright https://github.com/laminas/laminas-mail/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-mail/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Mail\Header;

class InReplyTo extends IdentificationField
{
    protected $fieldName = 'In-Reply-To';
    protected static $type = 'in-reply-to';
}
laminas-mail/src/Header/Sender.php000064400000010433147361032560013030 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-mail for the canonical source repository
 * @copyright https://github.com/laminas/laminas-mail/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-mail/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Mail\Header;

use Laminas\Mail;
use Laminas\Mime\Mime;

/**
 * Sender header class methods.
 *
 * @see https://tools.ietf.org/html/rfc2822 RFC 2822
 * @see https://tools.ietf.org/html/rfc2047 RFC 2047
 */
class Sender implements HeaderInterface
{
    /**
     * @var \Laminas\Mail\Address\AddressInterface
     */
    protected $address;

    /**
     * Header encoding
     *
     * @var null|string
     */
    protected $encoding;

    public static function fromString($headerLine)
    {
        list($name, $value) = GenericHeader::splitHeaderLine($headerLine);
        $value = HeaderWrap::mimeDecodeValue($value);

        // check to ensure proper header type for this factory
        if (strtolower($name) !== 'sender') {
            throw new Exception\InvalidArgumentException('Invalid header name for Sender string');
        }

        $header     = new static();

        /**
         * matches the header value so that the email must be enclosed by < > when a name is present
         * 'name' and 'email' capture groups correspond respectively to 'display-name' and 'addr-spec' in the ABNF
         * @see https://tools.ietf.org/html/rfc5322#section-3.4
         */
        $hasMatches = preg_match(
            '/^(?:(?P<name>.+)\s)?(?(name)<|<?)(?P<email>[^\s]+?)(?(name)>|>?)$/',
            $value,
            $matches
        );

        if ($hasMatches !== 1) {
            throw new Exception\InvalidArgumentException('Invalid header value for Sender string');
        }

        $senderName = trim($matches['name']);

        if (empty($senderName)) {
            $senderName = null;
        }

        $header->setAddress($matches['email'], $senderName);

        return $header;
    }

    public function getFieldName()
    {
        return 'Sender';
    }

    public function getFieldValue($format = HeaderInterface::FORMAT_RAW)
    {
        if (! $this->address instanceof Mail\Address\AddressInterface) {
            return '';
        }

        $email = sprintf('<%s>', $this->address->getEmail());
        $name  = $this->address->getName();

        if (! empty($name)) {
            if ($format == HeaderInterface::FORMAT_ENCODED) {
                $encoding = $this->getEncoding();
                if ('ASCII' !== $encoding) {
                    $name  = HeaderWrap::mimeEncodeValue($name, $encoding);
                }
            }
            $email = sprintf('%s %s', $name, $email);
        }

        return $email;
    }

    public function setEncoding($encoding)
    {
        $this->encoding = $encoding;
        return $this;
    }

    public function getEncoding()
    {
        if (! $this->encoding) {
            $this->encoding = Mime::isPrintable($this->getFieldValue(HeaderInterface::FORMAT_RAW))
                ? 'ASCII'
                : 'UTF-8';
        }

        return $this->encoding;
    }

    public function toString()
    {
        return 'Sender: ' . $this->getFieldValue(HeaderInterface::FORMAT_ENCODED);
    }

    /**
     * Set the address used in this header
     *
     * @param  string|\Laminas\Mail\Address\AddressInterface $emailOrAddress
     * @param  null|string $name
     * @throws Exception\InvalidArgumentException
     * @return Sender
     */
    public function setAddress($emailOrAddress, $name = null)
    {
        if (is_string($emailOrAddress)) {
            $emailOrAddress = new Mail\Address($emailOrAddress, $name);
        } elseif (! $emailOrAddress instanceof Mail\Address\AddressInterface) {
            throw new Exception\InvalidArgumentException(sprintf(
                '%s expects a string or AddressInterface object; received "%s"',
                __METHOD__,
                (is_object($emailOrAddress) ? get_class($emailOrAddress) : gettype($emailOrAddress))
            ));
        }
        $this->address = $emailOrAddress;
        return $this;
    }

    /**
     * Retrieve the internal address from this header
     *
     * @return \Laminas\Mail\Address\AddressInterface|null
     */
    public function getAddress()
    {
        return $this->address;
    }
}
laminas-mail/src/Header/ListParser.php000064400000006037147361032560013705 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-mail for the canonical source repository
 * @copyright https://github.com/laminas/laminas-mail/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-mail/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Mail\Header;

use function in_array;

/**
 * @internal
 */
class ListParser
{
    public const CHAR_QUOTES = ['\'', '"'];
    public const CHAR_DELIMS = [',', ';'];
    public const CHAR_ESCAPE = '\\';

    /**
     * @param string $value
     * @param array $delims Delimiters allowed between values; parser will
     *     split on these, as long as they are not within quotes. Defaults
     *     to ListParser::CHAR_DELIMS.
     * @return array
     */
    public static function parse($value, array $delims = self::CHAR_DELIMS)
    {
        $values            = [];
        $length            = strlen($value);
        $currentValue      = '';
        $inEscape          = false;
        $inQuote           = false;
        $currentQuoteDelim = null;

        for ($i = 0; $i < $length; $i += 1) {
            $char = $value[$i];

            // If we are in an escape sequence, append the character and continue.
            if ($inEscape) {
                $currentValue .= $char;
                $inEscape = false;
                continue;
            }

            // If we are not in a quoted string, and have a delimiter, append
            // the current value to the list, and reset the current value.
            if (in_array($char, $delims, true) && ! $inQuote) {
                $values [] = $currentValue;
                $currentValue = '';
                continue;
            }

            // Append the character to the current value
            $currentValue .= $char;

            // Escape sequence discovered.
            if (self::CHAR_ESCAPE === $char) {
                $inEscape = true;
                continue;
            }

            // If the character is not a quote character, we are done
            // processing it.
            if (! in_array($char, self::CHAR_QUOTES)) {
                continue;
            }

            // If the character matches a previously matched quote delimiter,
            // we reset our quote status and the currently opened quote
            // delimiter.
            if ($char === $currentQuoteDelim) {
                $inQuote = false;
                $currentQuoteDelim = null;
                continue;
            }

            // If already in quote and the character does not match the previously
            // matched quote delimiter, we're done here.
            if ($inQuote) {
                continue;
            }

            // Otherwise, we're starting a quoted string.
            $inQuote = true;
            $currentQuoteDelim = $char;
        }

        // If we reached the end of the string and still have a current value,
        // append it to the list (no delimiter was reached).
        if ('' !== $currentValue) {
            $values [] = $currentValue;
        }

        return $values;
    }
}
laminas-mail/src/Header/References.php000064400000000673147361032560013676 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-mail for the canonical source repository
 * @copyright https://github.com/laminas/laminas-mail/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-mail/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Mail\Header;

class References extends IdentificationField
{
    protected $fieldName = 'References';
    protected static $type = 'references';
}
laminas-mail/src/Header/Bcc.php000064400000000755147361032560012305 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-mail for the canonical source repository
 * @copyright https://github.com/laminas/laminas-mail/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-mail/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Mail\Header;

class Bcc extends AbstractAddressList
{
    /**
     * @var string
     */
    protected $fieldName = 'Bcc';

    /**
     * @var string
     */
    protected static $type = 'bcc';
}
laminas-mail/src/Header/To.php000064400000000643147361032560012174 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-mail for the canonical source repository
 * @copyright https://github.com/laminas/laminas-mail/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-mail/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Mail\Header;

class To extends AbstractAddressList
{
    protected $fieldName = 'To';
    protected static $type = 'to';
}
laminas-mail/src/Header/ContentTransferEncoding.php000064400000005573147361032560016407 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-mail for the canonical source repository
 * @copyright https://github.com/laminas/laminas-mail/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-mail/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Mail\Header;

class ContentTransferEncoding implements HeaderInterface
{
    /**
     * Allowed Content-Transfer-Encoding parameters specified by RFC 1521
     * (reduced set)
     * @var array
     */
    protected static $allowedTransferEncodings = [
        '7bit',
        '8bit',
        'quoted-printable',
        'base64',
        'binary',
        /*
         * not implemented:
         * x-token: 'X-'
         */
    ];

    /**
     * @var string
     */
    protected $transferEncoding;

    /**
     * @var array
     */
    protected $parameters = [];

    public static function fromString($headerLine)
    {
        list($name, $value) = GenericHeader::splitHeaderLine($headerLine);
        $value = HeaderWrap::mimeDecodeValue($value);

        // check to ensure proper header type for this factory
        if (strtolower($name) !== 'content-transfer-encoding') {
            throw new Exception\InvalidArgumentException('Invalid header line for Content-Transfer-Encoding string');
        }

        $header = new static();
        $header->setTransferEncoding($value);

        return $header;
    }

    public function getFieldName()
    {
        return 'Content-Transfer-Encoding';
    }

    public function getFieldValue($format = HeaderInterface::FORMAT_RAW)
    {
        return $this->transferEncoding;
    }

    public function setEncoding($encoding)
    {
        // Header must be always in US-ASCII
        return $this;
    }

    public function getEncoding()
    {
        return 'ASCII';
    }

    public function toString()
    {
        return 'Content-Transfer-Encoding: ' . $this->getFieldValue();
    }

    /**
     * Set the content transfer encoding
     *
     * @param  string $transferEncoding
     * @throws Exception\InvalidArgumentException
     * @return $this
     */
    public function setTransferEncoding($transferEncoding)
    {
        // Per RFC 1521, the value of the header is not case sensitive
        $transferEncoding = strtolower($transferEncoding);

        if (! in_array($transferEncoding, static::$allowedTransferEncodings)) {
            throw new Exception\InvalidArgumentException(sprintf(
                '%s expects one of "'. implode(', ', static::$allowedTransferEncodings) . '"; received "%s"',
                __METHOD__,
                (string) $transferEncoding
            ));
        }
        $this->transferEncoding = $transferEncoding;
        return $this;
    }

    /**
     * Retrieve the content transfer encoding
     *
     * @return string
     */
    public function getTransferEncoding()
    {
        return $this->transferEncoding;
    }
}
laminas-mail/src/Header/IdentificationField.php000064400000006227147361032560015513 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-mail for the canonical source repository
 * @copyright https://github.com/laminas/laminas-mail/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-mail/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Mail\Header;

use Laminas\Mail\Headers;

/**
 * @see https://tools.ietf.org/html/rfc5322#section-3.6.4
 */
abstract class IdentificationField implements HeaderInterface
{
    /**
     * @var string lower case field name
     */
    protected static $type;

    /**
     * @var string[]
     */
    protected $messageIds;

    /**
     * @var string
     */
    protected $fieldName;

    /**
     * @param string $headerLine
     * @return static
     */
    public static function fromString($headerLine)
    {
        list($name, $value) = GenericHeader::splitHeaderLine($headerLine);
        if (strtolower($name) !== static::$type) {
            throw new Exception\InvalidArgumentException(sprintf(
                'Invalid header line for "%s" string',
                __CLASS__
            ));
        }

        $value = HeaderWrap::mimeDecodeValue($value);

        $messageIds = array_map(
            [self::class, "trimMessageId"],
            explode(" ", $value)
        );

        $header = new static();
        $header->setIds($messageIds);

        return $header;
    }

    /**
     * @param string $id
     * @return string
     */
    private static function trimMessageId($id)
    {
        return trim($id, "\t\n\r\0\x0B<>");
    }

    /**
     * @return string
     */
    public function getFieldName()
    {
        return $this->fieldName;
    }

    /**
     * @param bool $format
     * @return string
     */
    public function getFieldValue($format = HeaderInterface::FORMAT_RAW)
    {
        return implode(Headers::FOLDING, array_map(function ($id) {
            return sprintf('<%s>', $id);
        }, $this->messageIds));
    }

    /**
     * @param string $encoding Ignored; headers of this type MUST always be in
     *     ASCII.
     * @return static This method is a no-op, and implements a fluent interface.
     */
    public function setEncoding($encoding)
    {
        return $this;
    }

    /**
     * @return string Always returns ASCII
     */
    public function getEncoding()
    {
        return 'ASCII';
    }

    /**
     * @return string
     */
    public function toString()
    {
        return sprintf('%s: %s', $this->getFieldName(), $this->getFieldValue());
    }

    /**
     * Set the message ids
     *
     * @param string[] $ids
     * @return static This method implements a fluent interface.
     */
    public function setIds($ids)
    {
        foreach ($ids as $id) {
            if (! HeaderValue::isValid($id)
                || preg_match("/[\r\n]/", $id)
            ) {
                throw new Exception\InvalidArgumentException('Invalid ID detected');
            }
        }

        $this->messageIds = array_map([self::class, "trimMessageId"], $ids);
        return $this;
    }

    /**
     * Retrieve the message ids
     *
     * @return string[]
     */
    public function getIds()
    {
        return $this->messageIds;
    }
}
laminas-mail/src/Header/HeaderName.php000064400000003367147361032560013611 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-mail for the canonical source repository
 * @copyright https://github.com/laminas/laminas-mail/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-mail/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Mail\Header;

final class HeaderName
{
    /**
     * No public constructor.
     */
    private function __construct()
    {
    }

    /**
     * Filter the header name according to RFC 2822
     *
     * @see    http://www.rfc-base.org/txt/rfc-2822.txt (section 2.2)
     * @param  string $name
     * @return string
     */
    public static function filter($name)
    {
        $result = '';
        $tot    = strlen($name);
        for ($i = 0; $i < $tot; $i += 1) {
            $ord = ord($name[$i]);
            if ($ord > 32 && $ord < 127 && $ord !== 58) {
                $result .= $name[$i];
            }
        }
        return $result;
    }

    /**
     * Determine if the header name contains any invalid characters.
     *
     * @param string $name
     * @return bool
     */
    public static function isValid($name)
    {
        $tot = strlen($name);
        for ($i = 0; $i < $tot; $i += 1) {
            $ord = ord($name[$i]);
            if ($ord < 33 || $ord > 126 || $ord === 58) {
                return false;
            }
        }
        return true;
    }

    /**
     * Assert that the header name is valid.
     *
     * Raises an exception if invalid.
     *
     * @param string $name
     * @throws Exception\RuntimeException
     * @return void
     */
    public static function assertValid($name)
    {
        if (! self::isValid($name)) {
            throw new Exception\RuntimeException('Invalid header name detected');
        }
    }
}
laminas-mail/src/Header/Cc.php000064400000000643147361032560012137 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-mail for the canonical source repository
 * @copyright https://github.com/laminas/laminas-mail/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-mail/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Mail\Header;

class Cc extends AbstractAddressList
{
    protected $fieldName = 'Cc';
    protected static $type = 'cc';
}
laminas-mail/src/Header/ContentType.php000064400000012057147361032560014070 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-mail for the canonical source repository
 * @copyright https://github.com/laminas/laminas-mail/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-mail/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Mail\Header;

use Laminas\Mail\Headers;
use Laminas\Mime\Mime;

class ContentType implements UnstructuredInterface
{
    /**
     * @var string
     */
    protected $type;

    /**
     * Header encoding
     *
     * @var string
     */
    protected $encoding = 'ASCII';

    /**
     * @var array
     */
    protected $parameters = [];

    public static function fromString($headerLine)
    {
        list($name, $value) = GenericHeader::splitHeaderLine($headerLine);
        $value = HeaderWrap::mimeDecodeValue($value);

        // check to ensure proper header type for this factory
        if (strtolower($name) !== 'content-type') {
            throw new Exception\InvalidArgumentException('Invalid header line for Content-Type string');
        }

        $value  = str_replace(Headers::FOLDING, ' ', $value);
        $parts = explode(';', $value, 2);

        $header = new static();
        $header->setType($parts[0]);

        if (isset($parts[1])) {
            $values = ListParser::parse(trim($parts[1]), [';', '=']);
            $length = count($values);

            for ($i = 0; $i < $length; $i += 2) {
                $value = $values[$i + 1];
                $value = trim($value, "'\" \t\n\r\0\x0B");
                $header->addParameter($values[$i], $value);
            }
        }

        return $header;
    }

    public function getFieldName()
    {
        return 'Content-Type';
    }

    public function getFieldValue($format = HeaderInterface::FORMAT_RAW)
    {
        $prepared = $this->type;
        if (empty($this->parameters)) {
            return $prepared;
        }

        $values = [$prepared];
        foreach ($this->parameters as $attribute => $value) {
            if (HeaderInterface::FORMAT_ENCODED === $format && ! Mime::isPrintable($value)) {
                $this->encoding = 'UTF-8';
                $value = HeaderWrap::wrap($value, $this);
                $this->encoding = 'ASCII';
            }

            $values[] = sprintf('%s="%s"', $attribute, $value);
        }

        return implode(';' . Headers::FOLDING, $values);
    }

    public function setEncoding($encoding)
    {
        $this->encoding = $encoding;
        return $this;
    }

    public function getEncoding()
    {
        return $this->encoding;
    }

    public function toString()
    {
        return 'Content-Type: ' . $this->getFieldValue(HeaderInterface::FORMAT_ENCODED);
    }

    /**
     * Set the content type
     *
     * @param  string $type
     * @throws Exception\InvalidArgumentException
     * @return ContentType
     */
    public function setType($type)
    {
        if (! preg_match('/^[a-z-]+\/[a-z0-9.+-]+$/i', $type)) {
            throw new Exception\InvalidArgumentException(sprintf(
                '%s expects a value in the format "type/subtype"; received "%s"',
                __METHOD__,
                (string) $type
            ));
        }
        $this->type = $type;
        return $this;
    }

    /**
     * Retrieve the content type
     *
     * @return string
     */
    public function getType()
    {
        return $this->type;
    }

    /**
     * Add a parameter pair
     *
     * @param  string $name
     * @param  string $value
     * @return ContentType
     * @throws Exception\InvalidArgumentException for parameter names that do not follow RFC 2822
     * @throws Exception\InvalidArgumentException for parameter values that do not follow RFC 2822
     */
    public function addParameter($name, $value)
    {
        $name  = trim(strtolower($name));
        $value = (string) $value;

        if (! HeaderValue::isValid($name)) {
            throw new Exception\InvalidArgumentException('Invalid content-type parameter name detected');
        }
        if (! HeaderWrap::canBeEncoded($value)) {
            throw new Exception\InvalidArgumentException(
                'Parameter value must be composed of printable US-ASCII or UTF-8 characters.'
            );
        }

        $this->parameters[$name] = $value;
        return $this;
    }

    /**
     * Get all parameters
     *
     * @return array
     */
    public function getParameters()
    {
        return $this->parameters;
    }

    /**
     * Get a parameter by name
     *
     * @param  string $name
     * @return null|string
     */
    public function getParameter($name)
    {
        $name = strtolower($name);
        if (isset($this->parameters[$name])) {
            return $this->parameters[$name];
        }

        return null;
    }

    /**
     * Remove a named parameter
     *
     * @param  string $name
     * @return bool
     */
    public function removeParameter($name)
    {
        $name = strtolower($name);
        if (isset($this->parameters[$name])) {
            unset($this->parameters[$name]);
            return true;
        }
        return false;
    }
}
laminas-mail/src/Header/Date.php000064400000003233147361032560012465 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-mail for the canonical source repository
 * @copyright https://github.com/laminas/laminas-mail/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-mail/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Mail\Header;

/**
 * @todo       Add accessors for setting date from DateTime, Laminas\Date, or a string
 */
class Date implements HeaderInterface
{
    /**
     * @var string
     */
    protected $value;

    public static function fromString($headerLine)
    {
        list($name, $value) = GenericHeader::splitHeaderLine($headerLine);
        $value = HeaderWrap::mimeDecodeValue($value);

        // check to ensure proper header type for this factory
        if (strtolower($name) !== 'date') {
            throw new Exception\InvalidArgumentException('Invalid header line for Date string');
        }

        $header = new static($value);

        return $header;
    }

    public function __construct($value)
    {
        if (! HeaderValue::isValid($value)) {
            throw new Exception\InvalidArgumentException('Invalid Date header value detected');
        }
        $this->value = $value;
    }

    public function getFieldName()
    {
        return 'Date';
    }

    public function getFieldValue($format = HeaderInterface::FORMAT_RAW)
    {
        return $this->value;
    }

    public function setEncoding($encoding)
    {
        // This header must be always in US-ASCII
        return $this;
    }

    public function getEncoding()
    {
        return 'ASCII';
    }

    public function toString()
    {
        return 'Date: ' . $this->getFieldValue();
    }
}
laminas-mail/src/Header/From.php000064400000000651147361032560012514 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-mail for the canonical source repository
 * @copyright https://github.com/laminas/laminas-mail/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-mail/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Mail\Header;

class From extends AbstractAddressList
{
    protected $fieldName = 'From';
    protected static $type = 'from';
}
laminas-mail/src/Header/GenericHeader.php000064400000012157147361032560014302 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-mail for the canonical source repository
 * @copyright https://github.com/laminas/laminas-mail/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-mail/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Mail\Header;

use Laminas\Mime\Mime;

class GenericHeader implements HeaderInterface, UnstructuredInterface
{
    /**
     * @var string
     */
    protected $fieldName = null;

    /**
     * @var string
     */
    protected $fieldValue = null;

    /**
     * Header encoding
     *
     * @var null|string
     */
    protected $encoding;

    /**
     * @param string $headerLine
     * @return GenericHeader
     */
    public static function fromString($headerLine)
    {
        list($name, $value) = self::splitHeaderLine($headerLine);
        $value  = HeaderWrap::mimeDecodeValue($value);
        $header = new static($name, $value);

        return $header;
    }

    /**
     * Splits the header line in `name` and `value` parts.
     *
     * @param string $headerLine
     * @return string[] `name` in the first index and `value` in the second.
     * @throws Exception\InvalidArgumentException If header does not match with the format ``name:value``
     */
    public static function splitHeaderLine($headerLine)
    {
        $parts = explode(':', $headerLine, 2);
        if (count($parts) !== 2) {
            throw new Exception\InvalidArgumentException('Header must match with the format "name:value"');
        }

        if (! HeaderName::isValid($parts[0])) {
            throw new Exception\InvalidArgumentException('Invalid header name detected');
        }

        if (! HeaderValue::isValid($parts[1])) {
            throw new Exception\InvalidArgumentException('Invalid header value detected');
        }

        $parts[1] = ltrim($parts[1]);

        return $parts;
    }

    /**
     * Constructor
     *
     * @param string $fieldName  Optional
     * @param string $fieldValue Optional
     */
    public function __construct($fieldName = null, $fieldValue = null)
    {
        if ($fieldName) {
            $this->setFieldName($fieldName);
        }

        if ($fieldValue !== null) {
            $this->setFieldValue($fieldValue);
        }
    }

    /**
     * Set header name
     *
     * @param  string $fieldName
     * @return GenericHeader
     * @throws Exception\InvalidArgumentException;
     */
    public function setFieldName($fieldName)
    {
        if (! is_string($fieldName) || empty($fieldName)) {
            throw new Exception\InvalidArgumentException('Header name must be a string');
        }

        // Pre-filter to normalize valid characters, change underscore to dash
        $fieldName = str_replace(' ', '-', ucwords(str_replace(['_', '-'], ' ', $fieldName)));

        if (! HeaderName::isValid($fieldName)) {
            throw new Exception\InvalidArgumentException(
                'Header name must be composed of printable US-ASCII characters, except colon.'
            );
        }

        $this->fieldName = $fieldName;
        return $this;
    }

    public function getFieldName()
    {
        return $this->fieldName;
    }

    /**
     * Set header value
     *
     * @param  string $fieldValue
     * @return GenericHeader
     * @throws Exception\InvalidArgumentException;
     */
    public function setFieldValue($fieldValue)
    {
        $fieldValue = (string) $fieldValue;

        if (! HeaderWrap::canBeEncoded($fieldValue)) {
            throw new Exception\InvalidArgumentException(
                'Header value must be composed of printable US-ASCII characters and valid folding sequences.'
            );
        }

        $this->fieldValue = $fieldValue;
        $this->encoding   = null;

        return $this;
    }

    public function getFieldValue($format = HeaderInterface::FORMAT_RAW)
    {
        if (HeaderInterface::FORMAT_ENCODED === $format) {
            return HeaderWrap::wrap($this->fieldValue, $this);
        }

        return $this->fieldValue;
    }

    public function setEncoding($encoding)
    {
        if ($encoding === $this->encoding) {
            return $this;
        }

        if ($encoding === null) {
            $this->encoding = null;
            return $this;
        }

        $encoding = strtoupper($encoding);
        if ($encoding === 'UTF-8') {
            $this->encoding = $encoding;
            return $this;
        }

        if ($encoding === 'ASCII' && Mime::isPrintable($this->fieldValue)) {
            $this->encoding = $encoding;
            return $this;
        }

        $this->encoding = null;

        return $this;
    }

    public function getEncoding()
    {
        if (! $this->encoding) {
            $this->encoding = Mime::isPrintable($this->fieldValue) ? 'ASCII' : 'UTF-8';
        }

        return $this->encoding;
    }

    public function toString()
    {
        $name = $this->getFieldName();
        if (empty($name)) {
            throw new Exception\RuntimeException('Header name is not set, use setFieldName()');
        }
        $value = $this->getFieldValue(HeaderInterface::FORMAT_ENCODED);

        return $name . ': ' . $value;
    }
}
laminas-mail/src/Header/HeaderValue.php000064400000005506147361032560014002 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-mail for the canonical source repository
 * @copyright https://github.com/laminas/laminas-mail/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-mail/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Mail\Header;

final class HeaderValue
{
    /**
     * No public constructor.
     */
    private function __construct()
    {
    }

    /**
     * Filter the header value according to RFC 2822
     *
     * @see    http://www.rfc-base.org/txt/rfc-2822.txt (section 2.2)
     * @param  string $value
     * @return string
     */
    public static function filter($value)
    {
        $result = '';
        $total  = strlen($value);

        // Filter for CR and LF characters, leaving CRLF + WSP sequences for
        // Long Header Fields (section 2.2.3 of RFC 2822)
        for ($i = 0; $i < $total; $i += 1) {
            $ord = ord($value[$i]);
            if ($ord === 10 || $ord > 127) {
                continue;
            }

            if ($ord === 13) {
                if ($i + 2 >= $total) {
                    continue;
                }

                $lf = ord($value[$i + 1]);
                $sp = ord($value[$i + 2]);

                if ($lf !== 10 || $sp !== 32) {
                    continue;
                }

                $result .= "\r\n ";
                $i += 2;
                continue;
            }

            $result .= $value[$i];
        }

        return $result;
    }

    /**
     * Determine if the header value contains any invalid characters.
     *
     * @see    http://www.rfc-base.org/txt/rfc-2822.txt (section 2.2)
     * @param string $value
     * @return bool
     */
    public static function isValid($value)
    {
        $total = strlen($value);
        for ($i = 0; $i < $total; $i += 1) {
            $ord = ord($value[$i]);

            // bare LF means we aren't valid
            if ($ord === 10 || $ord > 127) {
                return false;
            }

            if ($ord === 13) {
                if ($i + 2 >= $total) {
                    return false;
                }

                $lf = ord($value[$i + 1]);
                $sp = ord($value[$i + 2]);

                if ($lf !== 10 || ! in_array($sp, [9, 32], true)) {
                    return false;
                }

                // skip over the LF following this
                $i += 2;
            }
        }

        return true;
    }

    /**
     * Assert that the header value is valid.
     *
     * Raises an exception if invalid.
     *
     * @param string $value
     * @throws Exception\RuntimeException
     * @return void
     */
    public static function assertValid($value)
    {
        if (! self::isValid($value)) {
            throw new Exception\RuntimeException('Invalid header value detected');
        }
    }
}
laminas-mail/src/Header/GenericMultiHeader.php000064400000003415147361032560015312 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-mail for the canonical source repository
 * @copyright https://github.com/laminas/laminas-mail/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-mail/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Mail\Header;

/**
 * Generic class for Headers with multiple occurs in the same message
 */
class GenericMultiHeader extends GenericHeader implements MultipleHeadersInterface
{
    public static function fromString($headerLine)
    {
        list($fieldName, $fieldValue) = GenericHeader::splitHeaderLine($headerLine);
        $fieldValue = HeaderWrap::mimeDecodeValue($fieldValue);

        if (strpos($fieldValue, ',')) {
            $headers = [];
            foreach (explode(',', $fieldValue) as $multiValue) {
                $headers[] = new static($fieldName, $multiValue);
            }
            return $headers;
        }

        return new static($fieldName, $fieldValue);
    }

    /**
     * Cast multiple header objects to a single string header
     *
     * @param  array $headers
     * @throws Exception\InvalidArgumentException
     * @return string
     */
    public function toStringMultipleHeaders(array $headers)
    {
        $name   = $this->getFieldName();
        $values = [$this->getFieldValue(HeaderInterface::FORMAT_ENCODED)];

        foreach ($headers as $header) {
            if (! $header instanceof static) {
                throw new Exception\InvalidArgumentException(
                    'This method toStringMultipleHeaders was expecting an array of headers of the same type'
                );
            }
            $values[] = $header->getFieldValue(HeaderInterface::FORMAT_ENCODED);
        }

        return $name . ': ' . implode(',', $values);
    }
}
laminas-mail/src/Header/AbstractAddressList.php000064400000015614147361032560015523 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-mail for the canonical source repository
 * @copyright https://github.com/laminas/laminas-mail/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-mail/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Mail\Header;

use Laminas\Mail\Address;
use Laminas\Mail\AddressList;
use Laminas\Mail\Headers;
use TrueBV\Exception\OutOfBoundsException;
use TrueBV\Punycode;

/**
 * Base class for headers composing address lists (to, from, cc, bcc, reply-to)
 */
abstract class AbstractAddressList implements HeaderInterface
{
    /**
     * @var AddressList
     */
    protected $addressList;

    /**
     * @var string Normalized field name
     */
    protected $fieldName;

    /**
     * Header encoding
     *
     * @var string
     */
    protected $encoding = 'ASCII';

    /**
     * @var string lower case field name
     */
    protected static $type;

    /**
     * @var Punycode|null
     */
    private static $punycode;

    public static function fromString($headerLine)
    {
        list($fieldName, $fieldValue) = GenericHeader::splitHeaderLine($headerLine);
        if (strtolower($fieldName) !== static::$type) {
            throw new Exception\InvalidArgumentException(sprintf(
                'Invalid header line for "%s" string',
                __CLASS__
            ));
        }

        // split value on ","
        $fieldValue = str_replace(Headers::FOLDING, ' ', $fieldValue);
        $fieldValue = preg_replace('/[^:]+:([^;]*);/', '$1,', $fieldValue);
        $values = ListParser::parse($fieldValue);

        $wasEncoded = false;
        $addresses = array_map(
            function ($value) use (&$wasEncoded) {
                $decodedValue = HeaderWrap::mimeDecodeValue($value);
                $wasEncoded = $wasEncoded || ($decodedValue !== $value);

                $value = trim($decodedValue);

                $comments = self::getComments($value);
                $value = self::stripComments($value);

                $value = preg_replace(
                    [
                        '#(?<!\\\)"(.*)(?<!\\\)"#',            // quoted-text
                        '#\\\([\x01-\x09\x0b\x0c\x0e-\x7f])#', // quoted-pair
                    ],
                    [
                        '\\1',
                        '\\1',
                    ],
                    $value
                );

                return empty($value) ? null : Address::fromString($value, $comments);
            },
            $values
        );
        $addresses = array_filter($addresses);

        $header = new static();
        if ($wasEncoded) {
            $header->setEncoding('UTF-8');
        }

        /** @var AddressList $addressList */
        $addressList = $header->getAddressList();
        foreach ($addresses as $address) {
            $addressList->add($address);
        }

        return $header;
    }

    public function getFieldName()
    {
        return $this->fieldName;
    }

    /**
     * Safely convert UTF-8 encoded domain name to ASCII
     * @param string $domainName the UTF-8 encoded email
     * @return string
     */
    protected function idnToAscii($domainName)
    {
        if (null === self::$punycode) {
            self::$punycode = new Punycode();
        }
        try {
            return self::$punycode->encode($domainName);
        } catch (OutOfBoundsException $e) {
            return $domainName;
        }
    }

    public function getFieldValue($format = HeaderInterface::FORMAT_RAW)
    {
        $emails   = [];
        $encoding = $this->getEncoding();

        foreach ($this->getAddressList() as $address) {
            $email = $address->getEmail();
            $name  = $address->getName();

            // quote $name if value requires so
            if (! empty($name) && (false !== strpos($name, ',') || false !== strpos($name, ';'))) {
                // FIXME: what if name contains double quote?
                $name = sprintf('"%s"', $name);
            }

            if ($format === HeaderInterface::FORMAT_ENCODED
                && 'ASCII' !== $encoding
            ) {
                if (! empty($name)) {
                    $name = HeaderWrap::mimeEncodeValue($name, $encoding);
                }

                if (preg_match('/^(.+)@([^@]+)$/', $email, $matches)) {
                    $localPart = $matches[1];
                    $hostname  = $this->idnToAscii($matches[2]);
                    $email = sprintf('%s@%s', $localPart, $hostname);
                }
            }

            if (empty($name)) {
                $emails[] = $email;
            } else {
                $emails[] = sprintf('%s <%s>', $name, $email);
            }
        }

        // Ensure the values are valid before sending them.
        if ($format !== HeaderInterface::FORMAT_RAW) {
            foreach ($emails as $email) {
                HeaderValue::assertValid($email);
            }
        }

        return implode(',' . Headers::FOLDING, $emails);
    }

    public function setEncoding($encoding)
    {
        $this->encoding = $encoding;
        return $this;
    }

    public function getEncoding()
    {
        return $this->encoding;
    }

    /**
     * Set address list for this header
     *
     * @param  AddressList $addressList
     */
    public function setAddressList(AddressList $addressList)
    {
        $this->addressList = $addressList;
    }

    /**
     * Get address list managed by this header
     *
     * @return AddressList
     */
    public function getAddressList()
    {
        if (null === $this->addressList) {
            $this->setAddressList(new AddressList());
        }
        return $this->addressList;
    }

    public function toString()
    {
        $name  = $this->getFieldName();
        $value = $this->getFieldValue(HeaderInterface::FORMAT_ENCODED);
        return (empty($value)) ? '' : sprintf('%s: %s', $name, $value);
    }

    /**
     * Retrieve comments from value, if any.
     *
     * Supposed to be private, protected as a workaround for PHP bug 68194
     *
     * @param string $value
     * @return string
     */
    protected static function getComments($value)
    {
        $matches = [];
        preg_match_all(
            '/\\(
                (?P<comment>(
                    \\\\.|
                    [^\\\\)]
                )+)
            \\)/x',
            $value,
            $matches
        );
        return isset($matches['comment']) ? implode(', ', $matches['comment']) : '';
    }

    /**
     * Strip all comments from value, if any.
     *
     * Supposed to be private, protected as a workaround for PHP bug 68194
     *
     * @param string $value
     * @return string
     */
    protected static function stripComments($value)
    {
        return preg_replace(
            '/\\(
                (
                    \\\\.|
                    [^\\\\)]
                )+
            \\)/x',
            '',
            $value
        );
    }
}
laminas-mail/src/Header/HeaderLocatorInterface.php000064400000001241147361032560016142 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-mail for the canonical source repository
 * @copyright https://github.com/laminas/laminas-mail/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-mail/blob/master/LICENSE.md New BSD License
 */

declare(strict_types=1);

namespace Laminas\Mail\Header;

/**
 * Interface detailing how to resolve header names to classes.
 */
interface HeaderLocatorInterface
{
    public function get(string $name, ?string $default = null): ?string;

    public function has(string $name): bool;

    public function add(string $name, string $class): void;

    public function remove(string $name): void;
}
laminas-mail/src/Header/Subject.php000064400000005503147361032560013211 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-mail for the canonical source repository
 * @copyright https://github.com/laminas/laminas-mail/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-mail/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Mail\Header;

use Laminas\Mime\Mime;

/**
 * Subject header class methods.
 *
 * @see https://tools.ietf.org/html/rfc2822 RFC 2822
 * @see https://tools.ietf.org/html/rfc2047 RFC 2047
 */
class Subject implements UnstructuredInterface
{
    /**
     * @var string
     */
    protected $subject = '';

    /**
     * Header encoding
     *
     * @var null|string
     */
    protected $encoding;

    public static function fromString($headerLine)
    {
        list($name, $value) = GenericHeader::splitHeaderLine($headerLine);
        $value = HeaderWrap::mimeDecodeValue($value);

        // check to ensure proper header type for this factory
        if (strtolower($name) !== 'subject') {
            throw new Exception\InvalidArgumentException('Invalid header line for Subject string');
        }

        $header = new static();
        $header->setSubject($value);

        return $header;
    }

    public function getFieldName()
    {
        return 'Subject';
    }

    public function getFieldValue($format = HeaderInterface::FORMAT_RAW)
    {
        if (HeaderInterface::FORMAT_ENCODED === $format) {
            return HeaderWrap::wrap($this->subject, $this);
        }

        return $this->subject;
    }

    public function setEncoding($encoding)
    {
        if ($encoding === $this->encoding) {
            return $this;
        }

        if ($encoding === null) {
            $this->encoding = null;
            return $this;
        }

        $encoding = strtoupper($encoding);
        if ($encoding === 'UTF-8') {
            $this->encoding = $encoding;
            return $this;
        }

        if ($encoding === 'ASCII' && Mime::isPrintable($this->subject)) {
            $this->encoding = $encoding;
            return $this;
        }

        $this->encoding = null;

        return $this;
    }

    public function getEncoding()
    {
        if (! $this->encoding) {
            $this->encoding = Mime::isPrintable($this->subject) ? 'ASCII' : 'UTF-8';
        }

        return $this->encoding;
    }

    public function setSubject($subject)
    {
        $subject = (string) $subject;

        if (! HeaderWrap::canBeEncoded($subject)) {
            throw new Exception\InvalidArgumentException(
                'Subject value must be composed of printable US-ASCII or UTF-8 characters.'
            );
        }

        $this->subject  = $subject;
        $this->encoding = null;

        return $this;
    }

    public function toString()
    {
        return 'Subject: ' . $this->getFieldValue(HeaderInterface::FORMAT_ENCODED);
    }
}
laminas-mail/src/Header/HeaderWrap.php000064400000011523147361032560013633 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-mail for the canonical source repository
 * @copyright https://github.com/laminas/laminas-mail/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-mail/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Mail\Header;

use Laminas\Mail\Headers;
use Laminas\Mime\Mime;

/**
 * Utility class used for creating wrapped or MIME-encoded versions of header
 * values.
 */
abstract class HeaderWrap
{
    /**
     * Wrap a long header line
     *
     * @param  string          $value
     * @param  HeaderInterface $header
     * @return string
     */
    public static function wrap($value, HeaderInterface $header)
    {
        if ($header instanceof UnstructuredInterface) {
            return static::wrapUnstructuredHeader($value, $header);
        } elseif ($header instanceof StructuredInterface) {
            return static::wrapStructuredHeader($value, $header);
        }
        return $value;
    }

    /**
     * Wrap an unstructured header line
     *
     * Wrap at 78 characters or before, based on whitespace.
     *
     * @param string          $value
     * @param HeaderInterface $header
     * @return string
     */
    protected static function wrapUnstructuredHeader($value, HeaderInterface $header)
    {
        $encoding = $header->getEncoding();
        if ($encoding == 'ASCII') {
            return wordwrap($value, 78, Headers::FOLDING);
        }
        return static::mimeEncodeValue($value, $encoding, 78);
    }

    /**
     * Wrap a structured header line
     *
     * @param  string              $value
     * @param  StructuredInterface $header
     * @return string
     */
    protected static function wrapStructuredHeader($value, StructuredInterface $header)
    {
        $delimiter = $header->getDelimiter();

        $length = strlen($value);
        $lines  = [];
        $temp   = '';
        for ($i = 0; $i < $length; $i++) {
            $temp .= $value[$i];
            if ($value[$i] == $delimiter) {
                $lines[] = $temp;
                $temp    = '';
            }
        }
        return implode(Headers::FOLDING, $lines);
    }

    /**
     * MIME-encode a value
     *
     * Performs quoted-printable encoding on a value, setting maximum
     * line-length to 998.
     *
     * @param  string $value
     * @param  string $encoding
     * @param  int    $lineLength maximum line-length, by default 998
     * @return string Returns the mime encode value without the last line ending
     */
    public static function mimeEncodeValue($value, $encoding, $lineLength = 998)
    {
        return Mime::encodeQuotedPrintableHeader($value, $encoding, $lineLength, Headers::EOL);
    }

    /**
     * MIME-decode a value
     *
     * Performs quoted-printable decoding on a value.
     *
     * @param  string $value
     * @return string Returns the mime encode value without the last line ending
     */
    public static function mimeDecodeValue($value)
    {
        // unfold first, because iconv_mime_decode is discarding "\n" with no apparent reason
        // making the resulting value no longer valid.

        // see https://tools.ietf.org/html/rfc2822#section-2.2.3 about unfolding
        $parts = explode(Headers::FOLDING, $value);
        $value = implode(' ', $parts);

        $decodedValue = iconv_mime_decode($value, ICONV_MIME_DECODE_CONTINUE_ON_ERROR, 'UTF-8');

        // imap (unlike iconv) can handle multibyte headers which are splitted across multiple line
        if (self::isNotDecoded($value, $decodedValue) && extension_loaded('imap')) {
            return array_reduce(
                imap_mime_header_decode(imap_utf8($value)),
                function ($accumulator, $headerPart) {
                    return $accumulator . $headerPart->text;
                },
                ''
            );
        }

        return $decodedValue;
    }

    private static function isNotDecoded($originalValue, $value)
    {
        return 0 === strpos($value, '=?')
            && strlen($value) - 2 === strpos($value, '?=')
            && false !== strpos($originalValue, $value);
    }

    /**
     * Test if is possible apply MIME-encoding
     *
     * @param string $value
     * @return bool
     */
    public static function canBeEncoded($value)
    {
        // avoid any wrapping by specifying line length long enough
        // "test" -> 4
        // "x-test: =?ISO-8859-1?B?dGVzdA==?=" -> 33
        //  8       +2          +3         +3  -> 16
        $charset = 'UTF-8';
        $lineLength = strlen($value) * 4 + strlen($charset) + 16;

        $preferences = [
            'scheme' => 'Q',
            'input-charset' => $charset,
            'output-charset' => $charset,
            'line-length' => $lineLength,
        ];

        $encoded = iconv_mime_encode('x-test', $value, $preferences);

        return (false !== $encoded);
    }
}
laminas-mail/src/Header/MimeVersion.php000064400000004211147361032560014042 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-mail for the canonical source repository
 * @copyright https://github.com/laminas/laminas-mail/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-mail/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Mail\Header;

class MimeVersion implements HeaderInterface
{
    /**
     * @var string Version string
     */
    protected $version = '1.0';

    public static function fromString($headerLine)
    {
        list($name, $value) = GenericHeader::splitHeaderLine($headerLine);
        $value = HeaderWrap::mimeDecodeValue($value);

        // check to ensure proper header type for this factory
        if (strtolower($name) !== 'mime-version') {
            throw new Exception\InvalidArgumentException('Invalid header line for MIME-Version string');
        }

        // Check for version, and set if found
        $header = new static();
        if (preg_match('/^(?P<version>\d+\.\d+)$/', $value, $matches)) {
            $header->setVersion($matches['version']);
        }

        return $header;
    }

    public function getFieldName()
    {
        return 'MIME-Version';
    }

    public function getFieldValue($format = HeaderInterface::FORMAT_RAW)
    {
        return $this->version;
    }

    public function setEncoding($encoding)
    {
        // This header must be always in US-ASCII
        return $this;
    }

    public function getEncoding()
    {
        return 'ASCII';
    }

    public function toString()
    {
        return 'MIME-Version: ' . $this->getFieldValue();
    }

    /**
     * Set the version string used in this header
     *
     * @param  string $version
     * @return MimeVersion
     */
    public function setVersion($version)
    {
        if (! preg_match('/^[1-9]\d*\.\d+$/', $version)) {
            throw new Exception\InvalidArgumentException('Invalid MIME-Version value detected');
        }
        $this->version = $version;
        return $this;
    }

    /**
     * Retrieve the version string for this header
     *
     * @return string
     */
    public function getVersion()
    {
        return $this->version;
    }
}
laminas-mail/src/Header/HeaderLocator.php000064400000005264147361032560014332 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-mail for the canonical source repository
 * @copyright https://github.com/laminas/laminas-mail/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-mail/blob/master/LICENSE.md New BSD License
 */

declare(strict_types=1);

namespace Laminas\Mail\Header;

/**
 * Plugin Class Loader implementation for HTTP headers
 */
final class HeaderLocator implements HeaderLocatorInterface
{
    /**
     * @var array Pre-aliased Header plugins
     */
    private $plugins = [
        'bcc'                       => Bcc::class,
        'cc'                        => Cc::class,
        'contentdisposition'        => ContentDisposition::class,
        'content_disposition'       => ContentDisposition::class,
        'content-disposition'       => ContentDisposition::class,
        'contenttype'               => ContentType::class,
        'content_type'              => ContentType::class,
        'content-type'              => ContentType::class,
        'contenttransferencoding'   => ContentTransferEncoding::class,
        'content_transfer_encoding' => ContentTransferEncoding::class,
        'content-transfer-encoding' => ContentTransferEncoding::class,
        'date'                      => Date::class,
        'from'                      => From::class,
        'in-reply-to'               => InReplyTo::class,
        'message-id'                => MessageId::class,
        'mimeversion'               => MimeVersion::class,
        'mime_version'              => MimeVersion::class,
        'mime-version'              => MimeVersion::class,
        'received'                  => Received::class,
        'references'                => References::class,
        'replyto'                   => ReplyTo::class,
        'reply_to'                  => ReplyTo::class,
        'reply-to'                  => ReplyTo::class,
        'sender'                    => Sender::class,
        'subject'                   => Subject::class,
        'to'                        => To::class,
    ];

    public function get(string $name, ?string $default = null): ?string
    {
        $name = $this->normalizeName($name);
        return $this->plugins[$name] ?? $default;
    }

    public function has(string $name): bool
    {
        return isset($this->plugins[$this->normalizeName($name)]);
    }

    public function add(string $name, string $class): void
    {
        $this->plugins[$this->normalizeName($name)] = $class;
    }

    public function remove(string $name): void
    {
        unset($this->plugins[$this->normalizeName($name)]);
    }

    private function normalizeName(string $name): string
    {
        return strtolower($name);
    }
}
laminas-mail/src/Header/Exception/ExceptionInterface.php000064400000000670147361032560017327 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-mail for the canonical source repository
 * @copyright https://github.com/laminas/laminas-mail/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-mail/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Mail\Header\Exception;

use Laminas\Mail\Exception\ExceptionInterface as MailException;

interface ExceptionInterface extends MailException
{
}
laminas-mail/src/Header/Exception/InvalidArgumentException.php000064400000000711147361032560020514 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-mail for the canonical source repository
 * @copyright https://github.com/laminas/laminas-mail/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-mail/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Mail\Header\Exception;

use Laminas\Mail\Exception;

class InvalidArgumentException extends Exception\InvalidArgumentException implements ExceptionInterface
{
}
laminas-mail/src/Header/Exception/BadMethodCallException.php000064400000000705147361032560020051 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-mail for the canonical source repository
 * @copyright https://github.com/laminas/laminas-mail/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-mail/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Mail\Header\Exception;

use Laminas\Mail\Exception;

class BadMethodCallException extends Exception\BadMethodCallException implements ExceptionInterface
{
}
laminas-mail/src/Header/Exception/RuntimeException.php000064400000000671147361032560017053 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-mail for the canonical source repository
 * @copyright https://github.com/laminas/laminas-mail/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-mail/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Mail\Header\Exception;

use Laminas\Mail\Exception;

class RuntimeException extends Exception\RuntimeException implements ExceptionInterface
{
}
laminas-mail/src/Header/StructuredInterface.php000064400000001006147361032560015571 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-mail for the canonical source repository
 * @copyright https://github.com/laminas/laminas-mail/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-mail/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Mail\Header;

interface StructuredInterface extends HeaderInterface
{
    /**
     * Return the delimiter at which a header line should be wrapped
     *
     * @return string
     */
    public function getDelimiter();
}
laminas-mail/src/Header/HeaderLoader.php000064400000004036147361032560014131 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-mail for the canonical source repository
 * @copyright https://github.com/laminas/laminas-mail/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-mail/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Mail\Header;

use Laminas\Loader\PluginClassLoader;

/**
 * Plugin Class Loader implementation for HTTP headers
 */
class HeaderLoader extends PluginClassLoader
{
    /**
     * @var array Pre-aliased Header plugins
     */
    protected $plugins = [
        'bcc'                       => Bcc::class,
        'cc'                        => Cc::class,
        'contentdisposition'        => ContentDisposition::class,
        'content_disposition'       => ContentDisposition::class,
        'content-disposition'       => ContentDisposition::class,
        'contenttype'               => ContentType::class,
        'content_type'              => ContentType::class,
        'content-type'              => ContentType::class,
        'contenttransferencoding'   => ContentTransferEncoding::class,
        'content_transfer_encoding' => ContentTransferEncoding::class,
        'content-transfer-encoding' => ContentTransferEncoding::class,
        'date'                      => Date::class,
        'from'                      => From::class,
        'in-reply-to'               => InReplyTo::class,
        'message-id'                => MessageId::class,
        'mimeversion'               => MimeVersion::class,
        'mime_version'              => MimeVersion::class,
        'mime-version'              => MimeVersion::class,
        'received'                  => Received::class,
        'references'                => References::class,
        'replyto'                   => ReplyTo::class,
        'reply_to'                  => ReplyTo::class,
        'reply-to'                  => ReplyTo::class,
        'sender'                    => Sender::class,
        'subject'                   => Subject::class,
        'to'                        => To::class,
    ];
}
laminas-mail/src/Header/ReplyTo.php000064400000000664147361032560013213 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-mail for the canonical source repository
 * @copyright https://github.com/laminas/laminas-mail/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-mail/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Mail\Header;

class ReplyTo extends AbstractAddressList
{
    protected $fieldName = 'Reply-To';
    protected static $type = 'reply-to';
}
laminas-mail/src/Header/MultipleHeadersInterface.php000064400000000662147361032560016523 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-mail for the canonical source repository
 * @copyright https://github.com/laminas/laminas-mail/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-mail/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Mail\Header;

interface MultipleHeadersInterface extends HeaderInterface
{
    public function toStringMultipleHeaders(array $headers);
}
laminas-mail/src/Header/UnstructuredInterface.php000064400000000650147361032560016140 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-mail for the canonical source repository
 * @copyright https://github.com/laminas/laminas-mail/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-mail/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Mail\Header;

/**
 * Marker interface for unstructured headers.
 */
interface UnstructuredInterface extends HeaderInterface
{
}
laminas-mail/src/Header/ContentDisposition.php000064400000022234147361032560015451 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-mail for the canonical source repository
 * @copyright https://github.com/laminas/laminas-mail/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-mail/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Mail\Header;

use Laminas\Mail\Headers;
use Laminas\Mime\Mime;

class ContentDisposition implements UnstructuredInterface
{
    /**
     * 78 chars (RFC 2822) - (semicolon + space (Header::FOLDING))
     *
     * @var int
     */
    public const MAX_PARAMETER_LENGTH = 76;

    /**
     * @var string
     */
    protected $disposition = 'inline';

    /**
     * Header encoding
     *
     * @var string
     */
    protected $encoding = 'ASCII';

    /**
     * @var array
     */
    protected $parameters = [];

    /**
     * @inheritDoc
     */
    public static function fromString($headerLine)
    {
        list($name, $value) = GenericHeader::splitHeaderLine($headerLine);
        $value = HeaderWrap::mimeDecodeValue($value);

        // check to ensure proper header type for this factory
        if (strtolower($name) !== 'content-disposition') {
            throw new Exception\InvalidArgumentException('Invalid header line for Content-Disposition string');
        }

        $value  = str_replace(Headers::FOLDING, ' ', $value);
        $parts = explode(';', $value, 2);

        $header = new static();
        $header->setDisposition($parts[0]);

        if (isset($parts[1])) {
            $values = ListParser::parse(trim($parts[1]), [';', '=']);
            $length = count($values);
            $continuedValues = [];

            for ($i = 0; $i < $length; $i += 2) {
                $value = $values[$i + 1];
                $value = trim($value, "'\" \t\n\r\0\x0B");
                $name = trim($values[$i], "'\" \t\n\r\0\x0B");

                if (strpos($name, '*')) {
                    list($name, $count) = explode('*', $name);
                    // allow optional count:
                    // Content-Disposition: attachment; filename*=UTF-8''%64%61%61%6D%69%2D%6D%C3%B5%72%76%2E%6A%70%67
                    if ($count === "") {
                        $count = 0;
                    }

                    if (! is_numeric($count)) {
                        $type = gettype($count);
                        $value = var_export($count, 1);
                        throw new Exception\InvalidArgumentException(sprintf(
                            "Invalid header line for Content-Disposition string".
                            " - count expected to be numeric, got %s with value %s",
                            $type,
                            $value
                        ));
                    }
                    if (! isset($continuedValues[$name])) {
                        $continuedValues[$name] = [];
                    }
                    $continuedValues[$name][$count] = $value;
                } else {
                    $header->setParameter($name, $value);
                }
            }

            foreach ($continuedValues as $name => $values) {
                $value = '';
                for ($i = 0, $iMax = count($values); $i < $iMax; $i++) {
                    if (! isset($values[$i])) {
                        throw new Exception\InvalidArgumentException(
                            'Invalid header line for Content-Disposition string - incomplete continuation'.
                            '; HeaderLine: '.$headerLine
                        );
                    }
                    $value .= $values[$i];
                }
                $header->setParameter($name, $value);
            }
        }

        return $header;
    }

    /**
     * @inheritDoc
     */
    public function getFieldName()
    {
        return 'Content-Disposition';
    }

    /**
     * @inheritDoc
     */
    public function getFieldValue($format = HeaderInterface::FORMAT_RAW)
    {
        $result = $this->disposition;
        if (empty($this->parameters)) {
            return $result;
        }

        foreach ($this->parameters as $attribute => $value) {
            $valueIsEncoded = false;
            if (HeaderInterface::FORMAT_ENCODED === $format && ! Mime::isPrintable($value)) {
                $value = $this->getEncodedValue($value);
                $valueIsEncoded = true;
            }

            $line = sprintf('%s="%s"', $attribute, $value);

            if (strlen($line) < self::MAX_PARAMETER_LENGTH) {
                $lines = explode(Headers::FOLDING, $result);

                if (count($lines) === 1) {
                    $existingLineLength = strlen('Content-Disposition: ' . $result);
                } else {
                    $existingLineLength = 1 + strlen($lines[count($lines) - 1]);
                }

                if ((2 + $existingLineLength + strlen($line)) <= self::MAX_PARAMETER_LENGTH) {
                    $result .= '; ' . $line;
                } else {
                    $result .= ';' . Headers::FOLDING . $line;
                }
            } else {
                // Use 'continuation' per RFC 2231
                if ($valueIsEncoded) {
                    $value = HeaderWrap::mimeDecodeValue($value);
                }

                $i = 0;
                $fullLength = mb_strlen($value, 'UTF-8');
                while ($fullLength > 0) {
                    $attributePart = $attribute . '*' . $i++ . '="';
                    $attLen = mb_strlen($attributePart, 'UTF-8');

                    $subPos = 1;
                    $valuePart = '';
                    while ($subPos <= $fullLength) {
                        $sub = mb_substr($value, 0, $subPos, 'UTF-8');
                        if ($valueIsEncoded) {
                            $sub = $this->getEncodedValue($sub);
                        }
                        if ($attLen + mb_strlen($sub, 'UTF-8') >= self::MAX_PARAMETER_LENGTH) {
                            $subPos--;
                            break;
                        }
                        $subPos++;
                        $valuePart = $sub;
                    }

                    $value = mb_substr($value, $subPos, null, 'UTF-8');
                    $fullLength = mb_strlen($value, 'UTF-8');
                    $result .= ';' . Headers::FOLDING . $attributePart . $valuePart . '"';
                }
            }
        }

        return $result;
    }

    /**
     * @param string $value
     * @return string
     */
    protected function getEncodedValue($value)
    {
        $configuredEncoding = $this->encoding;
        $this->encoding = 'UTF-8';
        $value = HeaderWrap::wrap($value, $this);
        $this->encoding = $configuredEncoding;
        return $value;
    }

    /**
     * @inheritDoc
     */
    public function setEncoding($encoding)
    {
        $this->encoding = $encoding;
        return $this;
    }

    /**
     * @inheritDoc
     */
    public function getEncoding()
    {
        return $this->encoding;
    }

    /**
     * @inheritDoc
     */
    public function toString()
    {
        return 'Content-Disposition: ' . $this->getFieldValue(HeaderInterface::FORMAT_ENCODED);
    }

    /**
     * Set the content disposition
     * Expected values include 'inline', 'attachment'
     *
     * @param string $disposition
     * @return ContentDisposition
     */
    public function setDisposition($disposition)
    {
        $this->disposition = strtolower($disposition);
        return $this;
    }

    /**
     * Retrieve the content disposition
     *
     * @return string
     */
    public function getDisposition()
    {
        return $this->disposition;
    }

    /**
     * Add a parameter pair
     *
     * @param string $name
     * @param string $value
     * @return ContentDisposition
     */
    public function setParameter($name, $value)
    {
        $name  = strtolower($name);

        if (! HeaderValue::isValid($name)) {
            throw new Exception\InvalidArgumentException(
                'Invalid content-disposition parameter name detected'
            );
        }
        // '5' here is for the quotes & equal sign in `name="value"`,
        // and the space & semicolon for line folding
        if ((strlen($name) + 5) >= self::MAX_PARAMETER_LENGTH) {
            throw new Exception\InvalidArgumentException(
                'Invalid content-disposition parameter name detected (too long)'
            );
        }

        $this->parameters[$name] = $value;
        return $this;
    }

    /**
     * Get all parameters
     *
     * @return array
     */
    public function getParameters()
    {
        return $this->parameters;
    }

    /**
     * Get a parameter by name
     *
     * @param string $name
     * @return null|string
     */
    public function getParameter($name)
    {
        $name = strtolower($name);
        if (isset($this->parameters[$name])) {
            return $this->parameters[$name];
        }
        return null;
    }

    /**
     * Remove a named parameter
     *
     * @param string $name
     * @return bool
     */
    public function removeParameter($name)
    {
        $name = strtolower($name);
        if (isset($this->parameters[$name])) {
            unset($this->parameters[$name]);
            return true;
        }
        return false;
    }
}
laminas-mail/src/Header/MessageId.php000064400000005164147361032560013456 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-mail for the canonical source repository
 * @copyright https://github.com/laminas/laminas-mail/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-mail/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Mail\Header;

class MessageId implements HeaderInterface
{
    /**
     * @var string
     */
    protected $messageId;

    public static function fromString($headerLine)
    {
        list($name, $value) = GenericHeader::splitHeaderLine($headerLine);
        $value = HeaderWrap::mimeDecodeValue($value);

        // check to ensure proper header type for this factory
        if (strtolower($name) !== 'message-id') {
            throw new Exception\InvalidArgumentException('Invalid header line for Message-ID string');
        }

        $header = new static();
        $header->setId($value);

        return $header;
    }

    public function getFieldName()
    {
        return 'Message-ID';
    }

    public function getFieldValue($format = HeaderInterface::FORMAT_RAW)
    {
        return $this->messageId;
    }

    public function setEncoding($encoding)
    {
        // This header must be always in US-ASCII
        return $this;
    }

    public function getEncoding()
    {
        return 'ASCII';
    }

    public function toString()
    {
        return 'Message-ID: ' . $this->getFieldValue();
    }

    /**
     * Set the message id
     *
     * @param string|null $id
     * @return MessageId
     */
    public function setId($id = null)
    {
        if ($id === null) {
            $id = $this->createMessageId();
        } else {
            $id = trim($id, '<>');
        }

        if (! HeaderValue::isValid($id)
            || preg_match("/[\r\n]/", $id)
        ) {
            throw new Exception\InvalidArgumentException('Invalid ID detected');
        }

        $this->messageId = sprintf('<%s>', $id);
        return $this;
    }

    /**
     * Retrieve the message id
     *
     * @return string
     */
    public function getId()
    {
        return $this->messageId;
    }

    /**
     * Creates the Message-ID
     *
     * @return string
     */
    public function createMessageId()
    {
        $time = time();

        if (isset($_SERVER['REMOTE_ADDR'])) {
            $user = $_SERVER['REMOTE_ADDR'];
        } else {
            $user = getmypid();
        }

        $rand = mt_rand();

        if (isset($_SERVER["SERVER_NAME"])) {
            $hostName = $_SERVER["SERVER_NAME"];
        } else {
            $hostName = php_uname('n');
        }

        return sha1($time . $user . $rand) . '@' . $hostName;
    }
}
laminas-mail/src/Header/HeaderInterface.php000064400000003311147361032560014616 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-mail for the canonical source repository
 * @copyright https://github.com/laminas/laminas-mail/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-mail/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Mail\Header;

interface HeaderInterface
{
    /**
     * Format value in Mime-Encoding (Quoted-Printable). Result is valid US-ASCII string
     *
     * @var bool
     */
    public const FORMAT_ENCODED = true;

    /**
     * Return value in internal encoding which is usually UTF-8
     *
     * @var bool
     */
    public const FORMAT_RAW     = false;

    /**
     * Factory to generate a header object from a string
     *
     * @param string $headerLine
     * @return static
     * @throws Exception\InvalidArgumentException If the header does not match with RFC 2822 definition.
     * @see http://tools.ietf.org/html/rfc2822#section-2.2
     */
    public static function fromString($headerLine);

    /**
     * Retrieve header name
     *
     * @return string
     */
    public function getFieldName();

    /**
     * Retrieve header value
     *
     * @param  bool $format Return the value in Mime::Encoded or in Raw format
     * @return string
     */
    public function getFieldValue($format = self::FORMAT_RAW);

    /**
     * Set header encoding
     *
     * @param  string $encoding
     * @return $this
     */
    public function setEncoding($encoding);

    /**
     * Get header encoding
     *
     * @return string
     */
    public function getEncoding();

    /**
     * Cast to string
     *
     * Returns in form of "NAME: VALUE"
     *
     * @return string
     */
    public function toString();
}
laminas-mail/src/Header/Received.php000064400000004573147361032560013346 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-mail for the canonical source repository
 * @copyright https://github.com/laminas/laminas-mail/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-mail/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Mail\Header;

use Laminas\Mail\Headers;

/**
 * @todo       Allow setting date from DateTime, Laminas\Date, or string
 */
class Received implements HeaderInterface, MultipleHeadersInterface
{
    /**
     * @var string
     */
    protected $value;

    public static function fromString($headerLine)
    {
        list($name, $value) = GenericHeader::splitHeaderLine($headerLine);
        $value = HeaderWrap::mimeDecodeValue($value);

        // check to ensure proper header type for this factory
        if (strtolower($name) !== 'received') {
            throw new Exception\InvalidArgumentException('Invalid header line for Received string');
        }

        $header = new static($value);

        return $header;
    }

    public function __construct($value = '')
    {
        if (! HeaderValue::isValid($value)) {
            throw new Exception\InvalidArgumentException('Invalid Received value provided');
        }
        $this->value = $value;
    }

    public function getFieldName()
    {
        return 'Received';
    }

    public function getFieldValue($format = HeaderInterface::FORMAT_RAW)
    {
        return $this->value;
    }

    public function setEncoding($encoding)
    {
        // This header must be always in US-ASCII
        return $this;
    }

    public function getEncoding()
    {
        return 'ASCII';
    }

    public function toString()
    {
        return 'Received: ' . $this->getFieldValue();
    }

    /**
     * Serialize collection of Received headers to string
     *
     * @param  array $headers
     * @throws Exception\RuntimeException
     * @return string
     */
    public function toStringMultipleHeaders(array $headers)
    {
        $strings = [$this->toString()];
        foreach ($headers as $header) {
            if (! $header instanceof self) {
                throw new Exception\RuntimeException(
                    'The Received multiple header implementation can only accept an array of Received headers'
                );
            }
            $strings[] = $header->toString();
        }
        return implode(Headers::EOL, $strings);
    }
}
laminas-mail/src/Storage.php000064400000001454147361032560012027 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-mail for the canonical source repository
 * @copyright https://github.com/laminas/laminas-mail/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-mail/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Mail;

class Storage
{
    // maildir and IMAP flags, using IMAP names, where possible to be able to distinguish between IMAP
    // system flags and other flags
    public const FLAG_PASSED   = 'Passed';
    public const FLAG_SEEN     = '\Seen';
    public const FLAG_UNSEEN   = '\Unseen';
    public const FLAG_ANSWERED = '\Answered';
    public const FLAG_FLAGGED  = '\Flagged';
    public const FLAG_DELETED  = '\Deleted';
    public const FLAG_DRAFT    = '\Draft';
    public const FLAG_RECENT   = '\Recent';
}
laminas-mail/src/AddressList.php000064400000013306147361032560012643 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-mail for the canonical source repository
 * @copyright https://github.com/laminas/laminas-mail/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-mail/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Mail;

use Countable;
use Iterator;

class AddressList implements Countable, Iterator
{
    /**
     * List of Address objects we're managing
     *
     * @var array
     */
    protected $addresses = [];

    /**
     * Add an address to the list
     *
     * @param  string|Address\AddressInterface $emailOrAddress
     * @param  null|string $name
     * @throws Exception\InvalidArgumentException
     * @return AddressList
     */
    public function add($emailOrAddress, $name = null)
    {
        if (is_string($emailOrAddress)) {
            $emailOrAddress = $this->createAddress($emailOrAddress, $name);
        }

        if (! $emailOrAddress instanceof Address\AddressInterface) {
            throw new Exception\InvalidArgumentException(sprintf(
                '%s expects an email address or %s\Address object as its first argument; received "%s"',
                __METHOD__,
                __NAMESPACE__,
                (is_object($emailOrAddress) ? get_class($emailOrAddress) : gettype($emailOrAddress))
            ));
        }

        $email = strtolower($emailOrAddress->getEmail());
        if ($this->has($email)) {
            return $this;
        }

        $this->addresses[$email] = $emailOrAddress;
        return $this;
    }

    /**
     * Add many addresses at once
     *
     * If an email key is provided, it will be used as the email, and the value
     * as the name. Otherwise, the value is passed as the sole argument to add(),
     * and, as such, can be either email strings or Address\AddressInterface objects.
     *
     * @param  array $addresses
     * @throws Exception\RuntimeException
     * @return AddressList
     */
    public function addMany(array $addresses)
    {
        foreach ($addresses as $key => $value) {
            if (is_int($key) || is_numeric($key)) {
                $this->add($value);
                continue;
            }

            if (! is_string($key)) {
                throw new Exception\RuntimeException(sprintf(
                    'Invalid key type in provided addresses array ("%s")',
                    (is_object($key) ? get_class($key) : var_export($key, 1))
                ));
            }

            $this->add($key, $value);
        }
        return $this;
    }

    /**
     * Add an address to the list from any valid string format, such as
     *  - "Laminas Dev" <dev@laminas.com>
     *  - dev@laminas.com
     *
     * @param string $address
     * @param null|string $comment Comment associated with the address, if any.
     * @throws Exception\InvalidArgumentException
     * @return AddressList
     */
    public function addFromString($address, $comment = null)
    {
        $this->add(Address::fromString($address, $comment));
        return $this;
    }

    /**
     * Merge another address list into this one
     *
     * @param  AddressList $addressList
     * @return AddressList
     */
    public function merge(self $addressList)
    {
        foreach ($addressList as $address) {
            $this->add($address);
        }
        return $this;
    }

    /**
     * Does the email exist in this list?
     *
     * @param  string $email
     * @return bool
     */
    public function has($email)
    {
        $email = strtolower($email);
        return isset($this->addresses[$email]);
    }

    /**
     * Get an address by email
     *
     * @param  string $email
     * @return bool|Address\AddressInterface
     */
    public function get($email)
    {
        $email = strtolower($email);
        if (! isset($this->addresses[$email])) {
            return false;
        }

        return $this->addresses[$email];
    }

    /**
     * Delete an address from the list
     *
     * @param  string $email
     * @return bool
     */
    public function delete($email)
    {
        $email = strtolower($email);
        if (! isset($this->addresses[$email])) {
            return false;
        }

        unset($this->addresses[$email]);
        return true;
    }

    /**
     * Return count of addresses
     *
     * @return int
     */
    public function count()
    {
        return count($this->addresses);
    }

    /**
     * Rewind iterator
     *
     * @return mixed the value of the first addresses element, or false if the addresses is
     * empty.
     * @see addresses
     */
    public function rewind()
    {
        return reset($this->addresses);
    }

    /**
     * Return current item in iteration
     *
     * @return Address
     */
    public function current()
    {
        return current($this->addresses);
    }

    /**
     * Return key of current item of iteration
     *
     * @return string
     */
    public function key()
    {
        return key($this->addresses);
    }

    /**
     * Move to next item
     *
     * @return mixed the addresses value in the next place that's pointed to by the
     * internal array pointer, or false if there are no more elements.
     * @see addresses
     */
    public function next()
    {
        return next($this->addresses);
    }

    /**
     * Is the current item of iteration valid?
     *
     * @return bool
     */
    public function valid()
    {
        $key = key($this->addresses);
        return ($key !== null && $key !== false);
    }

    /**
     * Create an address object
     *
     * @param  string $email
     * @param  string|null $name
     * @return Address
     */
    protected function createAddress($email, $name)
    {
        return new Address($email, $name);
    }
}
laminas-mail/src/Storage/Imap.php000064400000042215147361032560012715 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-mail for the canonical source repository
 * @copyright https://github.com/laminas/laminas-mail/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-mail/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Mail\Storage;

use Laminas\Config\Config;
use Laminas\Mail;
use Laminas\Mail\Protocol;

class Imap extends AbstractStorage implements Folder\FolderInterface, Writable\WritableInterface
{
    // TODO: with an internal cache we could optimize this class, or create an extra class with
    // such optimizations. Especially the various fetch calls could be combined to one cache call

    /**
     * protocol handler
     * @var null|Protocol\Imap
     */
    protected $protocol;

    /**
     * name of current folder
     * @var string
     */
    protected $currentFolder = '';

    /**
     * IMAP folder delimiter character
     * @var null|string
     */
    protected $delimiter;

    /**
     * IMAP flags to constants translation
     * @var array
     */
    protected static $knownFlags = [
        '\Passed'   => Mail\Storage::FLAG_PASSED,
        '\Answered' => Mail\Storage::FLAG_ANSWERED,
        '\Seen'     => Mail\Storage::FLAG_SEEN,
        '\Unseen'   => Mail\Storage::FLAG_UNSEEN,
        '\Deleted'  => Mail\Storage::FLAG_DELETED,
        '\Draft'    => Mail\Storage::FLAG_DRAFT,
        '\Flagged'  => Mail\Storage::FLAG_FLAGGED,
    ];

    /**
     * IMAP flags to search criteria
     * @var array
     */
    protected static $searchFlags = [
        '\Recent'   => 'RECENT',
        '\Answered' => 'ANSWERED',
        '\Seen'     => 'SEEN',
        '\Unseen'   => 'UNSEEN',
        '\Deleted'  => 'DELETED',
        '\Draft'    => 'DRAFT',
        '\Flagged'  => 'FLAGGED',
    ];

    /**
     * Count messages all messages in current box
     *
     * @param null $flags
     * @throws Exception\RuntimeException
     * @throws Protocol\Exception\RuntimeException
     * @return int number of messages
     */
    public function countMessages($flags = null)
    {
        if (! $this->currentFolder) {
            throw new Exception\RuntimeException('No selected folder to count');
        }

        if ($flags === null) {
            return count($this->protocol->search(['ALL']));
        }

        $params = [];
        foreach ((array) $flags as $flag) {
            if (isset(static::$searchFlags[$flag])) {
                $params[] = static::$searchFlags[$flag];
            } else {
                $params[] = 'KEYWORD';
                $params[] = $this->protocol->escapeString($flag);
            }
        }
        return count($this->protocol->search($params));
    }

    /**
     * get a list of messages with number and size
     *
     * @param int $id number of message
     * @return int|array size of given message of list with all messages as [num => size]
     * @throws Protocol\Exception\RuntimeException
     */
    public function getSize($id = 0)
    {
        if ($id) {
            return $this->protocol->fetch('RFC822.SIZE', $id);
        }
        return $this->protocol->fetch('RFC822.SIZE', 1, INF);
    }

    /**
     * Fetch a message
     *
     * @param int $id number of message
     * @return Message
     * @throws Protocol\Exception\RuntimeException
     */
    public function getMessage($id)
    {
        $data = $this->protocol->fetch(['FLAGS', 'RFC822.HEADER'], $id);
        $header = $data['RFC822.HEADER'];

        $flags = [];
        foreach ($data['FLAGS'] as $flag) {
            $flags[] = static::$knownFlags[$flag] ?? $flag;
        }

        return new $this->messageClass(['handler' => $this, 'id' => $id, 'headers' => $header, 'flags' => $flags]);
    }

    /*
     * Get raw header of message or part
     *
     * @param  int               $id       number of message
     * @param  null|array|string $part     path to part or null for message header
     * @param  int               $topLines include this many lines with header (after an empty line)
     * @param  int $topLines include this many lines with header (after an empty line)
     * @return string raw header
     * @throws Exception\RuntimeException
     * @throws Protocol\Exception\RuntimeException
     */
    public function getRawHeader($id, $part = null, $topLines = 0)
    {
        if ($part !== null) {
            // TODO: implement
            throw new Exception\RuntimeException('not implemented');
        }

        // TODO: toplines
        return $this->protocol->fetch('RFC822.HEADER', $id);
    }

    /*
     * Get raw content of message or part
     *
     * @param  int               $id   number of message
     * @param  null|array|string $part path to part or null for message content
     * @return string raw content
     * @throws Protocol\Exception\RuntimeException
     * @throws Exception\RuntimeException
     */
    public function getRawContent($id, $part = null)
    {
        if ($part !== null) {
            // TODO: implement
            throw new Exception\RuntimeException('not implemented');
        }

        return $this->protocol->fetch('RFC822.TEXT', $id);
    }

    // @codingStandardsIgnoreStart
    /**
     * create instance with parameters
     *
     * Supported parameters are
     *
     * - user username
     * - host hostname or ip address of IMAP server [optional, default = 'localhost']
     * - password password for user 'username' [optional, default = '']
     * - port port for IMAP server [optional, default = 110]
     * - ssl 'SSL' or 'TLS' for secure sockets
     * - folder select this folder [optional, default = 'INBOX']
     *
     * @param  array|object|Config|Protocol\Imap $params mail reader specific parameters or configured Imap protocol object
     * @throws Exception\RuntimeException
     * @throws Exception\InvalidArgumentException
     * @throws Protocol\Exception\RuntimeException
     */
    // @codingStandardsIgnoreEnd
    public function __construct($params)
    {
        if (is_array($params)) {
            $params = (object) $params;
        }

        $this->has['flags'] = true;

        if ($params instanceof Protocol\Imap) {
            $this->protocol = $params;
            try {
                $this->selectFolder('INBOX');
            } catch (Exception\ExceptionInterface $e) {
                throw new Exception\RuntimeException('cannot select INBOX, is this a valid transport?', 0, $e);
            }
            return;
        }

        if (! isset($params->user)) {
            throw new Exception\InvalidArgumentException('need at least user in params');
        }

        $host     = isset($params->host) ? $params->host : 'localhost';
        $password = isset($params->password) ? $params->password : '';
        $port     = isset($params->port) ? $params->port : null;
        $ssl      = isset($params->ssl) ? $params->ssl : false;

        $this->protocol = new Protocol\Imap();

        if (isset($params->novalidatecert)) {
            $this->protocol->setNoValidateCert((bool)$params->novalidatecert);
        }

        $this->protocol->connect($host, $port, $ssl);
        if (! $this->protocol->login($params->user, $password)) {
            throw new Exception\RuntimeException('cannot login, user or password wrong');
        }
        $this->selectFolder(isset($params->folder) ? $params->folder : 'INBOX');
    }

    /**
     * Close resource for mail lib.
     *
     * If you need to control, when the resource is closed. Otherwise the
     * destructor would call this.
     */
    public function close()
    {
        $this->currentFolder = '';
        $this->protocol->logout();
    }

    /**
     * Keep the server busy.
     *
     * @throws Exception\RuntimeException
     */
    public function noop()
    {
        if (! $this->protocol->noop()) {
            throw new Exception\RuntimeException('could not do nothing');
        }
    }

    /**
     * Remove a message from server.
     *
     * If you're doing that from a web environment you should be careful and
     * use a uniqueid as parameter if possible to identify the message.
     *
     * @param  int $id number of message
     * @throws Exception\RuntimeException
     */
    public function removeMessage($id)
    {
        if (! $this->protocol->store([Mail\Storage::FLAG_DELETED], $id, null, '+')) {
            throw new Exception\RuntimeException('cannot set deleted flag');
        }
        // TODO: expunge here or at close? we can handle an error here better and are more fail safe
        if (! $this->protocol->expunge()) {
            throw new Exception\RuntimeException('message marked as deleted, but could not expunge');
        }
    }

    /**
     * get unique id for one or all messages
     *
     * if storage does not support unique ids it's the same as the message
     * number.
     *
     * @param int|null $id message number
     * @return array|string message number for given message or all messages as array
     * @throws Protocol\Exception\RuntimeException
     */
    public function getUniqueId($id = null)
    {
        if ($id) {
            return $this->protocol->fetch('UID', $id);
        }

        return $this->protocol->fetch('UID', 1, INF);
    }

    /**
     * get a message number from a unique id
     *
     * I.e. if you have a webmailer that supports deleting messages you should
     * use unique ids as parameter and use this method to translate it to
     * message number right before calling removeMessage()
     *
     * @param string $id unique id
     * @throws Exception\InvalidArgumentException
     * @return int message number
     */
    public function getNumberByUniqueId($id)
    {
        // TODO: use search to find number directly
        $ids = $this->getUniqueId();
        foreach ($ids as $k => $v) {
            if ($v == $id) {
                return $k;
            }
        }

        throw new Exception\InvalidArgumentException('unique id not found');
    }

    /**
     * get root folder or given folder
     *
     * @param  string $rootFolder get folder structure for given folder, else root
     * @throws Exception\RuntimeException
     * @throws Exception\InvalidArgumentException
     * @throws Protocol\Exception\RuntimeException
     * @return Folder root or wanted folder
     */
    public function getFolders($rootFolder = null)
    {
        $folders = $this->protocol->listMailbox((string) $rootFolder);
        if (! $folders) {
            throw new Exception\InvalidArgumentException('folder not found');
        }

        ksort($folders, SORT_STRING);
        $root = new Folder('/', '/', false);
        $stack = [null];
        $folderStack = [null];
        $parentFolder = $root;
        $parent = '';

        foreach ($folders as $globalName => $data) {
            do {
                if (! $parent || strpos($globalName, $parent) === 0) {
                    $pos = strrpos($globalName, $data['delim']);
                    if ($pos === false) {
                        $localName = $globalName;
                    } else {
                        $localName = substr($globalName, $pos + 1);
                    }
                    $selectable = ! $data['flags'] || ! in_array('\\Noselect', $data['flags']);

                    array_push($stack, $parent);
                    $parent = $globalName . $data['delim'];
                    $folder = new Folder($localName, $globalName, $selectable);
                    $parentFolder->$localName = $folder;
                    array_push($folderStack, $parentFolder);
                    $parentFolder = $folder;
                    $this->delimiter = $data['delim'];
                    break;
                } elseif ($stack) {
                    $parent = array_pop($stack);
                    $parentFolder = array_pop($folderStack);
                }
            } while ($stack);
            if (! $stack) {
                throw new Exception\RuntimeException('error while constructing folder tree');
            }
        }

        return $root;
    }

    /**
     * select given folder
     *
     * folder must be selectable!
     *
     * @param  Folder|string $globalName global name of folder or instance for subfolder
     * @throws Exception\RuntimeException
     * @throws Protocol\Exception\RuntimeException
     */
    public function selectFolder($globalName)
    {
        $this->currentFolder = $globalName;
        if (! $this->protocol->select($this->currentFolder)) {
            $this->currentFolder = '';
            throw new Exception\RuntimeException('cannot change folder, maybe it does not exist');
        }
    }

    /**
     * get Folder instance for current folder
     *
     * @return Folder instance of current folder
     */
    public function getCurrentFolder()
    {
        return $this->currentFolder;
    }

    /**
     * create a new folder
     *
     * This method also creates parent folders if necessary. Some mail storages
     * may restrict, which folder may be used as parent or which chars may be
     * used in the folder name
     *
     * @param string $name global name of folder, local name if $parentFolder
     *     is set
     * @param string|Folder $parentFolder parent folder for new folder, else
     *     root folder is parent
     * @throws Exception\RuntimeException
     */
    public function createFolder($name, $parentFolder = null)
    {
        // TODO: we assume / as the hierarchy delim - need to get that from the folder class!
        if ($parentFolder instanceof Folder) {
            $folder = $parentFolder->getGlobalName() . '/' . $name;
        } elseif ($parentFolder !== null) {
            $folder = $parentFolder . '/' . $name;
        } else {
            $folder = $name;
        }

        if (! $this->protocol->create($folder)) {
            throw new Exception\RuntimeException('cannot create folder');
        }
    }

    /**
     * remove a folder
     *
     * @param  string|Folder $name name or instance of folder
     * @throws Exception\RuntimeException
     */
    public function removeFolder($name)
    {
        if ($name instanceof Folder) {
            $name = $name->getGlobalName();
        }

        if (! $this->protocol->delete($name)) {
            throw new Exception\RuntimeException('cannot delete folder');
        }
    }

    /**
     * rename and/or move folder
     *
     * The new name has the same restrictions as in createFolder()
     *
     * @param  string|Folder $oldName name or instance of folder
     * @param  string $newName new global name of folder
     * @throws Exception\RuntimeException
     */
    public function renameFolder($oldName, $newName)
    {
        if ($oldName instanceof Folder) {
            $oldName = $oldName->getGlobalName();
        }

        if (! $this->protocol->rename($oldName, $newName)) {
            throw new Exception\RuntimeException('cannot rename folder');
        }
    }

    /**
     * append a new message to mail storage
     *
     * @param string $message message as string or instance of message class
     * @param null|string|Folder $folder  folder for new message, else current
     *     folder is taken
     * @param null|array $flags set flags for new message, else a default set
     *     is used
     * @throws Exception\RuntimeException
     */
    public function appendMessage($message, $folder = null, $flags = null)
    {
        if ($folder === null) {
            $folder = $this->currentFolder;
        }

        if ($flags === null) {
            $flags = [Mail\Storage::FLAG_SEEN];
        }

        // TODO: handle class instances for $message
        if (! $this->protocol->append($folder, $message, $flags)) {
            throw new Exception\RuntimeException(
                'cannot create message, please check if the folder exists and your flags'
            );
        }
    }

    /**
     * copy an existing message
     *
     * @param int $id number of message
     * @param string|Folder $folder name or instance of target folder
     * @throws Exception\RuntimeException
     */
    public function copyMessage($id, $folder)
    {
        if (! $this->protocol->copy($folder, $id)) {
            throw new Exception\RuntimeException('cannot copy message, does the folder exist?');
        }
    }

    /**
     * move an existing message
     *
     * NOTE: IMAP has no native move command, thus it's emulated with copy and delete
     *
     * @param int $id number of message
     * @param string|Folder $folder name or instance of target folder
     * @throws Exception\RuntimeException
     */
    public function moveMessage($id, $folder)
    {
        $this->copyMessage($id, $folder);
        $this->removeMessage($id);
    }

    /**
     * set flags for message
     *
     * NOTE: this method can't set the recent flag.
     *
     * @param int $id number of message
     * @param array $flags new flags for message
     * @throws Exception\RuntimeException
     */
    public function setFlags($id, $flags)
    {
        if (! $this->protocol->store($flags, $id)) {
            throw new Exception\RuntimeException(
                'cannot set flags, have you tried to set the recent flag or special chars?'
            );
        }
    }

    /**
     * get IMAP delimiter
     *
     * @return string|null
     */
    public function delimiter()
    {
        if (! isset($this->delimiter)) {
            $this->getFolders();
        }
        return $this->delimiter;
    }
}
laminas-mail/src/Storage/Message/File.php000064400000003441147361032560014270 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-mail for the canonical source repository
 * @copyright https://github.com/laminas/laminas-mail/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-mail/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Mail\Storage\Message;

use Laminas\Mail\Storage\Part;

class File extends Part\File implements MessageInterface
{
    /**
     * flags for this message
     * @var array
     */
    protected $flags = [];

    /**
     * Public constructor
     *
     * In addition to the parameters of Laminas\Mail\Storage\Part::__construct() this constructor supports:
     * - flags array with flags for message, keys are ignored, use constants defined in Laminas\Mail\Storage
     *
     * @param  array $params
     * @throws \Laminas\Mail\Storage\Exception\ExceptionInterface
     */
    public function __construct(array $params)
    {
        if (! empty($params['flags'])) {
            // set key and value to the same value for easy lookup
            $this->flags = array_combine($params['flags'], $params['flags']);
        }

        parent::__construct($params);
    }

    /**
     * return toplines as found after headers
     *
     * @return string toplines
     */
    public function getTopLines()
    {
        return $this->topLines;
    }

    /**
     * check if flag is set
     *
     * @param mixed $flag a flag name, use constants defined in \Laminas\Mail\Storage
     * @return bool true if set, otherwise false
     */
    public function hasFlag($flag)
    {
        return isset($this->flags[$flag]);
    }

    /**
     * get all set flags
     *
     * @return array array with flags, key and value are the same for easy lookup
     */
    public function getFlags()
    {
        return $this->flags;
    }
}
laminas-mail/src/Storage/Message/MessageInterface.php000064400000001546147361032560016622 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-mail for the canonical source repository
 * @copyright https://github.com/laminas/laminas-mail/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-mail/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Mail\Storage\Message;

interface MessageInterface
{
    /**
     * return toplines as found after headers
     *
     * @return string toplines
     */
    public function getTopLines();

    /**
     * check if flag is set
     *
     * @param mixed $flag a flag name, use constants defined in Laminas\Mail\Storage
     * @return bool true if set, otherwise false
     */
    public function hasFlag($flag);

    /**
     * get all set flags
     *
     * @return array array with flags, key and value are the same for easy lookup
     */
    public function getFlags();
}
laminas-mail/src/Storage/Message.php000064400000004571147361032560013416 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-mail for the canonical source repository
 * @copyright https://github.com/laminas/laminas-mail/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-mail/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Mail\Storage;

use Laminas\Stdlib\ErrorHandler;

class Message extends Part implements Message\MessageInterface
{
    /**
     * flags for this message
     * @var array
     */
    protected $flags = [];

    /**
     * Public constructor
     *
     * In addition to the parameters of Part::__construct() this constructor supports:
     * - file  filename or file handle of a file with raw message content
     * - flags array with flags for message, keys are ignored, use constants defined in \Laminas\Mail\Storage
     *
     * @param array $params
     * @throws Exception\RuntimeException
     */
    public function __construct(array $params)
    {
        if (isset($params['file'])) {
            if (! is_resource($params['file'])) {
                ErrorHandler::start();
                $params['raw'] = file_get_contents($params['file']);
                $error = ErrorHandler::stop();
                if ($params['raw'] === false) {
                    throw new Exception\RuntimeException('could not open file', 0, $error);
                }
            } else {
                $params['raw'] = stream_get_contents($params['file']);
            }

            $params['raw'] = ltrim($params['raw']);
        }

        if (! empty($params['flags'])) {
            // set key and value to the same value for easy lookup
            $this->flags = array_combine($params['flags'], $params['flags']);
        }

        parent::__construct($params);
    }

    /**
     * return toplines as found after headers
     *
     * @return string toplines
     */
    public function getTopLines()
    {
        return $this->topLines;
    }

    /**
     * check if flag is set
     *
     * @param mixed $flag a flag name, use constants defined in \Laminas\Mail\Storage
     * @return bool true if set, otherwise false
     */
    public function hasFlag($flag)
    {
        return isset($this->flags[$flag]);
    }

    /**
     * get all set flags
     *
     * @return array array with flags, key and value are the same for easy lookup
     */
    public function getFlags()
    {
        return $this->flags;
    }
}
laminas-mail/src/Storage/Folder/Maildir.php000064400000015433147361032560014625 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-mail for the canonical source repository
 * @copyright https://github.com/laminas/laminas-mail/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-mail/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Mail\Storage\Folder;

use Laminas\Mail\Storage;
use Laminas\Mail\Storage\Exception;
use Laminas\Stdlib\ErrorHandler;

class Maildir extends Storage\Maildir implements FolderInterface
{
    /**
     * root folder for folder structure
     * @var Storage\Folder
     */
    protected $rootFolder;

    /**
     * rootdir of folder structure
     * @var string
     */
    protected $rootdir;

    /**
     * name of current folder
     * @var string
     */
    protected $currentFolder;

    /**
     * delim char for subfolders
     * @var string
     */
    protected $delim;

    /**
     * Create instance with parameters
     *
     * Supported parameters are:
     *
     * - dirname rootdir of maildir structure
     * - delim   delim char for folder structure, default is '.'
     * - folder initial selected folder, default is 'INBOX'
     *
     * @param  $params array mail reader specific parameters
     * @throws Exception\InvalidArgumentException
     */
    public function __construct($params)
    {
        if (is_array($params)) {
            $params = (object) $params;
        }

        if (! isset($params->dirname) || ! is_dir($params->dirname)) {
            throw new Exception\InvalidArgumentException('no valid dirname given in params');
        }

        $this->rootdir = rtrim($params->dirname, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR;

        $this->delim = isset($params->delim) ? $params->delim : '.';

        $this->buildFolderTree();
        $this->selectFolder(! empty($params->folder) ? $params->folder : 'INBOX');
        $this->has['top'] = true;
        $this->has['flags'] = true;
    }

    /**
     * find all subfolders and mbox files for folder structure
     *
     * Result is save in Storage\Folder instances with the root in $this->rootFolder.
     * $parentFolder and $parentGlobalName are only used internally for recursion.
     *
     * @throws Exception\RuntimeException
     */
    protected function buildFolderTree()
    {
        $this->rootFolder = new Storage\Folder('/', '/', false);
        $this->rootFolder->INBOX = new Storage\Folder('INBOX', 'INBOX', true);

        ErrorHandler::start(E_WARNING);
        $dh    = opendir($this->rootdir);
        $error = ErrorHandler::stop();
        if (! $dh) {
            throw new Exception\RuntimeException("can't read folders in maildir", 0, $error);
        }
        $dirs = [];

        while (($entry = readdir($dh)) !== false) {
            // maildir++ defines folders must start with .
            if ($entry[0] != '.' || $entry == '.' || $entry == '..') {
                continue;
            }

            if ($this->isMaildir($this->rootdir . $entry)) {
                $dirs[] = $entry;
            }
        }
        closedir($dh);

        sort($dirs);
        $stack = [null];
        $folderStack = [null];
        $parentFolder = $this->rootFolder;
        $parent = '.';

        foreach ($dirs as $dir) {
            do {
                if (strpos($dir, $parent) === 0) {
                    $local = substr($dir, strlen($parent));
                    if (strpos($local, $this->delim) !== false) {
                        throw new Exception\RuntimeException('error while reading maildir');
                    }
                    array_push($stack, $parent);
                    $parent = $dir . $this->delim;
                    $folder = new Storage\Folder($local, substr($dir, 1), true);
                    $parentFolder->$local = $folder;
                    array_push($folderStack, $parentFolder);
                    $parentFolder = $folder;
                    break;
                } elseif ($stack) {
                    $parent = array_pop($stack);
                    $parentFolder = array_pop($folderStack);
                }
            } while ($stack);
            if (! $stack) {
                throw new Exception\RuntimeException('error while reading maildir');
            }
        }
    }

    /**
     * get root folder or given folder
     *
     * @param string $rootFolder get folder structure for given folder, else root
     * @throws \Laminas\Mail\Storage\Exception\InvalidArgumentException
     * @return \Laminas\Mail\Storage\Folder root or wanted folder
     */
    public function getFolders($rootFolder = null)
    {
        if (! $rootFolder || $rootFolder == 'INBOX') {
            return $this->rootFolder;
        }

        // rootdir is same as INBOX in maildir
        if (strpos($rootFolder, 'INBOX' . $this->delim) === 0) {
            $rootFolder = substr($rootFolder, 6);
        }
        $currentFolder = $this->rootFolder;
        $subname = trim($rootFolder, $this->delim);

        while ($currentFolder) {
            ErrorHandler::start(E_NOTICE);
            list($entry, $subname) = explode($this->delim, $subname, 2);
            ErrorHandler::stop();
            $currentFolder = $currentFolder->$entry;
            if (! $subname) {
                break;
            }
        }

        if ($currentFolder->getGlobalName() != rtrim($rootFolder, $this->delim)) {
            throw new Exception\InvalidArgumentException("folder $rootFolder not found");
        }
        return $currentFolder;
    }

    /**
     * select given folder
     *
     * folder must be selectable!
     *
     * @param Storage\Folder|string $globalName global name of folder or
     *     instance for subfolder
     * @throws Exception\RuntimeException
     */
    public function selectFolder($globalName)
    {
        $this->currentFolder = (string) $globalName;

        // getting folder from folder tree for validation
        $folder = $this->getFolders($this->currentFolder);

        try {
            $this->openMaildir($this->rootdir . '.' . $folder->getGlobalName());
        } catch (Exception\ExceptionInterface $e) {
            // check what went wrong
            if (! $folder->isSelectable()) {
                throw new Exception\RuntimeException("{$this->currentFolder} is not selectable", 0, $e);
            }
            // seems like file has vanished; rebuilding folder tree - but it's still an exception
            $this->buildFolderTree();
            throw new Exception\RuntimeException(
                'seems like the maildir has vanished; I have rebuilt the folder tree; '
                . 'search for another folder and try again',
                0,
                $e
            );
        }
    }

    /**
     * get Storage\Folder instance for current folder
     *
     * @return Storage\Folder instance of current folder
     */
    public function getCurrentFolder()
    {
        return $this->currentFolder;
    }
}
laminas-mail/src/Storage/Folder/Mbox.php000064400000015546147361032560014156 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-mail for the canonical source repository
 * @copyright https://github.com/laminas/laminas-mail/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-mail/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Mail\Storage\Folder;

use Laminas\Config\Config;
use Laminas\Mail\Storage;
use Laminas\Mail\Storage\Exception;
use Laminas\Stdlib\ErrorHandler;

class Mbox extends Storage\Mbox implements FolderInterface
{
    /**
     * Storage\Folder root folder for folder structure
     * @var Storage\Folder
     */
    protected $rootFolder;

    /**
     * rootdir of folder structure
     * @var string
     */
    protected $rootdir;

    /**
     * name of current folder
     * @var string
     */
    protected $currentFolder;

    /**
     * Create instance with parameters
     *
     * Disallowed parameters are:
     * - filename use \Laminas\Mail\Storage\Mbox for a single file
     *
     * Supported parameters are:
     *
     * - dirname rootdir of mbox structure
     * - folder initial selected folder, default is 'INBOX'
     *
     * @param  $params array|object|Config mail reader specific parameters
     * @throws Exception\InvalidArgumentException
     */
    public function __construct($params)
    {
        if (is_array($params)) {
            $params = (object) $params;
        }

        if (isset($params->filename)) {
            throw new Exception\InvalidArgumentException(sprintf('use %s for a single file', Storage\Mbox::class));
        }

        if (! isset($params->dirname) || ! is_dir($params->dirname)) {
            throw new Exception\InvalidArgumentException('no valid dirname given in params');
        }

        $this->rootdir = rtrim($params->dirname, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR;

        $this->buildFolderTree($this->rootdir);
        $this->selectFolder(! empty($params->folder) ? $params->folder : 'INBOX');
        $this->has['top']      = true;
        $this->has['uniqueid'] = false;
    }

    /**
     * find all subfolders and mbox files for folder structure
     *
     * Result is save in Storage\Folder instances with the root in $this->rootFolder.
     * $parentFolder and $parentGlobalName are only used internally for recursion.
     *
     * @param string $currentDir call with root dir, also used for recursion.
     * @param Storage\Folder|null $parentFolder used for recursion
     * @param string $parentGlobalName used for recursion
     * @throws Exception\InvalidArgumentException
     */
    protected function buildFolderTree($currentDir, $parentFolder = null, $parentGlobalName = '')
    {
        if (! $parentFolder) {
            $this->rootFolder = new Storage\Folder('/', '/', false);
            $parentFolder = $this->rootFolder;
        }

        ErrorHandler::start(E_WARNING);
        $dh = opendir($currentDir);
        ErrorHandler::stop();
        if (! $dh) {
            throw new Exception\InvalidArgumentException("can't read dir $currentDir");
        }
        while (($entry = readdir($dh)) !== false) {
            // ignore hidden files for mbox
            if ($entry[0] == '.') {
                continue;
            }
            $absoluteEntry = $currentDir . $entry;
            $globalName = $parentGlobalName . DIRECTORY_SEPARATOR . $entry;
            if (is_file($absoluteEntry) && $this->isMboxFile($absoluteEntry)) {
                $parentFolder->$entry = new Storage\Folder($entry, $globalName);
                continue;
            }
            if (! is_dir($absoluteEntry) /* || $entry == '.' || $entry == '..' */) {
                continue;
            }
            $folder = new Storage\Folder($entry, $globalName, false);
            $parentFolder->$entry = $folder;
            $this->buildFolderTree($absoluteEntry . DIRECTORY_SEPARATOR, $folder, $globalName);
        }

        closedir($dh);
    }

    /**
     * get root folder or given folder
     *
     * @param string $rootFolder get folder structure for given folder, else root
     * @return Storage\Folder root or wanted folder
     * @throws Exception\InvalidArgumentException
     */
    public function getFolders($rootFolder = null)
    {
        if (! $rootFolder) {
            return $this->rootFolder;
        }

        $currentFolder = $this->rootFolder;
        $subname = trim($rootFolder, DIRECTORY_SEPARATOR);
        while ($currentFolder) {
            ErrorHandler::start(E_NOTICE);
            list($entry, $subname) = explode(DIRECTORY_SEPARATOR, $subname, 2);
            ErrorHandler::stop();
            $currentFolder = $currentFolder->$entry;
            if (! $subname) {
                break;
            }
        }

        if ($currentFolder->getGlobalName() != DIRECTORY_SEPARATOR . trim($rootFolder, DIRECTORY_SEPARATOR)) {
            throw new Exception\InvalidArgumentException("folder $rootFolder not found");
        }
        return $currentFolder;
    }

    /**
     * select given folder
     *
     * folder must be selectable!
     *
     * @param Storage\Folder|string $globalName global name of folder or
     *     instance for subfolder
     * @throws Exception\RuntimeException
     */
    public function selectFolder($globalName)
    {
        $this->currentFolder = (string) $globalName;

        // getting folder from folder tree for validation
        $folder = $this->getFolders($this->currentFolder);

        try {
            $this->openMboxFile($this->rootdir . $folder->getGlobalName());
        } catch (Exception\ExceptionInterface $e) {
            // check what went wrong
            if (! $folder->isSelectable()) {
                throw new Exception\RuntimeException("{$this->currentFolder} is not selectable", 0, $e);
            }
            // seems like file has vanished; rebuilding folder tree - but it's still an exception
            $this->buildFolderTree($this->rootdir);
            throw new Exception\RuntimeException(
                'seems like the mbox file has vanished; I have rebuilt the folder tree; '
                . 'search for another folder and try again',
                0,
                $e
            );
        }
    }

    /**
     * get Storage\Folder instance for current folder
     *
     * @return Storage\Folder instance of current folder
     * @throws Exception\ExceptionInterface
     */
    public function getCurrentFolder()
    {
        return $this->currentFolder;
    }

    /**
     * magic method for serialize()
     *
     * with this method you can cache the mbox class
     *
     * @return array name of variables
     */
    public function __sleep()
    {
        return array_merge(parent::__sleep(), ['currentFolder', 'rootFolder', 'rootdir']);
    }

    /**
     * magic method for unserialize(), with this method you can cache the mbox class
     */
    public function __wakeup()
    {
        // if cache is stall selectFolder() rebuilds the tree on error
        parent::__wakeup();
    }
}
laminas-mail/src/Storage/Folder/FolderInterface.php000064400000002202147361032560016266 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-mail for the canonical source repository
 * @copyright https://github.com/laminas/laminas-mail/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-mail/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Mail\Storage\Folder;

interface FolderInterface
{
    /**
     * get root folder or given folder
     *
     * @param string $rootFolder get folder structure for given folder, else root
     * @return FolderInterface root or wanted folder
     */
    public function getFolders($rootFolder = null);

    /**
     * select given folder
     *
     * folder must be selectable!
     *
     * @param FolderInterface|string $globalName global name of folder or instance for subfolder
     * @throws \Laminas\Mail\Storage\Exception\ExceptionInterface
     */
    public function selectFolder($globalName);

    /**
     * get Laminas\Mail\Storage\Folder instance for current folder
     *
     * @return FolderInterface instance of current folder
     * @throws \Laminas\Mail\Storage\Exception\ExceptionInterface
     */
    public function getCurrentFolder();
}
laminas-mail/src/Storage/Pop3.php000064400000021612147361032560012646 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-mail for the canonical source repository
 * @copyright https://github.com/laminas/laminas-mail/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-mail/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Mail\Storage;

use Laminas\Config\Config;
use Laminas\Mail\Exception as MailException;
use Laminas\Mail\Protocol;
use Laminas\Mime;

class Pop3 extends AbstractStorage
{
    /**
     * protocol handler
     * @var null|\Laminas\Mail\Protocol\Pop3
     */
    protected $protocol;

    /**
     * Count messages all messages in current box
     *
     * @return int number of messages
     * @throws \Laminas\Mail\Storage\Exception\ExceptionInterface
     * @throws \Laminas\Mail\Protocol\Exception\ExceptionInterface
     */
    public function countMessages()
    {
        $count  = 0; // "Declare" variable before first usage.
        $octets = 0; // "Declare" variable since it's passed by reference
        $this->protocol->status($count, $octets);
        return (int) $count;
    }

    /**
     * get a list of messages with number and size
     *
     * @param int $id number of message
     * @return int|array size of given message of list with all messages as array(num => size)
     * @throws \Laminas\Mail\Protocol\Exception\ExceptionInterface
     */
    public function getSize($id = 0)
    {
        $id = $id ? $id : null;
        return $this->protocol->getList($id);
    }

    /**
     * Fetch a message
     *
     * @param int $id number of message
     * @return \Laminas\Mail\Storage\Message
     * @throws \Laminas\Mail\Protocol\Exception\ExceptionInterface
     */
    public function getMessage($id)
    {
        $bodyLines = 0;
        $message = $this->protocol->top($id, $bodyLines, true);

        return new $this->messageClass([
            'handler' => $this,
            'id' => $id,
            'headers' => $message,
            'noToplines' => $bodyLines < 1,
        ]);
    }

    /*
     * Get raw header of message or part
     *
     * @param  int               $id       number of message
     * @param  null|array|string $part     path to part or null for message header
     * @param  int               $topLines include this many lines with header (after an empty line)
     * @return string raw header
     * @throws \Laminas\Mail\Protocol\Exception\ExceptionInterface
     * @throws \Laminas\Mail\Storage\Exception\ExceptionInterface
     */
    public function getRawHeader($id, $part = null, $topLines = 0)
    {
        if ($part !== null) {
            // TODO: implement
            throw new Exception\RuntimeException('not implemented');
        }

        return $this->protocol->top($id, 0, true);
    }

    /*
     * Get raw content of message or part
     *
     * @param  int               $id   number of message
     * @param  null|array|string $part path to part or null for message content
     * @return string raw content
     * @throws \Laminas\Mail\Protocol\Exception\ExceptionInterface
     * @throws \Laminas\Mail\Storage\Exception\ExceptionInterface
     */
    public function getRawContent($id, $part = null)
    {
        if ($part !== null) {
            // TODO: implement
            throw new Exception\RuntimeException('not implemented');
        }

        $content = $this->protocol->retrieve($id);
        // TODO: find a way to avoid decoding the headers
        $headers = null; // "Declare" variable since it's passed by reference
        $body    = null; // "Declare" variable before first usage.
        Mime\Decode::splitMessage($content, $headers, $body);
        return $body;
    }

    // @codingStandardsIgnoreStart
    /**
     * create instance with parameters
     * Supported parameters are
     *   - host hostname or ip address of POP3 server
     *   - user username
     *   - password password for user 'username' [optional, default = '']
     *   - port port for POP3 server [optional, default = 110]
     *   - ssl 'SSL' or 'TLS' for secure sockets
     *
     * @param  array|object|Config|Protocol\Pop3 $params mail reader specific parameters or configured Pop3 protocol object
     * @throws \Laminas\Mail\Storage\Exception\InvalidArgumentException
     * @throws \Laminas\Mail\Protocol\Exception\RuntimeException
     */
    // @codingStandardsIgnoreEnd
    public function __construct($params)
    {
        if (is_array($params)) {
            $params = (object) $params;
        }

        $this->has['fetchPart'] = false;
        $this->has['top']       = null;
        $this->has['uniqueid']  = null;

        if ($params instanceof Protocol\Pop3) {
            $this->protocol = $params;
            return;
        }

        if (! isset($params->user)) {
            throw new Exception\InvalidArgumentException('need at least user in params');
        }

        $host     = isset($params->host) ? $params->host : 'localhost';
        $password = isset($params->password) ? $params->password : '';
        $port     = isset($params->port) ? $params->port : null;
        $ssl      = isset($params->ssl) ? $params->ssl : false;

        $this->protocol = new Protocol\Pop3();

        if (isset($params->novalidatecert)) {
            $this->protocol->setNoValidateCert((bool)$params->novalidatecert);
        }

        $this->protocol->connect($host, $port, $ssl);
        $this->protocol->login($params->user, $password);
    }

    /**
     * Close resource for mail lib. If you need to control, when the resource
     * is closed. Otherwise the destructor would call this.
     */
    public function close()
    {
        $this->protocol->logout();
    }

    /**
     * Keep the server busy.
     *
     * @throws \Laminas\Mail\Protocol\Exception\RuntimeException
     */
    public function noop()
    {
        $this->protocol->noop();
    }

    /**
     * Remove a message from server. If you're doing that from a web environment
     * you should be careful and use a uniqueid as parameter if possible to
     * identify the message.
     *
     * @param  int $id number of message
     * @throws \Laminas\Mail\Protocol\Exception\RuntimeException
     */
    public function removeMessage($id)
    {
        $this->protocol->delete($id);
    }

    /**
     * get unique id for one or all messages
     *
     * if storage does not support unique ids it's the same as the message number
     *
     * @param int|null $id message number
     * @return array|string message number for given message or all messages as array
     * @throws \Laminas\Mail\Storage\Exception\ExceptionInterface
     */
    public function getUniqueId($id = null)
    {
        if (! $this->hasUniqueid) {
            if ($id) {
                return $id;
            }
            $count = $this->countMessages();
            if ($count < 1) {
                return [];
            }
            $range = range(1, $count);
            return array_combine($range, $range);
        }

        return $this->protocol->uniqueid($id);
    }

    /**
     * get a message number from a unique id
     *
     * I.e. if you have a webmailer that supports deleting messages you should use unique ids
     * as parameter and use this method to translate it to message number right before calling removeMessage()
     *
     * @param string $id unique id
     * @throws Exception\InvalidArgumentException
     * @return int message number
     */
    public function getNumberByUniqueId($id)
    {
        if (! $this->hasUniqueid) {
            return $id;
        }

        $ids = $this->getUniqueId();
        foreach ($ids as $k => $v) {
            if ($v == $id) {
                return $k;
            }
        }

        throw new Exception\InvalidArgumentException('unique id not found');
    }

    /**
     * Special handling for hasTop and hasUniqueid. The headers of the first message is
     * retrieved if Top wasn't needed/tried yet.
     *
     * @see AbstractStorage::__get()
     * @param  string $var
     * @return string
     */
    public function __get($var)
    {
        $result = parent::__get($var);
        if ($result !== null) {
            return $result;
        }

        if (strtolower($var) == 'hastop') {
            if ($this->protocol->hasTop === null) {
                // need to make a real call, because not all server are honest in their capas
                try {
                    $this->protocol->top(1, 0, false);
                } catch (MailException\ExceptionInterface $e) {
                    // ignoring error
                }
            }
            $this->has['top'] = $this->protocol->hasTop;
            return $this->protocol->hasTop;
        }

        if (strtolower($var) == 'hasuniqueid') {
            $id = null;
            try {
                $id = $this->protocol->uniqueid(1);
            } catch (MailException\ExceptionInterface $e) {
                // ignoring error
            }
            $this->has['uniqueid'] = (bool) $id;
            return $this->has['uniqueid'];
        }

        return $result;
    }
}
laminas-mail/src/Storage/Folder.php000064400000011261147361032560013237 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-mail for the canonical source repository
 * @copyright https://github.com/laminas/laminas-mail/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-mail/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Mail\Storage;

use RecursiveIterator;

class Folder implements RecursiveIterator
{
    /**
     * subfolders of folder array(localName => \Laminas\Mail\Storage\Folder folder)
     * @var array
     */
    protected $folders;

    /**
     * local name (name of folder in parent folder)
     * @var string
     */
    protected $localName;

    /**
     * global name (absolute name of folder)
     * @var string
     */
    protected $globalName;

    /**
     * folder is selectable if folder is able to hold messages, otherwise it is a parent folder
     * @var bool
     */
    protected $selectable = true;

    /**
     * create a new mail folder instance
     *
     * @param string $localName  name of folder in current subdirectory
     * @param string $globalName absolute name of folder
     * @param bool $selectable if true folder holds messages, if false it's
     *     just a parent for subfolders (Default: true)
     * @param array $folders init with given instances of Folder as subfolders
     */
    public function __construct($localName, $globalName = '', $selectable = true, array $folders = [])
    {
        $this->localName  = $localName;
        $this->globalName = $globalName ? $globalName : $localName;
        $this->selectable = $selectable;
        $this->folders    = $folders;
    }

    /**
     * implements RecursiveIterator::hasChildren()
     *
     * @return bool current element has children
     */
    public function hasChildren()
    {
        $current = $this->current();
        return $current && $current instanceof self && ! $current->isLeaf();
    }

    /**
     * implements RecursiveIterator::getChildren()
     *
     * @return \Laminas\Mail\Storage\Folder same as self::current()
     */
    public function getChildren()
    {
        return $this->current();
    }

    /**
     * implements Iterator::valid()
     *
     * @return bool check if there's a current element
     */
    public function valid()
    {
        return key($this->folders) !== null;
    }

    /**
     * implements Iterator::next()
     */
    public function next()
    {
        next($this->folders);
    }

    /**
     * implements Iterator::key()
     *
     * @return string key/local name of current element
     */
    public function key()
    {
        return key($this->folders);
    }

    /**
     * implements Iterator::current()
     *
     * @return \Laminas\Mail\Storage\Folder current folder
     */
    public function current()
    {
        return current($this->folders);
    }

    /**
     * implements Iterator::rewind()
     */
    public function rewind()
    {
        reset($this->folders);
    }

    /**
     * get subfolder named $name
     *
     * @param  string $name wanted subfolder
     * @throws Exception\InvalidArgumentException
     * @return \Laminas\Mail\Storage\Folder folder named $folder
     */
    public function __get($name)
    {
        if (! isset($this->folders[$name])) {
            throw new Exception\InvalidArgumentException("no subfolder named $name");
        }

        return $this->folders[$name];
    }

    /**
     * add or replace subfolder named $name
     *
     * @param string $name local name of subfolder
     * @param \Laminas\Mail\Storage\Folder $folder instance for new subfolder
     */
    public function __set($name, self $folder)
    {
        $this->folders[$name] = $folder;
    }

    /**
     * remove subfolder named $name
     *
     * @param string $name local name of subfolder
     */
    public function __unset($name)
    {
        unset($this->folders[$name]);
    }

    /**
     * magic method for easy output of global name
     *
     * @return string global name of folder
     */
    public function __toString()
    {
        return (string) $this->getGlobalName();
    }

    /**
     * get local name
     *
     * @return string local name
     */
    public function getLocalName()
    {
        return $this->localName;
    }

    /**
     * get global name
     *
     * @return string global name
     */
    public function getGlobalName()
    {
        return $this->globalName;
    }

    /**
     * is this folder selectable?
     *
     * @return bool selectable
     */
    public function isSelectable()
    {
        return $this->selectable;
    }

    /**
     * check if folder has no subfolder
     *
     * @return bool true if no subfolders
     */
    public function isLeaf()
    {
        return empty($this->folders);
    }
}
laminas-mail/src/Storage/Part/PartInterface.php000064400000007150147361032560015463 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-mail for the canonical source repository
 * @copyright https://github.com/laminas/laminas-mail/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-mail/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Mail\Storage\Part;

use ArrayIterator;
use Laminas\Mail\Header\HeaderInterface;
use Laminas\Mail\Headers;
use RecursiveIterator;

interface PartInterface extends RecursiveIterator
{
    /**
     * Check if part is a multipart message
     *
     * @return bool if part is multipart
     */
    public function isMultipart();

    /**
     * Body of part
     *
     * If part is multipart the raw content of this part with all sub parts is
     * returned.
     *
     * @return string body
     * @throws Exception\ExceptionInterface
     */
    public function getContent();

    /**
     * Return size of part
     *
     * @return int size
     */
    public function getSize();

    /**
     * Get part of multipart message
     *
     * @param  int $num number of part starting with 1 for first part
     * @return PartInterface wanted part
     * @throws Exception\ExceptionInterface
     */
    public function getPart($num);

    /**
     * Count parts of a multipart part
     *
     * @return int number of sub-parts
     */
    public function countParts();

    /**
     * Get all headers
     *
     * The returned headers are as saved internally. All names are lowercased.
     * The value is a string or an array if a header with the same name occurs
     * more than once.
     *
     * @return Headers
     */
    public function getHeaders();

    /**
     * Get a header in specified format
     *
     * Internally headers that occur more than once are saved as array, all
     * other as string. If $format is set to string implode is used to concat
     * the values (with Laminas\Mime\Mime::LINEEND as delim).
     *
     * @param string $name name of header, matches case-insensitive, but
     *     camel-case is replaced with dashes
     * @param string $format change type of return value to 'string' or 'array'
     * @return string|array|HeaderInterface|ArrayIterator value of header in
     *     wanted or internal format
     * @throws Exception\ExceptionInterface
     */
    public function getHeader($name, $format = null);

    /**
     * Get a specific field from a header like content type or all fields as array
     *
     * If the header occurs more than once, only the value from the first
     * header is returned.
     *
     * Throws an exception if the requested header does not exist. If the
     * specific header field does not exist, returns null.
     *
     * @param string $name name of header, like in getHeader()
     * @param string $wantedPart the wanted part, default is first, if null an
     *     array with all parts is returned
     * @param string $firstName key name for the first part
     * @return string|array wanted part or all parts as
     *     [$firstName => firstPart, partname => value]
     * @throws Exception\ExceptionInterface
     */
    public function getHeaderField($name, $wantedPart = '0', $firstName = '0');

    /**
     * Getter for mail headers - name is matched in lowercase
     *
     * This getter is short for PartInterface::getHeader($name, 'string')
     *
     * @see PartInterface::getHeader()
     * @param  string $name header name
     * @return string value of header
     * @throws Exception\ExceptionInterface
     */
    public function __get($name);

    /**
     * magic method to get content of part
     *
     * @return string content
     */
    public function __toString();
}
laminas-mail/src/Storage/Part/Exception/ExceptionInterface.php000064400000000714147361032560020450 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-mail for the canonical source repository
 * @copyright https://github.com/laminas/laminas-mail/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-mail/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Mail\Storage\Part\Exception;

use Laminas\Mail\Storage\Exception\ExceptionInterface as StorageException;

interface ExceptionInterface extends StorageException
{
}
laminas-mail/src/Storage/Part/Exception/InvalidArgumentException.php000064400000001010147361032560021627 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-mail for the canonical source repository
 * @copyright https://github.com/laminas/laminas-mail/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-mail/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Mail\Storage\Part\Exception;

use Laminas\Mail\Storage\Exception;

/**
 * Exception for Laminas\Mail component.
 */
class InvalidArgumentException extends Exception\InvalidArgumentException implements ExceptionInterface
{
}
laminas-mail/src/Storage/Part/Exception/RuntimeException.php000064400000000770147361032560020175 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-mail for the canonical source repository
 * @copyright https://github.com/laminas/laminas-mail/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-mail/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Mail\Storage\Part\Exception;

use Laminas\Mail\Storage\Exception;

/**
 * Exception for Laminas\Mail component.
 */
class RuntimeException extends Exception\RuntimeException implements ExceptionInterface
{
}
laminas-mail/src/Storage/Part/File.php000064400000011540147361032560013611 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-mail for the canonical source repository
 * @copyright https://github.com/laminas/laminas-mail/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-mail/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Mail\Storage\Part;

use Laminas\Mail\Headers;
use Laminas\Mail\Storage\Part;

class File extends Part
{
    protected $contentPos = [];
    protected $partPos = [];
    protected $fh;

    /**
     * Public constructor
     *
     * This handler supports the following params:
     * - file     filename or open file handler with message content (required)
     * - startPos start position of message or part in file (default: current position)
     * - endPos   end position of message or part in file (default: end of file)
     * - EOL      end of Line for messages
     *
     * @param   array $params  full message with or without headers
     * @throws Exception\RuntimeException
     * @throws Exception\InvalidArgumentException
     */
    public function __construct(array $params)
    {
        if (empty($params['file'])) {
            throw new Exception\InvalidArgumentException('no file given in params');
        }

        if (! is_resource($params['file'])) {
            $this->fh = fopen($params['file'], 'r');
        } else {
            $this->fh = $params['file'];
        }
        if (! $this->fh) {
            throw new Exception\RuntimeException('could not open file');
        }
        if (isset($params['startPos'])) {
            fseek($this->fh, $params['startPos']);
        }
        $header = '';
        $endPos = $params['endPos'] ?? null;
        while (($endPos === null || ftell($this->fh) < $endPos) && trim($line = fgets($this->fh))) {
            $header .= $line;
        }

        if (isset($params['EOL'])) {
            $this->headers = Headers::fromString($header, $params['EOL']);
        } else {
            $this->headers = Headers::fromString($header);
        }

        $this->contentPos[0] = ftell($this->fh);
        if ($endPos !== null) {
            $this->contentPos[1] = $endPos;
        } else {
            fseek($this->fh, 0, SEEK_END);
            $this->contentPos[1] = ftell($this->fh);
        }
        if (! $this->isMultipart()) {
            return;
        }

        $boundary = $this->getHeaderField('content-type', 'boundary');
        if (! $boundary) {
            throw new Exception\RuntimeException('no boundary found in content type to split message');
        }

        $part = [];
        $pos = $this->contentPos[0];
        fseek($this->fh, $pos);
        while (! feof($this->fh) && ($endPos === null || $pos < $endPos)) {
            $line = fgets($this->fh);
            if ($line === false) {
                if (feof($this->fh)) {
                    break;
                }
                throw new Exception\RuntimeException('error reading file');
            }

            $lastPos = $pos;
            $pos = ftell($this->fh);
            $line = trim($line);

            if ($line == '--' . $boundary) {
                if ($part) {
                    // not first part
                    $part[1] = $lastPos;
                    $this->partPos[] = $part;
                }
                $part = [$pos];
            } elseif ($line == '--' . $boundary . '--') {
                $part[1] = $lastPos;
                $this->partPos[] = $part;
                break;
            }
        }
        $this->countParts = count($this->partPos);
    }

    /**
     * Body of part
     *
     * If part is multipart the raw content of this part with all sub parts is returned
     *
     * @param resource $stream Optional
     * @return string body
     */
    public function getContent($stream = null)
    {
        fseek($this->fh, $this->contentPos[0]);
        if ($stream !== null) {
            return stream_copy_to_stream($this->fh, $stream, $this->contentPos[1] - $this->contentPos[0]);
        }
        $length = $this->contentPos[1] - $this->contentPos[0];
        return $length < 1 ? '' : fread($this->fh, $length);
    }

    /**
     * Return size of part
     *
     * Quite simple implemented currently (not decoding). Handle with care.
     *
     * @return int size
     */
    public function getSize()
    {
        return $this->contentPos[1] - $this->contentPos[0];
    }

    /**
     * Get part of multipart message
     *
     * @param  int $num number of part starting with 1 for first part
     * @throws Exception\RuntimeException
     * @return Part wanted part
     */
    public function getPart($num)
    {
        --$num;
        if (! isset($this->partPos[$num])) {
            throw new Exception\RuntimeException('part not found');
        }

        return new static([
            'file' => $this->fh,
            'startPos' => $this->partPos[$num][0],
            'endPos' => $this->partPos[$num][1],
        ]);
    }
}
laminas-mail/src/Storage/Part.php000064400000031623147361032560012736 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-mail for the canonical source repository
 * @copyright https://github.com/laminas/laminas-mail/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-mail/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Mail\Storage;

use Laminas\Mail\Header\HeaderInterface;
use Laminas\Mail\Headers;
use Laminas\Mime;
use RecursiveIterator;

class Part implements RecursiveIterator, Part\PartInterface
{
    /**
     * Headers of the part
     * @var Headers|null
     */
    protected $headers;

    /**
     * raw part body
     * @var null|string
     */
    protected $content;

    /**
     * toplines as fetched with headers
     * @var string
     */
    protected $topLines = '';

    /**
     * parts of multipart message
     * @var array
     */
    protected $parts = [];

    /**
     * count of parts of a multipart message
     * @var null|int
     */
    protected $countParts;

    /**
     * current position of iterator
     * @var int
     */
    protected $iterationPos = 1;

    /**
     * mail handler, if late fetch is active
     * @var null|AbstractStorage
     */
    protected $mail;

    /**
     * message number for mail handler
     * @var int
     */
    protected $messageNum = 0;

    /**
     * Public constructor
     *
     * Part supports different sources for content. The possible params are:
     * - handler    an instance of AbstractStorage for late fetch
     * - id         number of message for handler
     * - raw        raw content with header and body as string
     * - headers    headers as array (name => value) or string, if a content part is found it's used as toplines
     * - noToplines ignore content found after headers in param 'headers'
     * - content    content as string
     * - strict     strictly parse raw content
     *
     * @param   array $params  full message with or without headers
     * @throws Exception\InvalidArgumentException
     */
    public function __construct(array $params)
    {
        if (isset($params['handler'])) {
            if (! $params['handler'] instanceof AbstractStorage) {
                throw new Exception\InvalidArgumentException('handler is not a valid mail handler');
            }
            if (! isset($params['id'])) {
                throw new Exception\InvalidArgumentException('need a message id with a handler');
            }

            $this->mail       = $params['handler'];
            $this->messageNum = $params['id'];
        }

        $params['strict'] = $params['strict'] ?? false;

        if (isset($params['raw'])) {
            Mime\Decode::splitMessage(
                $params['raw'],
                $this->headers,
                $this->content,
                Mime\Mime::LINEEND,
                $params['strict']
            );
        } elseif (isset($params['headers'])) {
            if (is_array($params['headers'])) {
                $this->headers = new Headers();
                $this->headers->addHeaders($params['headers']);
            } else {
                if (empty($params['noToplines'])) {
                    Mime\Decode::splitMessage($params['headers'], $this->headers, $this->topLines);
                } else {
                    $this->headers = Headers::fromString($params['headers']);
                }
            }

            if (isset($params['content'])) {
                $this->content = $params['content'];
            }
        }
    }

    /**
     * Check if part is a multipart message
     *
     * @return bool if part is multipart
     */
    public function isMultipart()
    {
        try {
            return stripos($this->contentType, 'multipart/') === 0;
        } catch (Exception\ExceptionInterface $e) {
            return false;
        }
    }

    /**
     * Body of part
     *
     * If part is multipart the raw content of this part with all sub parts is returned
     *
     * @throws Exception\RuntimeException
     * @return string body
     */
    public function getContent()
    {
        if ($this->content !== null) {
            return $this->content;
        }

        if ($this->mail) {
            return $this->mail->getRawContent($this->messageNum);
        }

        throw new Exception\RuntimeException('no content');
    }

    /**
     * Return size of part
     *
     * Quite simple implemented currently (not decoding). Handle with care.
     *
     * @return int size
     */
    public function getSize()
    {
        return strlen($this->getContent());
    }

    /**
     * Cache content and split in parts if multipart
     *
     * @throws Exception\RuntimeException
     * @return null
     */
    protected function cacheContent()
    {
        // caching content if we can't fetch parts
        if ($this->content === null && $this->mail) {
            $this->content = $this->mail->getRawContent($this->messageNum);
        }

        if (! $this->isMultipart()) {
            return;
        }

        // split content in parts
        $boundary = $this->getHeaderField('content-type', 'boundary');
        if (! $boundary) {
            throw new Exception\RuntimeException('no boundary found in content type to split message');
        }
        $parts = Mime\Decode::splitMessageStruct($this->content, $boundary);
        if ($parts === null) {
            return;
        }
        $counter = 1;
        foreach ($parts as $part) {
            $this->parts[$counter++] = new static(['headers' => $part['header'], 'content' => $part['body']]);
        }
    }

    /**
     * Get part of multipart message
     *
     * @param  int $num number of part starting with 1 for first part
     * @throws Exception\RuntimeException
     * @return Part wanted part
     */
    public function getPart($num)
    {
        if (isset($this->parts[$num])) {
            return $this->parts[$num];
        }

        if (! $this->mail && $this->content === null) {
            throw new Exception\RuntimeException('part not found');
        }

        if ($this->mail && $this->mail->hasFetchPart) {
            // TODO: fetch part
            // return
        }

        $this->cacheContent();

        if (! isset($this->parts[$num])) {
            throw new Exception\RuntimeException('part not found');
        }

        return $this->parts[$num];
    }

    /**
     * Count parts of a multipart part
     *
     * @return int number of sub-parts
     */
    public function countParts()
    {
        if ($this->countParts) {
            return $this->countParts;
        }

        $this->countParts = count($this->parts);
        if ($this->countParts) {
            return $this->countParts;
        }

        if ($this->mail && $this->mail->hasFetchPart) {
            // TODO: fetch part
            // return
        }

        $this->cacheContent();

        $this->countParts = count($this->parts);
        return $this->countParts;
    }

    /**
     * Access headers collection
     *
     * Lazy-loads if not already attached.
     *
     * @return Headers
     * @throws Exception\RuntimeException
     */
    public function getHeaders()
    {
        if (null === $this->headers) {
            if ($this->mail) {
                $part = $this->mail->getRawHeader($this->messageNum);
                $this->headers = Headers::fromString($part);
            } else {
                $this->headers = new Headers();
            }
        }
        if (! $this->headers instanceof Headers) {
            throw new Exception\RuntimeException(
                '$this->headers must be an instance of Headers'
            );
        }

        return $this->headers;
    }

    /**
     * Get a header in specified format
     *
     * Internally headers that occur more than once are saved as array, all other as string. If $format
     * is set to string implode is used to concat the values (with Mime::LINEEND as delim).
     *
     * @param  string $name   name of header, matches case-insensitive, but camel-case is replaced with dashes
     * @param  string $format change type of return value to 'string' or 'array'
     * @throws Exception\InvalidArgumentException
     * @return string|array|HeaderInterface|\ArrayIterator value of header in wanted or internal format
     */
    public function getHeader($name, $format = null)
    {
        $header = $this->getHeaders()->get($name);
        if ($header === false) {
            $lowerName = strtolower(preg_replace('%([a-z])([A-Z])%', '\1-\2', $name));
            $header = $this->getHeaders()->get($lowerName);
            if ($header === false) {
                throw new Exception\InvalidArgumentException(
                    "Header with Name $name or $lowerName not found"
                );
            }
        }

        switch ($format) {
            case 'string':
                if ($header instanceof HeaderInterface) {
                    $return = $header->getFieldValue(HeaderInterface::FORMAT_RAW);
                } else {
                    $return = '';
                    foreach ($header as $h) {
                        $return .= $h->getFieldValue(HeaderInterface::FORMAT_RAW)
                                 . Mime\Mime::LINEEND;
                    }
                    $return = trim($return, Mime\Mime::LINEEND);
                }
                break;
            case 'array':
                if ($header instanceof HeaderInterface) {
                    $return = [$header->getFieldValue()];
                } else {
                    $return = [];
                    foreach ($header as $h) {
                        $return[] = $h->getFieldValue(HeaderInterface::FORMAT_RAW);
                    }
                }
                break;
            default:
                $return = $header;
        }

        return $return;
    }

    /**
     * Get a specific field from a header like content type or all fields as array
     *
     * If the header occurs more than once, only the value from the first header
     * is returned.
     *
     * Throws an Exception if the requested header does not exist. If
     * the specific header field does not exist, returns null.
     *
     * @param  string $name       name of header, like in getHeader()
     * @param  string $wantedPart the wanted part, default is first, if null an array with all parts is returned
     * @param  string $firstName  key name for the first part
     * @return string|array wanted part or all parts as array($firstName => firstPart, partname => value)
     * @throws \Laminas\Mime\Exception\RuntimeException
     */
    public function getHeaderField($name, $wantedPart = '0', $firstName = '0')
    {
        return Mime\Decode::splitHeaderField(current($this->getHeader($name, 'array')), $wantedPart, $firstName);
    }

    /**
     * Getter for mail headers - name is matched in lowercase
     *
     * This getter is short for Part::getHeader($name, 'string')
     *
     * @see Part::getHeader()
     *
     * @param  string $name header name
     * @return string value of header
     * @throws Exception\ExceptionInterface
     */
    public function __get($name)
    {
        return $this->getHeader($name, 'string');
    }

    /**
     * Isset magic method proxy to hasHeader
     *
     * This method is short syntax for Part::hasHeader($name);
     *
     * @see Part::hasHeader
     *
     * @param  string
     * @return bool
     */
    public function __isset($name)
    {
        return $this->getHeaders()->has($name);
    }

    /**
     * magic method to get content of part
     *
     * @return string content
     */
    public function __toString()
    {
        return $this->getContent();
    }

    /**
     * implements RecursiveIterator::hasChildren()
     *
     * @return bool current element has children/is multipart
     */
    public function hasChildren()
    {
        $current = $this->current();
        return $current && $current instanceof self && $current->isMultipart();
    }

    /**
     * implements RecursiveIterator::getChildren()
     *
     * @return Part same as self::current()
     */
    public function getChildren()
    {
        return $this->current();
    }

    /**
     * implements Iterator::valid()
     *
     * @return bool check if there's a current element
     */
    public function valid()
    {
        if ($this->countParts === null) {
            $this->countParts();
        }
        return $this->iterationPos && $this->iterationPos <= $this->countParts;
    }

    /**
     * implements Iterator::next()
     */
    public function next()
    {
        ++$this->iterationPos;
    }

    /**
     * implements Iterator::key()
     *
     * @return string key/number of current part
     */
    public function key()
    {
        return $this->iterationPos;
    }

    /**
     * implements Iterator::current()
     *
     * @return Part current part
     */
    public function current()
    {
        return $this->getPart($this->iterationPos);
    }

    /**
     * implements Iterator::rewind()
     */
    public function rewind()
    {
        $this->countParts();
        $this->iterationPos = 1;
    }
}
laminas-mail/src/Storage/Maildir.php000064400000027647147361032560013424 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-mail for the canonical source repository
 * @copyright https://github.com/laminas/laminas-mail/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-mail/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Mail\Storage;

use Laminas\Config\Config;
use Laminas\Mail;
use Laminas\Stdlib\ErrorHandler;

class Maildir extends AbstractStorage
{
    /**
     * used message class, change it in an extended class to extend the returned message class
     * @var string
     */
    protected $messageClass = Message\File::class;

    /**
     * data of found message files in maildir dir
     * @var array
     */
    protected $files = [];

    /**
     * known flag chars in filenames
     *
     * This list has to be in alphabetical order for setFlags()
     *
     * @var array
     */
    protected static $knownFlags = [
        'D' => Mail\Storage::FLAG_DRAFT,
        'F' => Mail\Storage::FLAG_FLAGGED,
        'P' => Mail\Storage::FLAG_PASSED,
        'R' => Mail\Storage::FLAG_ANSWERED,
        'S' => Mail\Storage::FLAG_SEEN,
        'T' => Mail\Storage::FLAG_DELETED,
    ];

    // TODO: getFlags($id) for fast access if headers are not needed (i.e. just setting flags)?

    /**
     * Count messages all messages in current box
     *
     * @param mixed $flags
     * @return int number of messages
     */
    public function countMessages($flags = null)
    {
        if ($flags === null) {
            return count($this->files);
        }

        $count = 0;
        if (! is_array($flags)) {
            foreach ($this->files as $file) {
                if (isset($file['flaglookup'][$flags])) {
                    ++$count;
                }
            }
            return $count;
        }

        $flags = array_flip($flags);
        foreach ($this->files as $file) {
            foreach ($flags as $flag => $v) {
                if (! isset($file['flaglookup'][$flag])) {
                    continue 2;
                }
            }
            ++$count;
        }
        return $count;
    }

    /**
     * Get one or all fields from file structure. Also checks if message is valid
     *
     * @param  int         $id    message number
     * @param  string|null $field wanted field
     * @throws Exception\InvalidArgumentException
     * @return string|array wanted field or all fields as array
     */
    protected function getFileData($id, $field = null)
    {
        if (! isset($this->files[$id - 1])) {
            throw new Exception\InvalidArgumentException('id does not exist');
        }

        if (! $field) {
            return $this->files[$id - 1];
        }

        if (! isset($this->files[$id - 1][$field])) {
            throw new Exception\InvalidArgumentException('field does not exist');
        }

        return $this->files[$id - 1][$field];
    }

    /**
     * Get a list of messages with number and size
     *
     * @param  int|null $id number of message or null for all messages
     * @return int|array size of given message of list with all messages as array(num => size)
     */
    public function getSize($id = null)
    {
        if ($id !== null) {
            $filedata = $this->getFileData($id);
            return $filedata['size'] ?? filesize($filedata['filename']);
        }

        $result = [];
        foreach ($this->files as $num => $data) {
            $result[$num + 1] = $data['size'] ?? filesize($data['filename']);
        }

        return $result;
    }

    /**
     * Fetch a message
     *
     * @param  int $id number of message
     * @return \Laminas\Mail\Storage\Message\File
     * @throws \Laminas\Mail\Storage\Exception\ExceptionInterface
     */
    public function getMessage($id)
    {
        // TODO that's ugly, would be better to let the message class decide
        if (\trim($this->messageClass, '\\') === Message\File::class
            || is_subclass_of($this->messageClass, Message\File::class)
        ) {
            return new $this->messageClass([
                'file'  => $this->getFileData($id, 'filename'),
                'flags' => $this->getFileData($id, 'flags'),
            ]);
        }

        return new $this->messageClass([
            'handler' => $this,
            'id'      => $id,
            'headers' => $this->getRawHeader($id),
            'flags'   => $this->getFileData($id, 'flags'),
        ]);
    }

    /*
     * Get raw header of message or part
     *
     * @param  int               $id       number of message
     * @param  null|array|string $part     path to part or null for message header
     * @param  int               $topLines include this many lines with header (after an empty line)
     * @throws Exception\RuntimeException
     * @return string raw header
     */
    public function getRawHeader($id, $part = null, $topLines = 0)
    {
        if ($part !== null) {
            // TODO: implement
            throw new Exception\RuntimeException('not implemented');
        }

        $fh = fopen($this->getFileData($id, 'filename'), 'r');

        $content = '';
        while (! feof($fh)) {
            $line = fgets($fh);
            if (! trim($line)) {
                break;
            }
            $content .= $line;
        }

        fclose($fh);
        return $content;
    }

    /*
     * Get raw content of message or part
     *
     * @param  int               $id   number of message
     * @param  null|array|string $part path to part or null for message content
     * @throws Exception\RuntimeException
     * @return string raw content
     */
    public function getRawContent($id, $part = null)
    {
        if ($part !== null) {
            // TODO: implement
            throw new Exception\RuntimeException('not implemented');
        }

        $fh = fopen($this->getFileData($id, 'filename'), 'r');

        while (! feof($fh)) {
            $line = fgets($fh);
            if (! trim($line)) {
                break;
            }
        }

        $content = stream_get_contents($fh);
        fclose($fh);
        return $content;
    }

    /**
     * Create instance with parameters
     * Supported parameters are:
     *   - dirname dirname of mbox file
     *
     * @param  $params array|object|Config mail reader specific parameters
     * @throws Exception\InvalidArgumentException
     */
    public function __construct($params)
    {
        if (is_array($params)) {
            $params = (object) $params;
        }

        if (! isset($params->dirname) || ! is_dir($params->dirname)) {
            throw new Exception\InvalidArgumentException('no valid dirname given in params');
        }

        if (! $this->isMaildir($params->dirname)) {
            throw new Exception\InvalidArgumentException('invalid maildir given');
        }

        $this->has['top'] = true;
        $this->has['flags'] = true;
        $this->openMaildir($params->dirname);
    }

    /**
     * check if a given dir is a valid maildir
     *
     * @param string $dirname name of dir
     * @return bool dir is valid maildir
     */
    protected function isMaildir($dirname)
    {
        if (file_exists($dirname . '/new') && ! is_dir($dirname . '/new')) {
            return false;
        }
        if (file_exists($dirname . '/tmp') && ! is_dir($dirname . '/tmp')) {
            return false;
        }
        return is_dir($dirname . '/cur');
    }

    /**
     * open given dir as current maildir
     *
     * @param string $dirname name of maildir
     * @throws Exception\RuntimeException
     */
    protected function openMaildir($dirname)
    {
        if ($this->files) {
            $this->close();
        }

        ErrorHandler::start(E_WARNING);
        $dh    = opendir($dirname . '/cur/');
        $error = ErrorHandler::stop();
        if (! $dh) {
            throw new Exception\RuntimeException('cannot open maildir', 0, $error);
        }
        $this->getMaildirFiles($dh, $dirname . '/cur/');
        closedir($dh);

        ErrorHandler::start(E_WARNING);
        $dh    = opendir($dirname . '/new/');
        $error = ErrorHandler::stop();
        if (! $dh) {
            throw new Exception\RuntimeException('cannot read recent mails in maildir', 0, $error);
        }

        $this->getMaildirFiles($dh, $dirname . '/new/', [Mail\Storage::FLAG_RECENT]);
        closedir($dh);
    }

    /**
     * find all files in opened dir handle and add to maildir files
     *
     * @param resource $dh            dir handle used for search
     * @param string   $dirname       dirname of dir in $dh
     * @param array    $defaultFlags default flags for given dir
     */
    protected function getMaildirFiles($dh, $dirname, $defaultFlags = [])
    {
        while (($entry = readdir($dh)) !== false) {
            if ($entry[0] == '.' || ! is_file($dirname . $entry)) {
                continue;
            }

            ErrorHandler::start(E_NOTICE);
            list($uniq, $info) = explode(':', $entry, 2);
            list(, $size) = explode(',', $uniq, 2);
            ErrorHandler::stop();
            if ($size && $size[0] == 'S' && $size[1] == '=') {
                $size = substr($size, 2);
            }
            if (! ctype_digit($size)) {
                $size = null;
            }

            ErrorHandler::start(E_NOTICE);
            list($version, $flags) = explode(',', $info, 2);
            ErrorHandler::stop();
            if ($version != 2) {
                $flags = '';
            }

            $namedFlags = $defaultFlags;
            $length = strlen($flags);
            for ($i = 0; $i < $length; ++$i) {
                $flag = $flags[$i];
                $namedFlags[$flag] = static::$knownFlags[$flag] ?? $flag;
            }

            $data = [
                'uniq'       => $uniq,
                'flags'      => $namedFlags,
                'flaglookup' => array_flip($namedFlags),
                'filename'   => $dirname . $entry,
            ];
            if ($size !== null) {
                $data['size'] = (int) $size;
            }
            $this->files[] = $data;
        }
        \usort($this->files, function ($a, $b) {
            return \strcmp($a['filename'], $b['filename']);
        });
    }

    /**
     * Close resource for mail lib. If you need to control, when the resource
     * is closed. Otherwise the destructor would call this.
     *
     */
    public function close()
    {
        $this->files = [];
    }

    /**
     * Waste some CPU cycles doing nothing.
     *
     * @return bool always return true
     */
    public function noop()
    {
        return true;
    }

    /**
     * stub for not supported message deletion
     *
     * @param $id
     * @throws Exception\RuntimeException
     */
    public function removeMessage($id)
    {
        throw new Exception\RuntimeException('maildir is (currently) read-only');
    }

    /**
     * get unique id for one or all messages
     *
     * if storage does not support unique ids it's the same as the message number
     *
     * @param int|null $id message number
     * @return array|string message number for given message or all messages as array
     */
    public function getUniqueId($id = null)
    {
        if ($id) {
            return $this->getFileData($id, 'uniq');
        }

        $ids = [];
        foreach ($this->files as $num => $file) {
            $ids[$num + 1] = $file['uniq'];
        }
        return $ids;
    }

    /**
     * get a message number from a unique id
     *
     * I.e. if you have a webmailer that supports deleting messages you should use unique ids
     * as parameter and use this method to translate it to message number right before calling removeMessage()
     *
     * @param string $id unique id
     * @throws Exception\InvalidArgumentException
     * @return int message number
     */
    public function getNumberByUniqueId($id)
    {
        foreach ($this->files as $num => $file) {
            if ($file['uniq'] == $id) {
                return $num + 1;
            }
        }

        throw new Exception\InvalidArgumentException('unique id not found');
    }
}
laminas-mail/src/Storage/Exception/ExceptionInterface.php000064400000000671147361032560017544 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-mail for the canonical source repository
 * @copyright https://github.com/laminas/laminas-mail/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-mail/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Mail\Storage\Exception;

use Laminas\Mail\Exception\ExceptionInterface as MailException;

interface ExceptionInterface extends MailException
{
}
laminas-mail/src/Storage/Exception/InvalidArgumentException.php000064400000000773147361032560020740 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-mail for the canonical source repository
 * @copyright https://github.com/laminas/laminas-mail/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-mail/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Mail\Storage\Exception;

use Laminas\Mail\Exception;

/**
 * Exception for Laminas\Mail component.
 */
class InvalidArgumentException extends Exception\InvalidArgumentException implements ExceptionInterface
{
}
laminas-mail/src/Storage/Exception/OutOfBoundsException.php000064400000000763147361032560020055 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-mail for the canonical source repository
 * @copyright https://github.com/laminas/laminas-mail/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-mail/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Mail\Storage\Exception;

use Laminas\Mail\Exception;

/**
 * Exception for Laminas\Mail component.
 */
class OutOfBoundsException extends Exception\OutOfBoundsException implements ExceptionInterface
{
}
laminas-mail/src/Storage/Exception/RuntimeException.php000064400000000753147361032560017270 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-mail for the canonical source repository
 * @copyright https://github.com/laminas/laminas-mail/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-mail/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Mail\Storage\Exception;

use Laminas\Mail\Exception;

/**
 * Exception for Laminas\Mail component.
 */
class RuntimeException extends Exception\RuntimeException implements ExceptionInterface
{
}
laminas-mail/src/Storage/AbstractStorage.php000064400000017562147361032560015126 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-mail for the canonical source repository
 * @copyright https://github.com/laminas/laminas-mail/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-mail/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Mail\Storage;

use ArrayAccess;
use Countable;
use SeekableIterator;

abstract class AbstractStorage implements
    ArrayAccess,
    Countable,
    SeekableIterator
{
    /**
     * class capabilities with default values
     * @var array
     */
    protected $has = [
        'uniqueid'  => true,
        'delete'    => false,
        'create'    => false,
        'top'       => false,
        'fetchPart' => true,
        'flags'     => false,
    ];

    /**
     * current iteration position
     * @var int
     */
    protected $iterationPos = 0;

    /**
     * maximum iteration position (= message count)
     * @var null|int
     */
    protected $iterationMax = null;

    /**
     * used message class, change it in an extended class to extend the returned message class
     * @var string
     */
    protected $messageClass = Message::class;

    /**
     * Getter for has-properties. The standard has properties
     * are: hasFolder, hasUniqueid, hasDelete, hasCreate, hasTop
     *
     * The valid values for the has-properties are:
     *   - true if a feature is supported
     *   - false if a feature is not supported
     *   - null is it's not yet known or it can't be know if a feature is supported
     *
     * @param  string $var  property name
     * @throws Exception\InvalidArgumentException
     * @return bool         supported or not
     */
    public function __get($var)
    {
        if (strpos($var, 'has') === 0) {
            $var = strtolower(substr($var, 3));
            return isset($this->has[$var]) ? $this->has[$var] : null;
        }

        throw new Exception\InvalidArgumentException($var . ' not found');
    }

    /**
     * Get a full list of features supported by the specific mail lib and the server
     *
     * @return array list of features as array(feature_name => true|false[|null])
     */
    public function getCapabilities()
    {
        return $this->has;
    }

    /**
     * Count messages messages in current box/folder
     *
     * @return int number of messages
     * @throws Exception\ExceptionInterface
     */
    abstract public function countMessages();

    /**
     * Get a list of messages with number and size
     *
     * @param  int $id  number of message
     * @return int|array size of given message of list with all messages as array(num => size)
     */
    abstract public function getSize($id = 0);

    /**
     * Get a message with headers and body
     *
     * @param  $id int number of message
     * @return Message
     */
    abstract public function getMessage($id);

    /**
     * Get raw header of message or part
     *
     * @param  int               $id       number of message
     * @param  null|array|string $part     path to part or null for message header
     * @param  int               $topLines include this many lines with header (after an empty line)
     * @return string raw header
     */
    abstract public function getRawHeader($id, $part = null, $topLines = 0);

    /**
     * Get raw content of message or part
     *
     * @param  int               $id   number of message
     * @param  null|array|string $part path to part or null for message content
     * @return string raw content
     */
    abstract public function getRawContent($id, $part = null);

    /**
     * Create instance with parameters
     *
     * @param  array $params mail reader specific parameters
     * @throws Exception\ExceptionInterface
     */
    abstract public function __construct($params);

    /**
     * Destructor calls close() and therefore closes the resource.
     */
    public function __destruct()
    {
        $this->close();
    }

    /**
     * Close resource for mail lib. If you need to control, when the resource
     * is closed. Otherwise the destructor would call this.
     */
    abstract public function close();

    /**
     * Keep the resource alive.
     */
    abstract public function noop();

    /**
     * delete a message from current box/folder
     *
     * @param $id
     */
    abstract public function removeMessage($id);

    /**
     * get unique id for one or all messages
     *
     * if storage does not support unique ids it's the same as the message number
     *
     * @param int|null $id message number
     * @return array|string message number for given message or all messages as array
     * @throws Exception\ExceptionInterface
     */
    abstract public function getUniqueId($id = null);

    /**
     * get a message number from a unique id
     *
     * I.e. if you have a webmailer that supports deleting messages you should use unique ids
     * as parameter and use this method to translate it to message number right before calling removeMessage()
     *
     * @param string $id unique id
     * @return int message number
     * @throws Exception\ExceptionInterface
     */
    abstract public function getNumberByUniqueId($id);

    // interface implementations follows

    /**
     * Countable::count()
     *
     * @return   int
     */
    public function count()
    {
        return $this->countMessages();
    }

    /**
     * ArrayAccess::offsetExists()
     *
     * @param  int  $id
     * @return bool
     */
    public function offsetExists($id)
    {
        try {
            if ($this->getMessage($id)) {
                return true;
            }
        } catch (Exception\ExceptionInterface $e) {
        }

        return false;
    }

    /**
     * ArrayAccess::offsetGet()
     *
     * @param    int $id
     * @return   \Laminas\Mail\Storage\Message message object
     */
    public function offsetGet($id)
    {
        return $this->getMessage($id);
    }

    /**
     * ArrayAccess::offsetSet()
     *
     * @param mixed $id
     * @param mixed $value
     * @throws Exception\RuntimeException
     */
    public function offsetSet($id, $value)
    {
        throw new Exception\RuntimeException('cannot write mail messages via array access');
    }

    /**
     * ArrayAccess::offsetUnset()
     *
     * @param    int   $id
     * @return   bool success
     */
    public function offsetUnset($id)
    {
        return $this->removeMessage($id);
    }

    /**
     * Iterator::rewind()
     *
     * Rewind always gets the new count from the storage. Thus if you use
     * the interfaces and your scripts take long you should use reset()
     * from time to time.
     */
    public function rewind()
    {
        $this->iterationMax = $this->countMessages();
        $this->iterationPos = 1;
    }

    /**
     * Iterator::current()
     *
     * @return Message current message
     */
    public function current()
    {
        return $this->getMessage($this->iterationPos);
    }

    /**
     * Iterator::key()
     *
     * @return   int id of current position
     */
    public function key()
    {
        return $this->iterationPos;
    }

    /**
     * Iterator::next()
     */
    public function next()
    {
        ++$this->iterationPos;
    }

    /**
     * Iterator::valid()
     *
     * @return bool
     */
    public function valid()
    {
        if ($this->iterationMax === null) {
            $this->iterationMax = $this->countMessages();
        }
        return $this->iterationPos && $this->iterationPos <= $this->iterationMax;
    }

    /**
     * SeekableIterator::seek()
     *
     * @param  int $pos
     * @throws Exception\OutOfBoundsException
     */
    public function seek($pos)
    {
        if ($this->iterationMax === null) {
            $this->iterationMax = $this->countMessages();
        }

        if ($pos > $this->iterationMax) {
            throw new Exception\OutOfBoundsException('this position does not exist');
        }
        $this->iterationPos = $pos;
    }
}
laminas-mail/src/Storage/Mbox.php000064400000030147147361032560012735 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-mail for the canonical source repository
 * @copyright https://github.com/laminas/laminas-mail/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-mail/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Mail\Storage;

use Laminas\Config\Config;
use Laminas\Stdlib\ErrorHandler;

class Mbox extends AbstractStorage
{
    /**
     * file handle to mbox file
     * @var null|resource
     */
    protected $fh;

    /**
     * filename of mbox file for __wakeup
     * @var string
     */
    protected $filename;

    /**
     * modification date of mbox file for __wakeup
     * @var int
     */
    protected $filemtime;

    /**
     * start and end position of messages as array('start' => start, 'separator' => headersep, 'end' => end)
     * @var array
     */
    protected $positions;

    /**
     * used message class, change it in an extended class to extend the returned message class
     * @var string
     */
    protected $messageClass = Message\File::class;

    /**
     * end of Line for messages
     *
     * @var string|null
     */
    protected $messageEOL;

    /**
     * Count messages all messages in current box
     *
     * @return int number of messages
     * @throws \Laminas\Mail\Storage\Exception\ExceptionInterface
     */
    public function countMessages()
    {
        return count($this->positions);
    }

    /**
     * Get a list of messages with number and size
     *
     * @param  int|null $id  number of message or null for all messages
     * @return int|array size of given message of list with all messages as array(num => size)
     */
    public function getSize($id = 0)
    {
        if ($id) {
            $pos = $this->positions[$id - 1];
            return $pos['end'] - $pos['start'];
        }

        $result = [];
        foreach ($this->positions as $num => $pos) {
            $result[$num + 1] = $pos['end'] - $pos['start'];
        }

        return $result;
    }

    /**
     * Get positions for mail message or throw exception if id is invalid
     *
     * @param int $id number of message
     * @throws Exception\InvalidArgumentException
     * @return array positions as in positions
     */
    protected function getPos($id)
    {
        if (! isset($this->positions[$id - 1])) {
            throw new Exception\InvalidArgumentException('id does not exist');
        }

        return $this->positions[$id - 1];
    }

    /**
     * Fetch a message
     *
     * @param  int $id number of message
     * @return \Laminas\Mail\Storage\Message\File
     * @throws \Laminas\Mail\Storage\Exception\ExceptionInterface
     */
    public function getMessage($id)
    {
        // TODO that's ugly, would be better to let the message class decide
        if (is_subclass_of($this->messageClass, Message\File::class)
            || strtolower($this->messageClass) === strtolower(Message\File::class)) {
            // TODO top/body lines
            $messagePos = $this->getPos($id);

            $messageClassParams = [
                'file' => $this->fh,
                'startPos' => $messagePos['start'],
                'endPos' => $messagePos['end'],
            ];

            if (isset($this->messageEOL)) {
                $messageClassParams['EOL'] = $this->messageEOL;
            }

            return new $this->messageClass($messageClassParams);
        }

        $bodyLines = 0; // TODO: need a way to change that

        $message = $this->getRawHeader($id);
        // file pointer is after headers now
        if ($bodyLines) {
            $message .= "\n";
            while ($bodyLines-- && ftell($this->fh) < $this->positions[$id - 1]['end']) {
                $message .= fgets($this->fh);
            }
        }

        return new $this->messageClass(['handler' => $this, 'id' => $id, 'headers' => $message]);
    }

    /*
     * Get raw header of message or part
     *
     * @param  int               $id       number of message
     * @param  null|array|string $part     path to part or null for message header
     * @param  int               $topLines include this many lines with header (after an empty line)
     * @return string raw header
     * @throws \Laminas\Mail\Protocol\Exception\ExceptionInterface
     * @throws \Laminas\Mail\Storage\Exception\ExceptionInterface
     */
    public function getRawHeader($id, $part = null, $topLines = 0)
    {
        if ($part !== null) {
            // TODO: implement
            throw new Exception\RuntimeException('not implemented');
        }
        $messagePos = $this->getPos($id);
        // TODO: toplines
        return stream_get_contents($this->fh, $messagePos['separator'] - $messagePos['start'], $messagePos['start']);
    }

    /*
     * Get raw content of message or part
     *
     * @param  int               $id   number of message
     * @param  null|array|string $part path to part or null for message content
     * @return string raw content
     * @throws \Laminas\Mail\Protocol\Exception\ExceptionInterface
     * @throws \Laminas\Mail\Storage\Exception\ExceptionInterface
     */
    public function getRawContent($id, $part = null)
    {
        if ($part !== null) {
            // TODO: implement
            throw new Exception\RuntimeException('not implemented');
        }
        $messagePos = $this->getPos($id);
        return stream_get_contents($this->fh, $messagePos['end'] - $messagePos['separator'], $messagePos['separator']);
    }

    /**
     * Create instance with parameters
     * Supported parameters are:
     *   - filename filename of mbox file
     *
     * @param  $params array|object|Config mail reader specific parameters
     * @throws Exception\InvalidArgumentException
     */
    public function __construct($params)
    {
        if (is_array($params)) {
            $params = (object) $params;
        }

        if (! isset($params->filename)) {
            throw new Exception\InvalidArgumentException('no valid filename given in params');
        }

        if (isset($params->messageEOL)) {
            $this->messageEOL = (string) $params->messageEOL;
        }

        $this->openMboxFile($params->filename);
        $this->has['top']      = true;
        $this->has['uniqueid'] = false;
    }

    /**
     * check if given file is a mbox file
     *
     * if $file is a resource its file pointer is moved after the first line
     *
     * @param  resource|string $file stream resource of name of file
     * @param  bool $fileIsString file is string or resource
     * @return bool file is mbox file
     */
    protected function isMboxFile($file, $fileIsString = true)
    {
        if ($fileIsString) {
            ErrorHandler::start(E_WARNING);
            $file = fopen($file, 'r');
            ErrorHandler::stop();
            if (! $file) {
                return false;
            }
        } else {
            fseek($file, 0);
        }

        $result = false;

        $line = fgets($file) ?: '';
        if (strpos($line, 'From ') === 0) {
            $result = true;
        }

        if ($fileIsString) {
            ErrorHandler::start(E_WARNING);
            fclose($file);
            ErrorHandler::stop();
        }

        return $result;
    }

    /**
     * open given file as current mbox file
     *
     * @param  string $filename filename of mbox file
     * @throws Exception\RuntimeException
     * @throws Exception\InvalidArgumentException
     */
    protected function openMboxFile($filename)
    {
        if ($this->fh) {
            $this->close();
        }

        if (is_dir($filename)) {
            throw new Exception\InvalidArgumentException('file is not a valid mbox file');
        }

        ErrorHandler::start();
        $this->fh = fopen($filename, 'r');
        $error = ErrorHandler::stop();
        if (! $this->fh) {
            throw new Exception\RuntimeException('cannot open mbox file', 0, $error);
        }
        $this->filename = $filename;
        $this->filemtime = filemtime($this->filename);

        if (! $this->isMboxFile($this->fh, false)) {
            ErrorHandler::start(E_WARNING);
            fclose($this->fh);
            $error = ErrorHandler::stop();
            throw new Exception\InvalidArgumentException('file is not a valid mbox format', 0, $error);
        }

        $messagePos = ['start' => ftell($this->fh), 'separator' => 0, 'end' => 0];
        while (($line = fgets($this->fh)) !== false) {
            if (strpos($line, 'From ') === 0) {
                $messagePos['end'] = ftell($this->fh) - strlen($line) - 2; // + newline
                if (! $messagePos['separator']) {
                    $messagePos['separator'] = $messagePos['end'];
                }
                $this->positions[] = $messagePos;
                $messagePos = ['start' => ftell($this->fh), 'separator' => 0, 'end' => 0];
            }
            if (! $messagePos['separator'] && ! trim($line)) {
                $messagePos['separator'] = ftell($this->fh);
            }
        }

        $messagePos['end'] = ftell($this->fh);
        if (! $messagePos['separator']) {
            $messagePos['separator'] = $messagePos['end'];
        }
        $this->positions[] = $messagePos;
    }

    /**
     * Close resource for mail lib. If you need to control, when the resource
     * is closed. Otherwise the destructor would call this.
     *
     */
    public function close()
    {
        if (is_resource($this->fh)) {
            fclose($this->fh);
        }
        $this->positions = [];
    }

    /**
     * Waste some CPU cycles doing nothing.
     *
     * @return bool always return true
     */
    public function noop()
    {
        return true;
    }

    /**
     * stub for not supported message deletion
     *
     * @param $id
     * @throws Exception\RuntimeException
     */
    public function removeMessage($id)
    {
        throw new Exception\RuntimeException('mbox is read-only');
    }

    /**
     * get unique id for one or all messages
     *
     * Mbox does not support unique ids (yet) - it's always the same as the message number.
     * That shouldn't be a problem, because we can't change mbox files. Therefor the message
     * number is save enough.
     *
     * @param int|null $id message number
     * @return array|string message number for given message or all messages as array
     * @throws \Laminas\Mail\Storage\Exception\ExceptionInterface
     */
    public function getUniqueId($id = null)
    {
        if ($id) {
            // check if id exists
            $this->getPos($id);
            return $id;
        }

        $range = range(1, $this->countMessages());
        return array_combine($range, $range);
    }

    /**
     * get a message number from a unique id
     *
     * I.e. if you have a webmailer that supports deleting messages you should use unique ids
     * as parameter and use this method to translate it to message number right before calling removeMessage()
     *
     * @param string $id unique id
     * @return int message number
     * @throws \Laminas\Mail\Storage\Exception\ExceptionInterface
     */
    public function getNumberByUniqueId($id)
    {
        // check if id exists
        $this->getPos($id);
        return $id;
    }

    /**
     * magic method for serialize()
     *
     * with this method you can cache the mbox class
     *
     * @return array name of variables
     */
    public function __sleep()
    {
        return ['filename', 'positions', 'filemtime'];
    }

    /**
     * magic method for unserialize()
     *
     * with this method you can cache the mbox class
     * for cache validation the mtime of the mbox file is used
     *
     * @throws Exception\RuntimeException
     */
    public function __wakeup()
    {
        ErrorHandler::start();
        $filemtime = filemtime($this->filename);
        ErrorHandler::stop();
        if ($this->filemtime != $filemtime) {
            $this->close();
            $this->openMboxFile($this->filename);
        } else {
            ErrorHandler::start();
            $this->fh = fopen($this->filename, 'r');
            $error    = ErrorHandler::stop();
            if (! $this->fh) {
                throw new Exception\RuntimeException('cannot open mbox file', 0, $error);
            }
        }
    }
}
laminas-mail/src/Storage/Writable/WritableInterface.php000064400000005600147361032560017167 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-mail for the canonical source repository
 * @copyright https://github.com/laminas/laminas-mail/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-mail/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Mail\Storage\Writable;

use Laminas\Mail\Message;
use Laminas\Mail\Storage;
use Laminas\Mime;

interface WritableInterface
{
    /**
     * create a new folder
     *
     * This method also creates parent folders if necessary. Some mail storages
     * may restrict, which folder may be used as parent or which chars may be
     * used in the folder name
     *
     * @param string $name global name of folder, local name if $parentFolder
     *     is set.
     * @param string|Storage\Folder $parentFolder parent folder for new folder,
     *     else root folder is parent.
     * @throws Storage\Exception\ExceptionInterface
     */
    public function createFolder($name, $parentFolder = null);

    /**
     * remove a folder
     *
     * @param string|Storage\Folder $name name or instance of folder.
     * @throws Storage\Exception\ExceptionInterface
     */
    public function removeFolder($name);

    /**
     * rename and/or move folder
     *
     * The new name has the same restrictions as in createFolder()
     *
     * @param string|Storage\Folder $oldName name or instance of folder.
     * @param string $newName new global name of folder.
     * @throws Storage\Exception\ExceptionInterface
     */
    public function renameFolder($oldName, $newName);

    /**
     * append a new message to mail storage
     *
     * @param  string|Message|Mime\Message $message message as string or
     *     instance of message class.
     * @param  null|string|Storage\Folder $folder folder for new message, else
     *     current folder is taken.
     * @param  null|array $flags set flags for new message, else a default set
     *     is used.
     * @throws Storage\Exception\ExceptionInterface
     */
    public function appendMessage($message, $folder = null, $flags = null);

    /**
     * copy an existing message
     *
     * @param  int $id number of message
     * @param  string|Storage\Folder $folder name or instance of target folder
     * @throws Storage\Exception\ExceptionInterface
     */
    public function copyMessage($id, $folder);

    /**
     * move an existing message
     *
     * @param  int $id number of message
     * @param  string|Storage\Folder $folder name or instance of target folder
     * @throws Storage\Exception\ExceptionInterface
     */
    public function moveMessage($id, $folder);

    /**
     * set flags for message
     *
     * NOTE: this method can't set the recent flag.
     *
     * @param int $id number of message
     * @param array $flags new flags for message
     * @throws Storage\Exception\ExceptionInterface
     */
    public function setFlags($id, $flags);
}
laminas-mail/src/Storage/Writable/Maildir.php000064400000105051147361032560015157 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-mail for the canonical source repository
 * @copyright https://github.com/laminas/laminas-mail/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-mail/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Mail\Storage\Writable;

use Laminas\Mail\Exception as MailException;
use Laminas\Mail\Storage;
use Laminas\Mail\Storage\Exception as StorageException;
use Laminas\Mail\Storage\Folder;
use Laminas\Stdlib\ErrorHandler;
use RecursiveIteratorIterator;

class Maildir extends Folder\Maildir implements WritableInterface
{
    // TODO: init maildir (+ constructor option create if not found)

    /**
     * use quota and size of quota if given
     *
     * @var bool|int
     */
    protected $quota;

    /**
     * create a new maildir
     *
     * If the given dir is already a valid maildir this will not fail.
     *
     * @param string $dir directory for the new maildir (may already exist)
     * @throws \Laminas\Mail\Storage\Exception\RuntimeException
     * @throws \Laminas\Mail\Storage\Exception\InvalidArgumentException
     */
    public static function initMaildir($dir)
    {
        if (file_exists($dir)) {
            if (! is_dir($dir)) {
                throw new StorageException\InvalidArgumentException('maildir must be a directory if already exists');
            }
        } else {
            ErrorHandler::start();
            $test  = mkdir($dir);
            $error = ErrorHandler::stop();
            if (! $test) {
                $dir = dirname($dir);
                if (! file_exists($dir)) {
                    throw new StorageException\InvalidArgumentException("parent $dir not found", 0, $error);
                } elseif (! is_dir($dir)) {
                    throw new StorageException\InvalidArgumentException("parent $dir not a directory", 0, $error);
                }

                throw new StorageException\RuntimeException('cannot create maildir', 0, $error);
            }
        }

        foreach (['cur', 'tmp', 'new'] as $subdir) {
            ErrorHandler::start();
            $test  = mkdir($dir . DIRECTORY_SEPARATOR . $subdir);
            $error = ErrorHandler::stop();
            if (! $test) {
                // ignore if dir exists (i.e. was already valid maildir or two processes try to create one)
                if (! file_exists($dir . DIRECTORY_SEPARATOR . $subdir)) {
                    throw new StorageException\RuntimeException('could not create subdir ' . $subdir, 0, $error);
                }
            }
        }
    }

    /**
     * Create instance with parameters
     * Additional parameters are (see parent for more):
     *   - create if true a new maildir is create if none exists
     *
     * @param  $params array mail reader specific parameters
     * @throws \Laminas\Mail\Storage\Exception\ExceptionInterface
     */
    public function __construct($params)
    {
        if (is_array($params)) {
            $params = (object) $params;
        }

        if (! empty($params->create)
            && isset($params->dirname)
            && ! file_exists($params->dirname . DIRECTORY_SEPARATOR . 'cur')
        ) {
            self::initMaildir($params->dirname);
        }

        parent::__construct($params);
    }

    /**
     * create a new folder
     *
     * This method also creates parent folders if necessary. Some mail storages may restrict, which folder
     * may be used as parent or which chars may be used in the folder name
     *
     * @param   string                           $name         global name of folder, local name if $parentFolder is set
     * @param   string|\Laminas\Mail\Storage\Folder $parentFolder parent of new folder, else root folder is parent
     * @throws \Laminas\Mail\Storage\Exception\RuntimeException
     * @return  string only used internally (new created maildir)
     */
    public function createFolder($name, $parentFolder = null)
    {
        if ($parentFolder instanceof Folder) {
            $folder = $parentFolder->getGlobalName() . $this->delim . $name;
        } elseif ($parentFolder !== null) {
            $folder = rtrim($parentFolder, $this->delim) . $this->delim . $name;
        } else {
            $folder = $name;
        }

        $folder = trim($folder, $this->delim);

        // first we check if we try to create a folder that does exist
        $exists = null;
        try {
            $exists = $this->getFolders($folder);
        } catch (MailException\ExceptionInterface $e) {
            // ok
        }
        if ($exists) {
            throw new StorageException\RuntimeException('folder already exists');
        }

        if (strpos($folder, $this->delim . $this->delim) !== false) {
            throw new StorageException\RuntimeException('invalid name - folder parts may not be empty');
        }

        if (strpos($folder, 'INBOX' . $this->delim) === 0) {
            $folder = substr($folder, 6);
        }

        $fulldir = $this->rootdir . '.' . $folder;

        // check if we got tricked and would create a dir outside of the rootdir or not as direct child
        if (strpos($folder, DIRECTORY_SEPARATOR) !== false || strpos($folder, '/') !== false
            || dirname($fulldir) . DIRECTORY_SEPARATOR != $this->rootdir
        ) {
            throw new StorageException\RuntimeException('invalid name - no directory separator allowed in folder name');
        }

        // has a parent folder?
        $parent = null;
        if (strpos($folder, $this->delim)) {
            // let's see if the parent folder exists
            $parent = substr($folder, 0, strrpos($folder, $this->delim));
            try {
                $this->getFolders($parent);
            } catch (MailException\ExceptionInterface $e) {
                // does not - create parent folder
                $this->createFolder($parent);
            }
        }

        ErrorHandler::start();
        if (! mkdir($fulldir) || ! mkdir($fulldir . DIRECTORY_SEPARATOR . 'cur')) {
            $error = ErrorHandler::stop();
            throw new StorageException\RuntimeException(
                'error while creating new folder, may be created incompletely',
                0,
                $error
            );
        }
        ErrorHandler::stop();

        mkdir($fulldir . DIRECTORY_SEPARATOR . 'new');
        mkdir($fulldir . DIRECTORY_SEPARATOR . 'tmp');

        $localName                             = $parent ? substr($folder, strlen($parent) + 1) : $folder;
        $this->getFolders($parent)->$localName = new Folder($localName, $folder, true);

        return $fulldir;
    }

    /**
     * remove a folder
     *
     * @param  string|Folder $name      name or instance of folder
     * @throws \Laminas\Mail\Storage\Exception\RuntimeException
     */
    public function removeFolder($name)
    {
        // TODO: This could fail in the middle of the task, which is not optimal.
        // But there is no defined standard way to mark a folder as removed and there is no atomar fs-op
        // to remove a directory. Also moving the folder to a/the trash folder is not possible, as
        // all parent folders must be created. What we could do is add a dash to the front of the
        // directory name and it should be ignored as long as other processes obey the standard.

        if ($name instanceof Folder) {
            $name = $name->getGlobalName();
        }

        $name = trim($name, $this->delim);
        if (strpos($name, 'INBOX' . $this->delim) === 0) {
            $name = substr($name, 6);
        }

        // check if folder exists and has no children
        if (! $this->getFolders($name)->isLeaf()) {
            throw new StorageException\RuntimeException('delete children first');
        }

        if ($name == 'INBOX' || $name == DIRECTORY_SEPARATOR || $name == '/') {
            throw new StorageException\RuntimeException('wont delete INBOX');
        }

        if ($name == $this->getCurrentFolder()) {
            throw new StorageException\RuntimeException('wont delete selected folder');
        }

        foreach (['tmp', 'new', 'cur', '.'] as $subdir) {
            $dir = $this->rootdir . '.' . $name . DIRECTORY_SEPARATOR . $subdir;
            if (! file_exists($dir)) {
                continue;
            }
            $dh = opendir($dir);
            if (! $dh) {
                throw new StorageException\RuntimeException("error opening $subdir");
            }
            while (($entry = readdir($dh)) !== false) {
                if ($entry == '.' || $entry == '..') {
                    continue;
                }
                if (! unlink($dir . DIRECTORY_SEPARATOR . $entry)) {
                    throw new StorageException\RuntimeException("error cleaning $subdir");
                }
            }
            closedir($dh);
            if ($subdir !== '.') {
                if (! rmdir($dir)) {
                    throw new StorageException\RuntimeException("error removing $subdir");
                }
            }
        }

        if (! rmdir($this->rootdir . '.' . $name)) {
            // at least we should try to make it a valid maildir again
            mkdir($this->rootdir . '.' . $name . DIRECTORY_SEPARATOR . 'cur');
            throw new StorageException\RuntimeException("error removing maindir");
        }

        $parent    = strpos($name, $this->delim) ? substr($name, 0, strrpos($name, $this->delim)) : null;
        $localName = $parent ? substr($name, strlen($parent) + 1) : $name;
        unset($this->getFolders($parent)->$localName);
    }

    /**
     * rename and/or move folder
     *
     * The new name has the same restrictions as in createFolder()
     *
     * @param  string|\Laminas\Mail\Storage\Folder $oldName name or instance of folder
     * @param  string                           $newName new global name of folder
     * @throws \Laminas\Mail\Storage\Exception\RuntimeException
     */
    public function renameFolder($oldName, $newName)
    {
        // TODO: This is also not atomar and has similar problems as removeFolder()

        if ($oldName instanceof Folder) {
            $oldName = $oldName->getGlobalName();
        }

        $oldName = trim($oldName, $this->delim);
        if (strpos($oldName, 'INBOX' . $this->delim) === 0) {
            $oldName = substr($oldName, 6);
        }

        $newName = trim($newName, $this->delim);
        if (strpos($newName, 'INBOX' . $this->delim) === 0) {
            $newName = substr($newName, 6);
        }

        if (strpos($newName, $oldName . $this->delim) === 0) {
            throw new StorageException\RuntimeException('new folder cannot be a child of old folder');
        }

        // check if folder exists and has no children
        $folder = $this->getFolders($oldName);

        if ($oldName == 'INBOX' || $oldName == DIRECTORY_SEPARATOR || $oldName == '/') {
            throw new StorageException\RuntimeException('wont rename INBOX');
        }

        if ($oldName == $this->getCurrentFolder()) {
            throw new StorageException\RuntimeException('wont rename selected folder');
        }

        $newdir = $this->createFolder($newName);

        if (! $folder->isLeaf()) {
            foreach ($folder as $k => $v) {
                $this->renameFolder($v->getGlobalName(), $newName . $this->delim . $k);
            }
        }

        $olddir = $this->rootdir . '.' . $folder;
        foreach (['tmp', 'new', 'cur'] as $subdir) {
            $subdir = DIRECTORY_SEPARATOR . $subdir;
            if (! file_exists($olddir . $subdir)) {
                continue;
            }
            // using copy or moving files would be even better - but also much slower
            if (! rename($olddir . $subdir, $newdir . $subdir)) {
                throw new StorageException\RuntimeException('error while moving ' . $subdir);
            }
        }
        // create a dummy if removing fails - otherwise we can't read it next time
        mkdir($olddir . DIRECTORY_SEPARATOR . 'cur');
        $this->removeFolder($oldName);
    }

    /**
     * create a uniqueid for maildir filename
     *
     * This is nearly the format defined in the maildir standard. The microtime() call should already
     * create a uniqueid, the pid is for multicore/-cpu machine that manage to call this function at the
     * exact same time, and uname() gives us the hostname for multiple machines accessing the same storage.
     *
     * If someone disables posix we create a random number of the same size, so this method should also
     * work on Windows - if you manage to get maildir working on Windows.
     * Microtime could also be disabled, although I've never seen it.
     *
     * @return string new uniqueid
     */
    protected function createUniqueId()
    {
        $id = '';
        $id .= microtime(true);
        $id .= '.' . getmypid();
        $id .= '.' . php_uname('n');

        return $id;
    }

    /**
     * open a temporary maildir file
     *
     * makes sure tmp/ exists and create a file with a unique name
     * you should close the returned filehandle!
     *
     * @param   string $folder name of current folder without leading .
     * @throws \Laminas\Mail\Storage\Exception\RuntimeException
     * @return  array array('dirname' => dir of maildir folder, 'uniq' => unique id, 'filename' => name of create file
     *                     'handle'  => file opened for writing)
     */
    protected function createTmpFile($folder = 'INBOX')
    {
        if ($folder == 'INBOX') {
            $tmpdir = $this->rootdir . DIRECTORY_SEPARATOR . 'tmp' . DIRECTORY_SEPARATOR;
        } else {
            $tmpdir = $this->rootdir . '.' . $folder . DIRECTORY_SEPARATOR . 'tmp' . DIRECTORY_SEPARATOR;
        }
        if (! file_exists($tmpdir)) {
            if (! mkdir($tmpdir)) {
                throw new StorageException\RuntimeException('problems creating tmp dir');
            }
        }

        // we should retry to create a unique id if a file with the same name exists
        // to avoid a script timeout we only wait 1 second (instead of 2) and stop
        // after a defined retry count
        // if you change this variable take into account that it can take up to $maxTries seconds
        // normally we should have a valid unique name after the first try, we're just following the "standard" here
        $maxTries = 5;
        for ($i = 0; $i < $maxTries; ++$i) {
            $uniq = $this->createUniqueId();
            if (! file_exists($tmpdir . $uniq)) {
                // here is the race condition! - as defined in the standard
                // to avoid having a long time between stat()ing the file and creating it we're opening it here
                // to mark the filename as taken
                $fh = fopen($tmpdir . $uniq, 'w');
                if (! $fh) {
                    throw new StorageException\RuntimeException('could not open temp file');
                }
                break;
            }
            sleep(1);
        }

        if (! $fh) {
            throw new StorageException\RuntimeException(
                "tried {$maxTries} unique ids for a temp file, but all were taken - giving up"
            );
        }

        return [
            'dirname' => $this->rootdir . '.' . $folder,
            'uniq' => $uniq,
            'filename' => $tmpdir . $uniq,
            'handle' => $fh,
        ];
    }

    /**
     * create an info string for filenames with given flags
     *
     * @param array $flags wanted flags, with the reference you'll get the set
     *     flags with correct key (= char for flag)
     * @return string info string for version 2 filenames including the leading colon
     * @throws StorageException\InvalidArgumentException
     */
    protected function getInfoString(&$flags)
    {
        // accessing keys is easier, faster and it removes duplicated flags
        $wantedFlags = array_flip($flags);
        if (isset($wantedFlags[Storage::FLAG_RECENT])) {
            throw new StorageException\InvalidArgumentException('recent flag may not be set');
        }

        $info  = ':2,';
        $flags = [];
        foreach (Storage\Maildir::$knownFlags as $char => $flag) {
            if (! isset($wantedFlags[$flag])) {
                continue;
            }
            $info .= $char;
            $flags[$char] = $flag;
            unset($wantedFlags[$flag]);
        }

        if (! empty($wantedFlags)) {
            $wantedFlags = implode(', ', array_keys($wantedFlags));
            throw new StorageException\InvalidArgumentException('unknown flag(s): ' . $wantedFlags);
        }

        return $info;
    }

    /**
     * append a new message to mail storage
     *
     * @param string|resource $message message as string or stream resource.
     * @param null|string|Folder $folder folder for new message, else current
     *     folder is taken.
     * @param null|array $flags set flags for new message, else a default set
     *     is used.
     * @param bool $recent handle this mail as if recent flag has been set,
     *     should only be used in delivery.
     * @throws StorageException\RuntimeException
     */
    public function appendMessage($message, $folder = null, $flags = null, $recent = false)
    {
        if ($this->quota && $this->checkQuota()) {
            throw new StorageException\RuntimeException('storage is over quota!');
        }

        if ($folder === null) {
            $folder = $this->currentFolder;
        }

        if (! ($folder instanceof Folder)) {
            $folder = $this->getFolders($folder);
        }

        if ($flags === null) {
            $flags = [Storage::FLAG_SEEN];
        }
        $info     = $this->getInfoString($flags);
        $tempFile = $this->createTmpFile($folder->getGlobalName());

        // TODO: handle class instances for $message
        if (is_resource($message) && get_resource_type($message) == 'stream') {
            stream_copy_to_stream($message, $tempFile['handle']);
        } else {
            fwrite($tempFile['handle'], $message);
        }
        fclose($tempFile['handle']);

        // we're adding the size to the filename for maildir++
        $size = filesize($tempFile['filename']);
        if ($size !== false) {
            $info = ',S=' . $size . $info;
        }
        $newFilename = $tempFile['dirname'] . DIRECTORY_SEPARATOR;
        $newFilename .= $recent ? 'new' : 'cur';
        $newFilename .= DIRECTORY_SEPARATOR . $tempFile['uniq'] . $info;

        // we're throwing any exception after removing our temp file and saving it to this variable instead
        $exception = null;

        if (! link($tempFile['filename'], $newFilename)) {
            $exception = new StorageException\RuntimeException('cannot link message file to final dir');
        }

        ErrorHandler::start(E_WARNING);
        unlink($tempFile['filename']);
        ErrorHandler::stop();

        if ($exception) {
            throw $exception;
        }

        $this->files[] = [
            'uniq' => $tempFile['uniq'],
            'flags' => $flags,
            'filename' => $newFilename,
        ];
        if ($this->quota) {
            $this->addQuotaEntry((int) $size, 1);
        }
    }

    /**
     * copy an existing message
     *
     * @param  int                              $id     number of message
     * @param  string|\Laminas\Mail\Storage\Folder $folder name or instance of targer folder
     * @throws \Laminas\Mail\Storage\Exception\RuntimeException
     */
    public function copyMessage($id, $folder)
    {
        if ($this->quota && $this->checkQuota()) {
            throw new StorageException\RuntimeException('storage is over quota!');
        }

        if (! ($folder instanceof Folder)) {
            $folder = $this->getFolders($folder);
        }

        $filedata = $this->getFileData($id);
        $oldFile  = $filedata['filename'];
        $flags    = $filedata['flags'];

        // copied message can't be recent
        while (($key = array_search(Storage::FLAG_RECENT, $flags)) !== false) {
            unset($flags[$key]);
        }
        $info = $this->getInfoString($flags);

        // we're creating the copy as temp file before moving to cur/
        $tempFile = $this->createTmpFile($folder->getGlobalName());
        // we don't write directly to the file
        fclose($tempFile['handle']);

        // we're adding the size to the filename for maildir++
        $size = filesize($oldFile);
        if ($size !== false) {
            $info = ',S=' . $size . $info;
        }

        $newFile = $tempFile['dirname'] . DIRECTORY_SEPARATOR . 'cur' . DIRECTORY_SEPARATOR . $tempFile['uniq'] . $info;

        // we're throwing any exception after removing our temp file and saving it to this variable instead
        $exception = null;

        if (! copy($oldFile, $tempFile['filename'])) {
            $exception = new StorageException\RuntimeException('cannot copy message file');
        } elseif (! link($tempFile['filename'], $newFile)) {
            $exception = new StorageException\RuntimeException('cannot link message file to final dir');
        }

        ErrorHandler::start(E_WARNING);
        unlink($tempFile['filename']);
        ErrorHandler::stop();

        if ($exception) {
            throw $exception;
        }

        if ($folder->getGlobalName() == $this->currentFolder
            || ($this->currentFolder == 'INBOX' && $folder->getGlobalName() == '/')
        ) {
            $this->files[] = [
                'uniq' => $tempFile['uniq'],
                'flags' => $flags,
                'filename' => $newFile,
            ];
        }

        if ($this->quota) {
            $this->addQuotaEntry((int) $size, 1);
        }
    }

    /**
     * move an existing message
     *
     * @param  int                              $id     number of message
     * @param  string|\Laminas\Mail\Storage\Folder $folder name or instance of targer folder
     * @throws \Laminas\Mail\Storage\Exception\RuntimeException
     */
    public function moveMessage($id, $folder)
    {
        if (! ($folder instanceof Folder)) {
            $folder = $this->getFolders($folder);
        }

        if ($folder->getGlobalName() == $this->currentFolder
            || ($this->currentFolder == 'INBOX' && $folder->getGlobalName() == '/')
        ) {
            throw new StorageException\RuntimeException('target is current folder');
        }

        $filedata = $this->getFileData($id);
        $oldFile  = $filedata['filename'];
        $flags    = $filedata['flags'];

        // moved message can't be recent
        while (($key = array_search(Storage::FLAG_RECENT, $flags)) !== false) {
            unset($flags[$key]);
        }
        $info = $this->getInfoString($flags);

        // reserving a new name
        $tempFile = $this->createTmpFile($folder->getGlobalName());
        fclose($tempFile['handle']);

        // we're adding the size to the filename for maildir++
        $size = filesize($oldFile);
        if ($size !== false) {
            $info = ',S=' . $size . $info;
        }

        $newFile = $tempFile['dirname'] . DIRECTORY_SEPARATOR . 'cur' . DIRECTORY_SEPARATOR . $tempFile['uniq'] . $info;

        // we're throwing any exception after removing our temp file and saving it to this variable instead
        $exception = null;

        if (! rename($oldFile, $newFile)) {
            $exception = new StorageException\RuntimeException('cannot move message file');
        }

        ErrorHandler::start(E_WARNING);
        unlink($tempFile['filename']);
        ErrorHandler::stop();

        if ($exception) {
            throw $exception;
        }

        unset($this->files[$id - 1]);
        // remove the gap
        $this->files = array_values($this->files);
    }

    /**
     * set flags for message
     *
     * NOTE: this method can't set the recent flag.
     *
     * @param   int   $id    number of message
     * @param   array $flags new flags for message
     * @throws \Laminas\Mail\Storage\Exception\RuntimeException
     */
    public function setFlags($id, $flags)
    {
        $info     = $this->getInfoString($flags);
        $filedata = $this->getFileData($id);

        // NOTE: double dirname to make sure we always move to cur. if recent
        // flag has been set (message is in new) it will be moved to cur.
        $newFilename = dirname($filedata['filename'], 2)
            . DIRECTORY_SEPARATOR
            . 'cur'
            . DIRECTORY_SEPARATOR
            . "$filedata[uniq]$info";

        ErrorHandler::start();
        $test  = rename($filedata['filename'], $newFilename);
        $error = ErrorHandler::stop();
        if (! $test) {
            throw new StorageException\RuntimeException('cannot rename file', 0, $error);
        }

        $filedata['flags']    = $flags;
        $filedata['filename'] = $newFilename;

        $this->files[$id - 1] = $filedata;
    }

    /**
     * stub for not supported message deletion
     *
     * @param $id
     * @throws \Laminas\Mail\Storage\Exception\RuntimeException
     */
    public function removeMessage($id)
    {
        $filename = $this->getFileData($id, 'filename');

        if ($this->quota) {
            $size = filesize($filename);
        }

        ErrorHandler::start();
        $test  = unlink($filename);
        $error = ErrorHandler::stop();
        if (! $test) {
            throw new StorageException\RuntimeException('cannot remove message', 0, $error);
        }
        unset($this->files[$id - 1]);
        // remove the gap
        $this->files = array_values($this->files);
        if ($this->quota) {
            $this->addQuotaEntry(0 - (int) $size, -1);
        }
    }

    /**
     * enable/disable quota and set a quota value if wanted or needed
     *
     * You can enable/disable quota with true/false. If you don't have
     * a MDA or want to enforce a quota value you can also set this value
     * here. Use array('size' => SIZE_QUOTA, 'count' => MAX_MESSAGE) do
     * define your quota. Order of these fields does matter!
     *
     * @param bool|array $value new quota value
     */
    public function setQuota($value)
    {
        $this->quota = $value;
    }

    /**
     * get currently set quota
     *
     * @see \Laminas\Mail\Storage\Writable\Maildir::setQuota()
     * @param bool $fromStorage
     * @throws \Laminas\Mail\Storage\Exception\RuntimeException
     * @return bool|array
     */
    public function getQuota($fromStorage = false)
    {
        if ($fromStorage) {
            ErrorHandler::start(E_WARNING);
            $fh    = fopen($this->rootdir . 'maildirsize', 'r');
            $error = ErrorHandler::stop();
            if (! $fh) {
                throw new StorageException\RuntimeException('cannot open maildirsize', 0, $error);
            }
            $definition = fgets($fh);
            fclose($fh);
            $definition = explode(',', trim($definition));
            $quota      = [];
            foreach ($definition as $member) {
                $key = $member[strlen($member) - 1];
                if ($key == 'S' || $key == 'C') {
                    $key = $key == 'C' ? 'count' : 'size';
                }
                $quota[$key] = substr($member, 0, -1);
            }
            return $quota;
        }

        return $this->quota;
    }

    /**
     * @see http://www.inter7.com/courierimap/README.maildirquota.html "Calculating maildirsize"
     * @throws \Laminas\Mail\Storage\Exception\RuntimeException
     * @return array
     */
    protected function calculateMaildirsize()
    {
        $timestamps = [];
        $messages   = 0;
        $totalSize  = 0;

        if (is_array($this->quota)) {
            $quota = $this->quota;
        } else {
            try {
                $quota = $this->getQuota(true);
            } catch (StorageException\ExceptionInterface $e) {
                throw new StorageException\RuntimeException('no quota definition found', 0, $e);
            }
        }

        $folders = new RecursiveIteratorIterator($this->getFolders(), RecursiveIteratorIterator::SELF_FIRST);
        foreach ($folders as $folder) {
            $subdir = $folder->getGlobalName();
            if ($subdir == 'INBOX') {
                $subdir = '';
            } else {
                $subdir = '.' . $subdir;
            }
            if ($subdir == 'Trash') {
                continue;
            }

            foreach (['cur', 'new'] as $subsubdir) {
                $dirname = $this->rootdir . $subdir . DIRECTORY_SEPARATOR . $subsubdir . DIRECTORY_SEPARATOR;
                if (! file_exists($dirname)) {
                    continue;
                }
                // NOTE: we are using mtime instead of "the latest timestamp". The latest would be atime
                // and as we are accessing the directory it would make the whole calculation useless.
                $timestamps[$dirname] = filemtime($dirname);

                $dh = opendir($dirname);
                // NOTE: Should have been checked in constructor. Not throwing an exception here, quotas will
                // therefore not be fully enforced, but next request will fail anyway, if problem persists.
                if (! $dh) {
                    continue;
                }

                while (($entry = readdir()) !== false) {
                    if ($entry[0] == '.' || ! is_file($dirname . $entry)) {
                        continue;
                    }

                    if (strpos($entry, ',S=')) {
                        strtok($entry, '=');
                        $filesize = strtok(':');
                        if (is_numeric($filesize)) {
                            $totalSize += $filesize;
                            ++$messages;
                            continue;
                        }
                    }
                    $size = filesize($dirname . $entry);
                    if ($size === false) {
                        // ignore, as we assume file got removed
                        continue;
                    }
                    $totalSize += $size;
                    ++$messages;
                }
            }
        }

        $tmp        = $this->createTmpFile();
        $fh         = $tmp['handle'];
        $definition = [];
        foreach ($quota as $type => $value) {
            if ($type == 'size' || $type == 'count') {
                $type = $type == 'count' ? 'C' : 'S';
            }
            $definition[] = $value . $type;
        }
        $definition = implode(',', $definition);
        fwrite($fh, "$definition\n");
        fwrite($fh, "$totalSize $messages\n");
        fclose($fh);
        rename($tmp['filename'], $this->rootdir . 'maildirsize');
        foreach ($timestamps as $dir => $timestamp) {
            if ($timestamp < filemtime($dir)) {
                unlink($this->rootdir . 'maildirsize');
                break;
            }
        }

        return [
            'size' => $totalSize,
            'count' => $messages,
            'quota' => $quota,
        ];
    }

    /**
     * @see http://www.inter7.com/courierimap/README.maildirquota.html "Calculating the quota for a Maildir++"
     * @param bool $forceRecalc
     * @return array
     */
    protected function calculateQuota($forceRecalc = false)
    {
        $fh          = null;
        $totalSize   = 0;
        $messages    = 0;
        $maildirsize = '';
        if (! $forceRecalc
            && file_exists($this->rootdir . 'maildirsize')
            && filesize($this->rootdir . 'maildirsize') < 5120
        ) {
            $fh = fopen($this->rootdir . 'maildirsize', 'r');
        }
        if ($fh) {
            $maildirsize = fread($fh, 5120);
            if (strlen($maildirsize) >= 5120) {
                fclose($fh);
                $fh          = null;
                $maildirsize = '';
            }
        }
        if (! $fh) {
            $result     = $this->calculateMaildirsize();
            $totalSize = $result['size'];
            $messages   = $result['count'];
            $quota      = $result['quota'];
        } else {
            $maildirsize = explode("\n", $maildirsize);
            if (is_array($this->quota)) {
                $quota = $this->quota;
            } else {
                $definition = explode(',', $maildirsize[0]);
                $quota      = [];
                foreach ($definition as $member) {
                    $key = $member[strlen($member) - 1];
                    if ($key == 'S' || $key == 'C') {
                        $key = $key == 'C' ? 'count' : 'size';
                    }
                    $quota[$key] = substr($member, 0, -1);
                }
            }
            unset($maildirsize[0]);
            foreach ($maildirsize as $line) {
                list($size, $count) = explode(' ', trim($line));
                $totalSize += $size;
                $messages += $count;
            }
        }

        $overQuota = false;
        $overQuota = $overQuota || (isset($quota['size']) && $totalSize > $quota['size']);
        $overQuota = $overQuota || (isset($quota['count']) && $messages > $quota['count']);
        // NOTE: $maildirsize equals false if it wasn't set (AKA we recalculated) or it's only
        // one line, because $maildirsize[0] gets unsetted.
        // Also we're using local time to calculate the 15 minute offset. Touching a file just for known the
        // local time of the file storage isn't worth the hassle.
        if ($overQuota && ($maildirsize || filemtime($this->rootdir . 'maildirsize') > time() - 900)) {
            $result     = $this->calculateMaildirsize();
            $totalSize  = $result['size'];
            $messages   = $result['count'];
            $quota      = $result['quota'];
            $overQuota = false;
            $overQuota = $overQuota || (isset($quota['size']) && $totalSize > $quota['size']);
            $overQuota = $overQuota || (isset($quota['count']) && $messages > $quota['count']);
        }

        if ($fh) {
            // TODO is there a safe way to keep the handle open for writing?
            fclose($fh);
        }

        return [
            'size' => $totalSize,
            'count' => $messages,
            'quota' => $quota,
            'over_quota' => $overQuota,
        ];
    }

    protected function addQuotaEntry($size, $count = 1)
    {
        if (! file_exists($this->rootdir . 'maildirsize')) {
            // TODO: should get file handler from calculateQuota
        }
        $size  = (int) $size;
        $count = (int) $count;
        file_put_contents($this->rootdir . 'maildirsize', "$size $count\n", FILE_APPEND);
    }

    /**
     * check if storage is currently over quota
     *
     * @see calculateQuota()
     * @param bool $detailedResponse return known data of quota and current size and message count
     * @param bool $forceRecalc
     * @return bool|array over quota state or detailed response
     */
    public function checkQuota($detailedResponse = false, $forceRecalc = false)
    {
        $result = $this->calculateQuota($forceRecalc);
        return $detailedResponse ? $result : $result['over_quota'];
    }
}
laminas-mail/src/Exception/ExceptionInterface.php000064400000000532147361032560016134 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-mail for the canonical source repository
 * @copyright https://github.com/laminas/laminas-mail/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-mail/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Mail\Exception;

interface ExceptionInterface
{
}
laminas-mail/src/Exception/DomainException.php000064400000000673147361032560015451 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-mail for the canonical source repository
 * @copyright https://github.com/laminas/laminas-mail/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-mail/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Mail\Exception;

/**
 * Exception for Laminas\Mail component.
 */
class DomainException extends \DomainException implements ExceptionInterface
{
}
laminas-mail/src/Exception/InvalidArgumentException.php000064400000000721147361032560017325 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-mail for the canonical source repository
 * @copyright https://github.com/laminas/laminas-mail/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-mail/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Mail\Exception;

/**
 * Exception for Laminas\Mail component.
 */
class InvalidArgumentException extends \InvalidArgumentException implements
    ExceptionInterface
{
}
laminas-mail/src/Exception/OutOfBoundsException.php000064400000000705147361032560016445 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-mail for the canonical source repository
 * @copyright https://github.com/laminas/laminas-mail/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-mail/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Mail\Exception;

/**
 * Exception for Laminas\Mail component.
 */
class OutOfBoundsException extends \OutOfBoundsException implements ExceptionInterface
{
}
laminas-mail/src/Exception/BadMethodCallException.php000064400000000715147361032560016662 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-mail for the canonical source repository
 * @copyright https://github.com/laminas/laminas-mail/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-mail/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Mail\Exception;

/**
 * Exception for Laminas\Mail component.
 */
class BadMethodCallException extends \BadMethodCallException implements
    ExceptionInterface
{
}
laminas-mail/src/Exception/RuntimeException.php000064400000000675147361032560015667 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-mail for the canonical source repository
 * @copyright https://github.com/laminas/laminas-mail/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-mail/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Mail\Exception;

/**
 * Exception for Laminas\Mail component.
 */
class RuntimeException extends \RuntimeException implements ExceptionInterface
{
}
laminas-mail/src/Address/AddressInterface.php000064400000001236147361032560015214 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-mail for the canonical source repository
 * @copyright https://github.com/laminas/laminas-mail/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-mail/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Mail\Address;

interface AddressInterface
{
    /**
     * Retrieve email
     *
     * @return string
     */
    public function getEmail();

    /**
     * Retrieve name, if any
     *
     * @return null|string
     */
    public function getName();

    /**
     * String representation of address
     *
     * @return string
     */
    public function toString();
}
laminas-mail/src/Headers.php000064400000043202147361032560011773 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-mail for the canonical source repository
 * @copyright https://github.com/laminas/laminas-mail/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-mail/blob/master/LICENSE.md New BSD License
 */

declare(strict_types=1);

namespace Laminas\Mail;

use ArrayIterator;
use Countable;
use Iterator;
use Laminas\Loader\PluginClassLocator;
use Laminas\Mail\Header\GenericHeader;
use Laminas\Mail\Header\HeaderInterface;
use Traversable;

/**
 * Basic mail headers collection functionality
 *
 * Handles aggregation of headers
 */
class Headers implements Countable, Iterator
{
    /** @var string End of Line for fields */
    public const EOL = "\r\n";

    /** @var string Start of Line when folding */
    public const FOLDING = "\r\n ";

    /**
     * @var null|Header\HeaderLocatorInterface
     */
    private $headerLocator;

    /**
     * @todo Remove for 3.0.0.
     * @var null|PluginClassLocator
     */
    protected $pluginClassLoader;

    /**
     * @var array key names for $headers array
     */
    protected $headersKeys = [];

    /**
     * @var  Header\HeaderInterface[] instances
     */
    protected $headers = [];

    /**
     * Header encoding; defaults to ASCII
     *
     * @var string
     */
    protected $encoding = 'ASCII';

    /**
     * Populates headers from string representation
     *
     * Parses a string for headers, and aggregates them, in order, in the
     * current instance, primarily as strings until they are needed (they
     * will be lazy loaded)
     *
     * @param  string $string
     * @param  string $EOL EOL string; defaults to {@link EOL}
     * @throws Exception\RuntimeException
     * @return Headers
     */
    public static function fromString($string, $EOL = self::EOL)
    {
        $headers     = new static();
        $currentLine = '';
        $emptyLine   = 0;

        // iterate the header lines, some might be continuations
        $lines = explode($EOL, $string);
        $total = count($lines);
        for ($i = 0; $i < $total; $i += 1) {
            $line = $lines[$i];

            if ($line === "") {
                // Empty line indicates end of headers
                // EXCEPT if there are more lines, in which case, there's a possible error condition
                $emptyLine += 1;
                if ($emptyLine > 2) {
                    break;
                }
                continue;
            } elseif (preg_match('/^\s*$/', $line)) {
                // skip empty continuation line
                continue;
            }

            if ($emptyLine > 1) {
                break;
            }

            // check if a header name is present
            if (preg_match('/^[\x21-\x39\x3B-\x7E]+:.*$/', $line)) {
                if ($currentLine) {
                    // a header name was present, then store the current complete line
                    try {
                        $headers->addHeaderLine($currentLine);
                    } catch (\Throwable $e) {
                        continue;
                    }
                }
                $currentLine = trim($line);
                continue;
            }

            // continuation: append to current line
            // recover the whitespace that break the line (unfolding, rfc2822#section-2.2.3)
            if (preg_match('/^\s+.*$/', $line)) {
                $currentLine .= ' ' . trim($line);
                continue;
            }

            // Line does not match header format!
            throw new Exception\RuntimeException(sprintf(
                'Line "%s" does not match header format!',
                $line
            ));
        }
        if ($currentLine) {
            try {
                $headers->addHeaderLine($currentLine);
            } catch (\Throwable $e) {
                //do nothing
            }
        }
        return $headers;
    }

    /**
     * Set an alternate PluginClassLocator implementation for loading header classes.
     *
     * @deprecated since 2.12.0
     * @todo Remove for version 3.0.0
     * @return $this
     */
    public function setPluginClassLoader(PluginClassLocator $pluginClassLoader)
    {
        // Silenced; can be caught in custom error handlers.
        @trigger_error(sprintf(
            'Since laminas/laminas-mail 2.12.0: Usage of %s is deprecated; use %s::setHeaderLocator() instead',
            __METHOD__,
            __CLASS__
        ), E_USER_DEPRECATED);

        $this->pluginClassLoader = $pluginClassLoader;
        return $this;
    }

    /**
     * Return a PluginClassLocator instance for customizing headers.
     *
     * Lazyloads a Header\HeaderLoader if necessary.
     *
     * @deprecated since 2.12.0
     * @todo Remove for version 3.0.0
     * @return PluginClassLocator
     */
    public function getPluginClassLoader()
    {
        // Silenced; can be caught in custom error handlers.
        @trigger_error(sprintf(
            'Since laminas/laminas-mail 2.12.0: Usage of %s is deprecated; use %s::getHeaderLocator() instead',
            __METHOD__,
            __CLASS__
        ), E_USER_DEPRECATED);

        if (! $this->pluginClassLoader) {
            $this->pluginClassLoader = new Header\HeaderLoader();
        }

        return $this->pluginClassLoader;
    }

    /**
     * Retrieve the header class locator for customizing headers.
     *
     * Lazyloads a Header\HeaderLocator instance if necessary.
     */
    public function getHeaderLocator(): Header\HeaderLocatorInterface
    {
        if (! $this->headerLocator) {
            $this->setHeaderLocator(new Header\HeaderLocator());
        }
        return $this->headerLocator;
    }

    /**
     * @todo Return self when we update to 7.4 or later as minimum PHP version.
     * @return $this
     */
    public function setHeaderLocator(Header\HeaderLocatorInterface $headerLocator)
    {
        $this->headerLocator = $headerLocator;
        return $this;
    }

    /**
     * Set the header encoding
     *
     * @param  string $encoding
     * @return Headers
     */
    public function setEncoding($encoding)
    {
        $this->encoding = $encoding;
        foreach ($this as $header) {
            $header->setEncoding($encoding);
        }
        return $this;
    }

    /**
     * Get the header encoding
     *
     * @return string
     */
    public function getEncoding()
    {
        return $this->encoding;
    }

    /**
     * Add many headers at once
     *
     * Expects an array (or Traversable object) of type/value pairs.
     *
     * @param  array|Traversable $headers
     * @throws Exception\InvalidArgumentException
     * @return Headers
     */
    public function addHeaders($headers)
    {
        if (! is_array($headers) && ! $headers instanceof Traversable) {
            throw new Exception\InvalidArgumentException(sprintf(
                'Expected array or Traversable; received "%s"',
                (is_object($headers) ? get_class($headers) : gettype($headers))
            ));
        }

        foreach ($headers as $name => $value) {
            if (is_int($name)) {
                if (is_string($value)) {
                    $this->addHeaderLine($value);
                } elseif (is_array($value) && count($value) == 1) {
                    $this->addHeaderLine(key($value), current($value));
                } elseif (is_array($value) && count($value) == 2) {
                    $this->addHeaderLine($value[0], $value[1]);
                } elseif ($value instanceof Header\HeaderInterface) {
                    $this->addHeader($value);
                }
            } elseif (is_string($name)) {
                $this->addHeaderLine($name, $value);
            }
        }

        return $this;
    }

    /**
     * Add a raw header line, either in name => value, or as a single string 'name: value'
     *
     * This method allows for lazy-loading in that the parsing and instantiation of HeaderInterface object
     * will be delayed until they are retrieved by either get() or current()
     *
     * @throws Exception\InvalidArgumentException
     * @param  string $headerFieldNameOrLine
     * @param  string $fieldValue optional
     * @return Headers
     */
    public function addHeaderLine($headerFieldNameOrLine, $fieldValue = null)
    {
        if (! is_string($headerFieldNameOrLine)) {
            throw new Exception\InvalidArgumentException(sprintf(
                '%s expects its first argument to be a string; received "%s"',
                __METHOD__,
                (is_object($headerFieldNameOrLine)
                ? get_class($headerFieldNameOrLine)
                : gettype($headerFieldNameOrLine))
            ));
        }

        if ($fieldValue === null) {
            $headers = $this->loadHeader($headerFieldNameOrLine);
            $headers = is_array($headers) ? $headers : [$headers];
            foreach ($headers as $header) {
                $this->addHeader($header);
            }
        } elseif (is_array($fieldValue)) {
            foreach ($fieldValue as $i) {
                $this->addHeader(Header\GenericMultiHeader::fromString($headerFieldNameOrLine . ':' . $i));
            }
        } else {
            $this->addHeader(Header\GenericHeader::fromString($headerFieldNameOrLine . ':' . $fieldValue));
        }

        return $this;
    }

    /**
     * Add a Header\Interface to this container, for raw values see {@link addHeaderLine()} and {@link addHeaders()}
     *
     * @param  Header\HeaderInterface $header
     * @return Headers
     */
    public function addHeader(Header\HeaderInterface $header)
    {
        $key = $this->normalizeFieldName($header->getFieldName());
        $this->headersKeys[] = $key;
        $this->headers[] = $header;
        if ($this->getEncoding() !== 'ASCII') {
            $header->setEncoding($this->getEncoding());
        }
        return $this;
    }

    /**
     * Remove a Header from the container
     *
     * @param  string|Header\HeaderInterface field name or specific header instance to remove
     * @return bool
     */
    public function removeHeader($instanceOrFieldName)
    {
        if (! $instanceOrFieldName instanceof Header\HeaderInterface && ! is_string($instanceOrFieldName)) {
            throw new Exception\InvalidArgumentException(sprintf(
                '%s requires a string or %s instance; received %s',
                __METHOD__,
                Header\HeaderInterface::class,
                is_object($instanceOrFieldName) ? get_class($instanceOrFieldName) : gettype($instanceOrFieldName)
            ));
        }

        if ($instanceOrFieldName instanceof Header\HeaderInterface) {
            $indexes = array_keys($this->headers, $instanceOrFieldName, true);
        }

        if (is_string($instanceOrFieldName)) {
            $key = $this->normalizeFieldName($instanceOrFieldName);
            $indexes = array_keys($this->headersKeys, $key, true);
        }

        if (! empty($indexes)) {
            foreach ($indexes as $index) {
                unset($this->headersKeys[$index]);
                unset($this->headers[$index]);
            }
            return true;
        }

        return false;
    }

    /**
     * Clear all headers
     *
     * Removes all headers from queue
     *
     * @return Headers
     */
    public function clearHeaders()
    {
        $this->headers = $this->headersKeys = [];
        return $this;
    }

    /**
     * Get all headers of a certain name/type
     *
     * @param  string $name
     * @return bool|ArrayIterator|Header\HeaderInterface Returns false if there is no headers with $name in this
     * contain, an ArrayIterator if the header is a MultipleHeadersInterface instance and finally returns
     * HeaderInterface for the rest of cases.
     */
    public function get($name)
    {
        $key = $this->normalizeFieldName($name);
        $results = [];

        foreach (array_keys($this->headersKeys, $key) as $index) {
            if ($this->headers[$index] instanceof Header\GenericHeader) {
                $results[] = $this->lazyLoadHeader($index);
            } else {
                $results[] = $this->headers[$index];
            }
        }

        switch (count($results)) {
            case 0:
                return false;
            case 1:
                if ($results[0] instanceof Header\MultipleHeadersInterface) {
                    return new ArrayIterator($results);
                }
                return $results[0];
            default:
                return new ArrayIterator($results);
        }
    }

    /**
     * Test for existence of a type of header
     *
     * @param  string $name
     * @return bool
     */
    public function has($name)
    {
        $name = $this->normalizeFieldName($name);
        return in_array($name, $this->headersKeys);
    }

    /**
     * Advance the pointer for this object as an iterator
     *
     */
    public function next()
    {
        next($this->headers);
    }

    /**
     * Return the current key for this object as an iterator
     *
     * @return mixed
     */
    public function key()
    {
        return key($this->headers);
    }

    /**
     * Is this iterator still valid?
     *
     * @return bool
     */
    public function valid()
    {
        return (current($this->headers) !== false);
    }

    /**
     * Reset the internal pointer for this object as an iterator
     *
     */
    public function rewind()
    {
        reset($this->headers);
    }

    /**
     * Return the current value for this iterator, lazy loading it if need be
     *
     * @return Header\HeaderInterface
     */
    public function current()
    {
        $current = current($this->headers);
        if ($current instanceof Header\GenericHeader) {
            $current = $this->lazyLoadHeader(key($this->headers));
        }
        return $current;
    }

    /**
     * Return the number of headers in this contain, if all headers have not been parsed, actual count could
     * increase if MultipleHeader objects exist in the Request/Response.  If you need an exact count, iterate
     *
     * @return int count of currently known headers
     */
    public function count()
    {
        return count($this->headers);
    }

    /**
     * Render all headers at once
     *
     * This method handles the normal iteration of headers; it is up to the
     * concrete classes to prepend with the appropriate status/request line.
     *
     * @return string
     */
    public function toString()
    {
        $headers = '';
        foreach ($this as $header) {
            if ($str = $header->toString()) {
                $headers .= $str . self::EOL;
            }
        }

        return $headers;
    }

    /**
     * Return the headers container as an array
     *
     * @param  bool $format Return the values in Mime::Encoded or in Raw format
     * @return array
     * @todo determine how to produce single line headers, if they are supported
     */
    public function toArray($format = Header\HeaderInterface::FORMAT_RAW)
    {
        $headers = [];
        /* @var $header Header\HeaderInterface */
        foreach ($this->headers as $header) {
            if ($header instanceof Header\MultipleHeadersInterface) {
                $name = $header->getFieldName();
                if (! isset($headers[$name])) {
                    $headers[$name] = [];
                }
                $headers[$name][] = $header->getFieldValue($format);
            } else {
                $headers[$header->getFieldName()] = $header->getFieldValue($format);
            }
        }
        return $headers;
    }

    /**
     * By calling this, it will force parsing and loading of all headers, after this count() will be accurate
     *
     * @return bool
     */
    public function forceLoading()
    {
        foreach ($this as $item) {
            // $item should now be loaded
        }
        return true;
    }

    /**
     * Create Header object from header line
     *
     * @param string $headerLine
     * @return Header\HeaderInterface|Header\HeaderInterface[]
     */
    public function loadHeader($headerLine)
    {
        list($name) = Header\GenericHeader::splitHeaderLine($headerLine);

        /** @var HeaderInterface $class */
        $class = $this->resolveHeaderClass($name);
        return $class::fromString($headerLine);
    }

    /**
     * @param $index
     * @return mixed
     */
    protected function lazyLoadHeader($index)
    {
        $current = $this->headers[$index];

        $key   = $this->headersKeys[$index];

        /** @var GenericHeader $class */
        $class = $this->resolveHeaderClass($key);

        $encoding = $current->getEncoding();
        $headers  = $class::fromString($current->toString());
        if (is_array($headers)) {
            $current = array_shift($headers);
            $current->setEncoding($encoding);
            $this->headers[$index] = $current;
            foreach ($headers as $header) {
                $header->setEncoding($encoding);
                $this->headersKeys[] = $key;
                $this->headers[]     = $header;
            }
            return $current;
        }

        $current = $headers;
        $current->setEncoding($encoding);
        $this->headers[$index] = $current;
        return $current;
    }

    /**
     * Normalize a field name
     *
     * @param  string $fieldName
     * @return string
     */
    protected function normalizeFieldName($fieldName)
    {
        return str_replace(['-', '_', ' ', '.'], '', strtolower($fieldName));
    }

    /**
     * @param string $key
     * @return string
     */
    private function resolveHeaderClass($key)
    {
        if ($this->pluginClassLoader) {
            return $this->pluginClassLoader->load($key) ?: Header\GenericHeader::class;
        }
        return $this->getHeaderLocator()->get($key, Header\GenericHeader::class);
    }
}
laminas-mail/README.md000064400000001303147361032560010373 0ustar00# laminas-mail

[![Build Status](https://github.com/laminas/laminas-mail/workflows/Continuous%20Integration/badge.svg)](https://github.com/laminas/laminas-mail/actions?query=workflow%3A"Continuous+Integration")

`Laminas\Mail` provides generalized functionality to compose and send both text and
MIME-compliant multipart email messages. Mail can be sent with `Laminas\Mail` via
the `Mail\Transport\Sendmail`, `Mail\Transport\Smtp` or the `Mail\Transport\File`
transport. Of course, you can also implement your own transport by implementing
the `Mail\Transport\TransportInterface`.

- File issues at https://github.com/laminas/laminas-mail/issues
- Documentation is at https://docs.laminas.dev/laminas-mail/
laminas-mail/LICENSE.md000064400000002732147361032560010527 0ustar00Copyright (c) 2020 Laminas Project a Series of LF Projects, LLC.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

- Redistributions of source code must retain the above copyright notice, this
  list of conditions and the following disclaimer.

- Redistributions in binary form must reproduce the above copyright notice,
  this list of conditions and the following disclaimer in the documentation
  and/or other materials provided with the distribution.

- Neither the name of Laminas Foundation nor the names of its contributors may
  be used to endorse or promote products derived from this software without
  specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
laminas-mime/COPYRIGHT.md000064400000000134147361032560011014 0ustar00Copyright (c) 2019-2020, Laminas Foundation.
All rights reserved. (https://getlaminas.org/)
laminas-mime/src/Message.php000064400000022414147361032560012013 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-mime for the canonical source repository
 * @copyright https://github.com/laminas/laminas-mime/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-mime/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Mime;

class Message
{
    protected $parts = [];
    protected $mime = null;

    /**
     * Returns the list of all Laminas\Mime\Part in the message
     *
     * @return Part[]
     */
    public function getParts()
    {
        return $this->parts;
    }

    /**
     * Sets the given array of Laminas\Mime\Part as the array for the message
     *
     * @param array $parts
     * @return self
     */
    public function setParts($parts)
    {
        $this->parts = $parts;
        return $this;
    }

    /**
     * Append a new Laminas\Mime\Part to the current message
     *
     * @param \Laminas\Mime\Part $part
     * @throws Exception\InvalidArgumentException
     * @return self
     */
    public function addPart(Part $part)
    {
        foreach ($this->getParts() as $key => $row) {
            if ($part == $row) {
                throw new Exception\InvalidArgumentException(sprintf(
                    'Provided part %s already defined.',
                    $part->getId()
                ));
            }
        }

        $this->parts[] = $part;
        return $this;
    }

    /**
     * Check if message needs to be sent as multipart
     * MIME message or if it has only one part.
     *
     * @return bool
     */
    public function isMultiPart()
    {
        return (count($this->parts) > 1);
    }

    /**
     * Set Laminas\Mime\Mime object for the message
     *
     * This can be used to set the boundary specifically or to use a subclass of
     * Laminas\Mime for generating the boundary.
     *
     * @param \Laminas\Mime\Mime $mime
     * @return self
     */
    public function setMime(Mime $mime)
    {
        $this->mime = $mime;
        return $this;
    }

    /**
     * Returns the Laminas\Mime\Mime object in use by the message
     *
     * If the object was not present, it is created and returned. Can be used to
     * determine the boundary used in this message.
     *
     * @return \Laminas\Mime\Mime
     */
    public function getMime()
    {
        if ($this->mime === null) {
            $this->mime = new Mime();
        }

        return $this->mime;
    }

    /**
     * Generate MIME-compliant message from the current configuration
     *
     * This can be a multipart message if more than one MIME part was added. If
     * only one part is present, the content of this part is returned. If no
     * part had been added, an empty string is returned.
     *
     * Parts are separated by the mime boundary as defined in Laminas\Mime\Mime. If
     * {@link setMime()} has been called before this method, the Laminas\Mime\Mime
     * object set by this call will be used. Otherwise, a new Laminas\Mime\Mime object
     * is generated and used.
     *
     * @param string $EOL EOL string; defaults to {@link Laminas\Mime\Mime::LINEEND}
     * @return string
     */
    public function generateMessage($EOL = Mime::LINEEND)
    {
        if (! $this->isMultiPart()) {
            if (empty($this->parts)) {
                return '';
            }
            $part = current($this->parts);
            $body = $part->getContent($EOL);
        } else {
            $mime = $this->getMime();

            $boundaryLine = $mime->boundaryLine($EOL);
            $body = 'This is a message in Mime Format.  If you see this, '
                  . "your mail reader does not support this format." . $EOL;

            foreach (array_keys($this->parts) as $p) {
                $body .= $boundaryLine
                       . $this->getPartHeaders($p, $EOL)
                       . $EOL
                       . $this->getPartContent($p, $EOL);
            }

            $body .= $mime->mimeEnd($EOL);
        }

        return trim($body);
    }

    /**
     * Get the headers of a given part as an array
     *
     * @param int $partnum
     * @return array
     */
    public function getPartHeadersArray($partnum)
    {
        return $this->parts[$partnum]->getHeadersArray();
    }

    /**
     * Get the headers of a given part as a string
     *
     * @param int $partnum
     * @param string $EOL
     * @return string
     */
    public function getPartHeaders($partnum, $EOL = Mime::LINEEND)
    {
        return $this->parts[$partnum]->getHeaders($EOL);
    }

    /**
     * Get the (encoded) content of a given part as a string
     *
     * @param int $partnum
     * @param string $EOL
     * @return string
     */
    public function getPartContent($partnum, $EOL = Mime::LINEEND)
    {
        return $this->parts[$partnum]->getContent($EOL);
    }

    /**
     * Explode MIME multipart string into separate parts
     *
     * Parts consist of the header and the body of each MIME part.
     *
     * @param string $body
     * @param string $boundary
     * @throws Exception\RuntimeException
     * @return array
     */
    // @codingStandardsIgnoreStart
    protected static function _disassembleMime($body, $boundary)
    {
        // @codingStandardsIgnoreEnd
        $start  = 0;
        $res    = [];
        // find every mime part limiter and cut out the
        // string before it.
        // the part before the first boundary string is discarded:
        $p = strpos($body, '--' . $boundary."\n", $start);
        if ($p === false) {
            // no parts found!
            return [];
        }

        // position after first boundary line
        $start = $p + 3 + strlen($boundary);

        while (($p = strpos($body, '--' . $boundary . "\n", $start)) !== false) {
            $res[] = substr($body, $start, $p - $start);
            $start = $p + 3 + strlen($boundary);
        }

        // no more parts, find end boundary
        $p = strpos($body, '--' . $boundary . '--', $start);
        if ($p === false) {
            throw new Exception\RuntimeException('Not a valid Mime Message: End Missing');
        }

        // the remaining part also needs to be parsed:
        $res[] = substr($body, $start, $p - $start);
        return $res;
    }

    /**
     * Decodes a MIME encoded string and returns a Laminas\Mime\Message object with
     * all the MIME parts set according to the given string
     *
     * @param string $message
     * @param string $boundary Multipart boundary; if omitted, $message will be
     *     treated as a single part.
     * @param string $EOL EOL string; defaults to {@link Laminas\Mime\Mime::LINEEND}
     * @throws Exception\RuntimeException
     * @return Message
     */
    public static function createFromMessage($message, $boundary = null, $EOL = Mime::LINEEND)
    {
        if ($boundary) {
            $parts = Decode::splitMessageStruct($message, $boundary, $EOL);
        } else {
            Decode::splitMessage($message, $headers, $body, $EOL);
            $parts = [[
                'header' => $headers,
                'body'   => $body,
            ]];
        }

        $res = new static();
        foreach ($parts as $part) {
            // now we build a new MimePart for the current Message Part:
            $properties = [];
            foreach ($part['header'] as $header) {
                /** @var \Laminas\Mail\Header\HeaderInterface $header */
                /**
                 * @todo check for characterset and filename
                 */

                $fieldName  = $header->getFieldName();
                $fieldValue = $header->getFieldValue();
                switch (strtolower($fieldName)) {
                    case 'content-type':
                        $properties['type'] = $fieldValue;
                        break;
                    case 'content-transfer-encoding':
                        $properties['encoding'] = $fieldValue;
                        break;
                    case 'content-id':
                        $properties['id'] = trim($fieldValue, '<>');
                        break;
                    case 'content-disposition':
                        $properties['disposition'] = $fieldValue;
                        break;
                    case 'content-description':
                        $properties['description'] = $fieldValue;
                        break;
                    case 'content-location':
                        $properties['location'] = $fieldValue;
                        break;
                    case 'content-language':
                        $properties['language'] = $fieldValue;
                        break;
                    default:
                        // Ignore unknown header
                        break;
                }
            }

            $body = $part['body'];

            if (isset($properties['encoding'])) {
                switch ($properties['encoding']) {
                    case 'quoted-printable':
                        $body = quoted_printable_decode($body);
                        break;
                    case 'base64':
                        $body = base64_decode($body);
                        break;
                }
            }

            $newPart = new Part($body);
            foreach ($properties as $key => $value) {
                $newPart->$key = $value;
            }
            $res->addPart($newPart);
        }

        return $res;
    }
}
laminas-mime/src/Mime.php000064400000034107147361032560011320 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-mime for the canonical source repository
 * @copyright https://github.com/laminas/laminas-mime/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-mime/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Mime;

/**
 * Support class for MultiPart Mime Messages
 */
class Mime
{
    // @codingStandardsIgnoreStart
    const TYPE_OCTETSTREAM         = 'application/octet-stream';
    const TYPE_TEXT                = 'text/plain';
    const TYPE_HTML                = 'text/html';
    const ENCODING_7BIT            = '7bit';
    const ENCODING_8BIT            = '8bit';
    const ENCODING_QUOTEDPRINTABLE = 'quoted-printable';
    const ENCODING_BASE64          = 'base64';
    const DISPOSITION_ATTACHMENT   = 'attachment';
    const DISPOSITION_INLINE       = 'inline';
    const LINELENGTH               = 72;
    const LINEEND                  = "\n";
    const MULTIPART_ALTERNATIVE    = 'multipart/alternative';
    const MULTIPART_MIXED          = 'multipart/mixed';
    const MULTIPART_RELATED        = 'multipart/related';
    const CHARSET_REGEX            = '#=\?(?P<charset>[\x21\x23-\x26\x2a\x2b\x2d\x5e\5f\60\x7b-\x7ea-zA-Z0-9]+)\?(?P<encoding>[\x21\x23-\x26\x2a\x2b\x2d\x5e\5f\60\x7b-\x7ea-zA-Z0-9]+)\?(?P<text>[\x21-\x3e\x40-\x7e]+)#';
    // @codingStandardsIgnoreEnd

    protected $boundary;
    protected static $makeUnique = 0;

    // lookup-Tables for QuotedPrintable
    public static $qpKeys = [
        "\x00","\x01","\x02","\x03","\x04","\x05","\x06","\x07",
        "\x08","\x09","\x0A","\x0B","\x0C","\x0D","\x0E","\x0F",
        "\x10","\x11","\x12","\x13","\x14","\x15","\x16","\x17",
        "\x18","\x19","\x1A","\x1B","\x1C","\x1D","\x1E","\x1F",
        "\x7F","\x80","\x81","\x82","\x83","\x84","\x85","\x86",
        "\x87","\x88","\x89","\x8A","\x8B","\x8C","\x8D","\x8E",
        "\x8F","\x90","\x91","\x92","\x93","\x94","\x95","\x96",
        "\x97","\x98","\x99","\x9A","\x9B","\x9C","\x9D","\x9E",
        "\x9F","\xA0","\xA1","\xA2","\xA3","\xA4","\xA5","\xA6",
        "\xA7","\xA8","\xA9","\xAA","\xAB","\xAC","\xAD","\xAE",
        "\xAF","\xB0","\xB1","\xB2","\xB3","\xB4","\xB5","\xB6",
        "\xB7","\xB8","\xB9","\xBA","\xBB","\xBC","\xBD","\xBE",
        "\xBF","\xC0","\xC1","\xC2","\xC3","\xC4","\xC5","\xC6",
        "\xC7","\xC8","\xC9","\xCA","\xCB","\xCC","\xCD","\xCE",
        "\xCF","\xD0","\xD1","\xD2","\xD3","\xD4","\xD5","\xD6",
        "\xD7","\xD8","\xD9","\xDA","\xDB","\xDC","\xDD","\xDE",
        "\xDF","\xE0","\xE1","\xE2","\xE3","\xE4","\xE5","\xE6",
        "\xE7","\xE8","\xE9","\xEA","\xEB","\xEC","\xED","\xEE",
        "\xEF","\xF0","\xF1","\xF2","\xF3","\xF4","\xF5","\xF6",
        "\xF7","\xF8","\xF9","\xFA","\xFB","\xFC","\xFD","\xFE",
        "\xFF"
    ];

    public static $qpReplaceValues = [
        "=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",
        "=7F","=80","=81","=82","=83","=84","=85","=86",
        "=87","=88","=89","=8A","=8B","=8C","=8D","=8E",
        "=8F","=90","=91","=92","=93","=94","=95","=96",
        "=97","=98","=99","=9A","=9B","=9C","=9D","=9E",
        "=9F","=A0","=A1","=A2","=A3","=A4","=A5","=A6",
        "=A7","=A8","=A9","=AA","=AB","=AC","=AD","=AE",
        "=AF","=B0","=B1","=B2","=B3","=B4","=B5","=B6",
        "=B7","=B8","=B9","=BA","=BB","=BC","=BD","=BE",
        "=BF","=C0","=C1","=C2","=C3","=C4","=C5","=C6",
        "=C7","=C8","=C9","=CA","=CB","=CC","=CD","=CE",
        "=CF","=D0","=D1","=D2","=D3","=D4","=D5","=D6",
        "=D7","=D8","=D9","=DA","=DB","=DC","=DD","=DE",
        "=DF","=E0","=E1","=E2","=E3","=E4","=E5","=E6",
        "=E7","=E8","=E9","=EA","=EB","=EC","=ED","=EE",
        "=EF","=F0","=F1","=F2","=F3","=F4","=F5","=F6",
        "=F7","=F8","=F9","=FA","=FB","=FC","=FD","=FE",
        "=FF"
    ];
    // @codingStandardsIgnoreStart
    public static $qpKeysString =
         "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F\x7F\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8A\x8B\x8C\x8D\x8E\x8F\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9A\x9B\x9C\x9D\x9E\x9F\xA0\xA1\xA2\xA3\xA4\xA5\xA6\xA7\xA8\xA9\xAA\xAB\xAC\xAD\xAE\xAF\xB0\xB1\xB2\xB3\xB4\xB5\xB6\xB7\xB8\xB9\xBA\xBB\xBC\xBD\xBE\xBF\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF\xD0\xD1\xD2\xD3\xD4\xD5\xD6\xD7\xD8\xD9\xDA\xDB\xDC\xDD\xDE\xDF\xE0\xE1\xE2\xE3\xE4\xE5\xE6\xE7\xE8\xE9\xEA\xEB\xEC\xED\xEE\xEF\xF0\xF1\xF2\xF3\xF4\xF5\xF6\xF7\xF8\xF9\xFA\xFB\xFC\xFD\xFE\xFF";
    // @codingStandardsIgnoreEnd

    /**
     * Check if the given string is "printable"
     *
     * Checks that a string contains no unprintable characters. If this returns
     * false, encode the string for secure delivery.
     *
     * @param string $str
     * @return bool
     */
    public static function isPrintable($str)
    {
        return (strcspn($str, static::$qpKeysString) == strlen($str));
    }

    /**
     * Encode a given string with the QUOTED_PRINTABLE mechanism and wrap the lines.
     *
     * @param string $str
     * @param int $lineLength Defaults to {@link LINELENGTH}
     * @param string $lineEnd Defaults to {@link LINEEND}
     * @return string
     */
    public static function encodeQuotedPrintable(
        $str,
        $lineLength = self::LINELENGTH,
        $lineEnd = self::LINEEND
    ) {
        $out = '';
        $str = self::_encodeQuotedPrintable($str);

        // Split encoded text into separate lines
        $initialPtr = 0;
        $strLength = strlen($str);
        while ($initialPtr < $strLength) {
            $continueAt = $strLength - $initialPtr;

            if ($continueAt > $lineLength) {
                $continueAt = $lineLength;
            }

            $chunk = substr($str, $initialPtr, $continueAt);

            // Ensure we are not splitting across an encoded character
            $endingMarkerPos = strrpos($chunk, '=');
            if ($endingMarkerPos !== false && $endingMarkerPos >= strlen($chunk) - 2) {
                $chunk = substr($chunk, 0, $endingMarkerPos);
                $continueAt = $endingMarkerPos;
            }

            if (ord($chunk[0]) == 0x2E) { // 0x2E is a dot
                $chunk = '=2E' . substr($chunk, 1);
            }

            // copied from swiftmailer https://git.io/vAXU1
            switch (ord(substr($chunk, strlen($chunk) - 1))) {
                case 0x09: // Horizontal Tab
                    $chunk = substr_replace($chunk, '=09', strlen($chunk) - 1, 1);
                    break;
                case 0x20: // Space
                    $chunk = substr_replace($chunk, '=20', strlen($chunk) - 1, 1);
                    break;
            }

            // Add string and continue
            $out .= $chunk . '=' . $lineEnd;
            $initialPtr += $continueAt;
        }

        $out = rtrim($out, $lineEnd);
        $out = rtrim($out, '=');
        return $out;
    }

    /**
     * Converts a string into quoted printable format.
     *
     * @param  string $str
     * @return string
     */
    // @codingStandardsIgnoreStart
    private static function _encodeQuotedPrintable($str)
    {
        // @codingStandardsIgnoreEnd
        $str = str_replace('=', '=3D', $str);
        $str = str_replace(static::$qpKeys, static::$qpReplaceValues, $str);
        $str = rtrim($str);
        return $str;
    }

    /**
     * Encode a given string with the QUOTED_PRINTABLE mechanism for Mail Headers.
     *
     * Mail headers depend on an extended quoted printable algorithm otherwise
     * a range of bugs can occur.
     *
     * @param string $str
     * @param string $charset
     * @param int $lineLength Defaults to {@link LINELENGTH}
     * @param string $lineEnd Defaults to {@link LINEEND}
     * @return string
     */
    public static function encodeQuotedPrintableHeader(
        $str,
        $charset,
        $lineLength = self::LINELENGTH,
        $lineEnd = self::LINEEND
    ) {
        // Reduce line-length by the length of the required delimiter, charsets and encoding
        $prefix = sprintf('=?%s?Q?', $charset);
        $lineLength = $lineLength - strlen($prefix) - 3;

        $str = self::_encodeQuotedPrintable($str);

        // Mail-Header required chars have to be encoded also:
        $str = str_replace(['?', ',', ' ', '_'], ['=3F', '=2C', '=20', '=5F'], $str);

        // initialize first line, we need it anyways
        $lines = [0 => ''];

        // Split encoded text into separate lines
        $tmp = '';
        while (strlen($str) > 0) {
            $currentLine = max(count($lines) - 1, 0);
            $token       = static::getNextQuotedPrintableToken($str);
            $substr      = substr($str, strlen($token));
            $str         = (false === $substr) ? '' : $substr;

            $tmp .= $token;
            if ($token === '=20') {
                // only if we have a single char token or space, we can append the
                // tempstring it to the current line or start a new line if necessary.
                $lineLimitReached = (strlen($lines[$currentLine] . $tmp) > $lineLength);
                $noCurrentLine = ($lines[$currentLine] === '');
                if ($noCurrentLine && $lineLimitReached) {
                    $lines[$currentLine] = $tmp;
                    $lines[$currentLine + 1] = '';
                } elseif ($lineLimitReached) {
                    $lines[$currentLine + 1] = $tmp;
                } else {
                    $lines[$currentLine] .= $tmp;
                }
                $tmp = '';
            }
            // don't forget to append the rest to the last line
            if (strlen($str) === 0) {
                $lines[$currentLine] .= $tmp;
            }
        }

        // assemble the lines together by pre- and appending delimiters, charset, encoding.
        for ($i = 0, $count = count($lines); $i < $count; $i++) {
            $lines[$i] = " " . $prefix . $lines[$i] . "?=";
        }
        $str = trim(implode($lineEnd, $lines));
        return $str;
    }

    /**
     * Retrieves the first token from a quoted printable string.
     *
     * @param  string $str
     * @return string
     */
    private static function getNextQuotedPrintableToken($str)
    {
        if (0 === strpos($str, '=')) {
            $token = substr($str, 0, 3);
        } else {
            $token = substr($str, 0, 1);
        }
        return $token;
    }

    /**
     * Encode a given string in mail header compatible base64 encoding.
     *
     * @param string $str
     * @param string $charset
     * @param int $lineLength Defaults to {@link LINELENGTH}
     * @param string $lineEnd Defaults to {@link LINEEND}
     * @return string
     */
    public static function encodeBase64Header(
        $str,
        $charset,
        $lineLength = self::LINELENGTH,
        $lineEnd = self::LINEEND
    ) {
        $prefix = '=?' . $charset . '?B?';
        $suffix = '?=';
        $remainingLength = $lineLength - strlen($prefix) - strlen($suffix);

        $encodedValue = static::encodeBase64($str, $remainingLength, $lineEnd);
        $encodedValue = str_replace($lineEnd, $suffix . $lineEnd . ' ' . $prefix, $encodedValue);
        $encodedValue = $prefix . $encodedValue . $suffix;
        return $encodedValue;
    }

    /**
     * Encode a given string in base64 encoding and break lines
     * according to the maximum linelength.
     *
     * @param string $str
     * @param int $lineLength Defaults to {@link LINELENGTH}
     * @param string $lineEnd Defaults to {@link LINEEND}
     * @return string
     */
    public static function encodeBase64(
        $str,
        $lineLength = self::LINELENGTH,
        $lineEnd = self::LINEEND
    ) {
        $lineLength = $lineLength - ($lineLength % 4);
        return rtrim(chunk_split(base64_encode($str), $lineLength, $lineEnd));
    }

    /**
     * Constructor
     *
     * @param null|string $boundary
     * @access public
     */
    public function __construct($boundary = null)
    {
        // This string needs to be somewhat unique
        if ($boundary === null) {
            $this->boundary = '=_' . md5(microtime(1) . static::$makeUnique++);
        } else {
            $this->boundary = $boundary;
        }
    }

    /**
     * Encode the given string with the given encoding.
     *
     * @param string $str
     * @param string $encoding
     * @param string $EOL EOL string; defaults to {@link LINEEND}
     * @return string
     */
    public static function encode($str, $encoding, $EOL = self::LINEEND)
    {
        switch ($encoding) {
            case self::ENCODING_BASE64:
                return static::encodeBase64($str, self::LINELENGTH, $EOL);

            case self::ENCODING_QUOTEDPRINTABLE:
                return static::encodeQuotedPrintable($str, self::LINELENGTH, $EOL);

            default:
                /**
                 * @todo 7Bit and 8Bit is currently handled the same way.
                 */
                return $str;
        }
    }

    /**
     * Return a MIME boundary
     *
     * @access public
     * @return string
     */
    public function boundary()
    {
        return $this->boundary;
    }

    /**
     * Return a MIME boundary line
     *
     * @param string $EOL Defaults to {@link LINEEND}
     * @access public
     * @return string
     */
    public function boundaryLine($EOL = self::LINEEND)
    {
        return $EOL . '--' . $this->boundary . $EOL;
    }

    /**
     * Return MIME ending
     *
     * @param string $EOL Defaults to {@link LINEEND}
     * @access public
     * @return string
     */
    public function mimeEnd($EOL = self::LINEEND)
    {
        return $EOL . '--' . $this->boundary . '--' . $EOL;
    }

    /**
     * Detect MIME charset
     *
     * Extract parts according to https://tools.ietf.org/html/rfc2047#section-2
     *
     * @param string $str
     * @return string
     */
    public static function mimeDetectCharset($str)
    {
        if (preg_match(self::CHARSET_REGEX, $str, $matches)) {
            return strtoupper($matches['charset']);
        }

        return 'ASCII';
    }
}
laminas-mime/src/Part.php000064400000026067147361032560011345 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-mime for the canonical source repository
 * @copyright https://github.com/laminas/laminas-mime/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-mime/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Mime;

/**
 * Class representing a MIME part.
 */
class Part
{
    public $type = Mime::TYPE_OCTETSTREAM;
    public $encoding = Mime::ENCODING_8BIT;
    public $id;
    public $disposition;
    public $filename;
    public $description;
    public $charset;
    public $boundary;
    public $location;
    public $language;
    protected $content;
    protected $isStream = false;
    protected $filters = [];

    /**
     * create a new Mime Part.
     * The (unencoded) content of the Part as passed
     * as a string or stream
     *
     * @param mixed $content  String or Stream containing the content
     * @throws Exception\InvalidArgumentException
     */
    public function __construct($content = '')
    {
        $this->setContent($content);
    }

    /**
     * @todo error checking for setting $type
     * @todo error checking for setting $encoding
     */

    /**
     * Set type
     * @param string $type
     * @return self
     */
    public function setType($type = Mime::TYPE_OCTETSTREAM)
    {
        $this->type = $type;
        return $this;
    }

    /**
     * Get type
     * @return string
     */
    public function getType()
    {
        return $this->type;
    }

    /**
     * Set encoding
     * @param string $encoding
     * @return self
     */
    public function setEncoding($encoding = Mime::ENCODING_8BIT)
    {
        $this->encoding = $encoding;
        return $this;
    }

    /**
     * Get encoding
     * @return string
     */
    public function getEncoding()
    {
        return $this->encoding;
    }

    /**
     * Set id
     * @param string $id
     * @return self
     */
    public function setId($id)
    {
        $this->id = $id;
        return $this;
    }

    /**
     * Get id
     * @return string
     */
    public function getId()
    {
        return $this->id;
    }

    /**
     * Set disposition
     * @param string $disposition
     * @return self
     */
    public function setDisposition($disposition)
    {
        $this->disposition = $disposition;
        return $this;
    }

    /**
     * Get disposition
     * @return string
     */
    public function getDisposition()
    {
        return $this->disposition;
    }

    /**
     * Set description
     * @param string $description
     * @return self
     */
    public function setDescription($description)
    {
        $this->description = $description;
        return $this;
    }

    /**
     * Get description
     * @return string
     */
    public function getDescription()
    {
        return $this->description;
    }

    /**
     * Set filename
     * @param string $fileName
     * @return self
     */
    public function setFileName($fileName)
    {
        $this->filename = $fileName;
        return $this;
    }

    /**
     * Get filename
     * @return string
     */
    public function getFileName()
    {
        return $this->filename;
    }

    /**
     * Set charset
     * @param string $type
     * @return self
     */
    public function setCharset($charset)
    {
        $this->charset = $charset;
        return $this;
    }

    /**
     * Get charset
     * @return string
     */
    public function getCharset()
    {
        return $this->charset;
    }

    /**
     * Set boundary
     * @param string $boundary
     * @return self
     */
    public function setBoundary($boundary)
    {
        $this->boundary = $boundary;
        return $this;
    }

    /**
     * Get boundary
     * @return string
     */
    public function getBoundary()
    {
        return $this->boundary;
    }

    /**
     * Set location
     * @param string $location
     * @return self
     */
    public function setLocation($location)
    {
        $this->location = $location;
        return $this;
    }

    /**
     * Get location
     * @return string
     */
    public function getLocation()
    {
        return $this->location;
    }

    /**
     * Set language
     * @param string $language
     * @return self
     */
    public function setLanguage($language)
    {
        $this->language = $language;
        return $this;
    }

    /**
     * Get language
     * @return string
     */
    public function getLanguage()
    {
        return $this->language;
    }

    /**
     * Set content
     * @param mixed $content  String or Stream containing the content
     * @throws Exception\InvalidArgumentException
     * @return self
     */
    public function setContent($content)
    {
        if (! is_string($content) && ! is_resource($content)) {
            throw new Exception\InvalidArgumentException(sprintf(
                'Content must be string or resource; received "%s"',
                is_object($content) ? get_class($content) : gettype($content)
            ));
        }
        $this->content = $content;
        if (is_resource($content)) {
            $this->isStream = true;
        }

        return $this;
    }

    /**
     * Set isStream
     * @param bool $isStream
     * @return self
     */
    public function setIsStream($isStream = false)
    {
        $this->isStream = (bool) $isStream;
        return $this;
    }

    /**
     * Get isStream
     * @return bool
     */
    public function getIsStream()
    {
        return $this->isStream;
    }

    /**
     * Set filters
     * @param array $filters
     * @return self
     */
    public function setFilters($filters = [])
    {
        $this->filters = $filters;
        return $this;
    }

    /**
     * Get Filters
     * @return array
     */
    public function getFilters()
    {
        return $this->filters;
    }

    /**
     * check if this part can be read as a stream.
     * if true, getEncodedStream can be called, otherwise
     * only getContent can be used to fetch the encoded
     * content of the part
     *
     * @return bool
     */
    public function isStream()
    {
        return $this->isStream;
    }

    /**
     * if this was created with a stream, return a filtered stream for
     * reading the content. very useful for large file attachments.
     *
     * @param string $EOL
     * @return resource
     * @throws Exception\RuntimeException if not a stream or unable to append filter
     */
    public function getEncodedStream($EOL = Mime::LINEEND)
    {
        if (! $this->isStream) {
            throw new Exception\RuntimeException('Attempt to get a stream from a string part');
        }

        //stream_filter_remove(); // ??? is that right?
        switch ($this->encoding) {
            case Mime::ENCODING_QUOTEDPRINTABLE:
                if (array_key_exists(Mime::ENCODING_QUOTEDPRINTABLE, $this->filters)) {
                    stream_filter_remove($this->filters[Mime::ENCODING_QUOTEDPRINTABLE]);
                }
                $filter = stream_filter_append(
                    $this->content,
                    'convert.quoted-printable-encode',
                    STREAM_FILTER_READ,
                    [
                        'line-length'      => 76,
                        'line-break-chars' => $EOL
                    ]
                );
                $this->filters[Mime::ENCODING_QUOTEDPRINTABLE] = $filter;
                if (! is_resource($filter)) {
                    throw new Exception\RuntimeException('Failed to append quoted-printable filter');
                }
                break;
            case Mime::ENCODING_BASE64:
                if (array_key_exists(Mime::ENCODING_BASE64, $this->filters)) {
                    stream_filter_remove($this->filters[Mime::ENCODING_BASE64]);
                }
                $filter = stream_filter_append(
                    $this->content,
                    'convert.base64-encode',
                    STREAM_FILTER_READ,
                    [
                        'line-length'      => 76,
                        'line-break-chars' => $EOL
                    ]
                );
                $this->filters[Mime::ENCODING_BASE64] = $filter;
                if (! is_resource($filter)) {
                    throw new Exception\RuntimeException('Failed to append base64 filter');
                }
                break;
            default:
        }
        return $this->content;
    }

    /**
     * Get the Content of the current Mime Part in the given encoding.
     *
     * @param string $EOL
     * @return string
     */
    public function getContent($EOL = Mime::LINEEND)
    {
        if ($this->isStream) {
            $encodedStream         = $this->getEncodedStream($EOL);
            $encodedStreamContents = stream_get_contents($encodedStream);
            $streamMetaData        = stream_get_meta_data($encodedStream);

            if (isset($streamMetaData['seekable']) && $streamMetaData['seekable']) {
                rewind($encodedStream);
            }

            return $encodedStreamContents;
        }
        return Mime::encode($this->content, $this->encoding, $EOL);
    }

    /**
     * Get the RAW unencoded content from this part
     * @return string
     */
    public function getRawContent()
    {
        if ($this->isStream) {
            return stream_get_contents($this->content);
        }
        return $this->content;
    }

    /**
     * Create and return the array of headers for this MIME part
     *
     * @access public
     * @param string $EOL
     * @return array
     */
    public function getHeadersArray($EOL = Mime::LINEEND)
    {
        $headers = [];

        $contentType = $this->type;
        if ($this->charset) {
            $contentType .= '; charset=' . $this->charset;
        }

        if ($this->boundary) {
            $contentType .= ';' . $EOL
                          . " boundary=\"" . $this->boundary . '"';
        }

        $headers[] = ['Content-Type', $contentType];

        if ($this->encoding) {
            $headers[] = ['Content-Transfer-Encoding', $this->encoding];
        }

        if ($this->id) {
            $headers[]  = ['Content-ID', '<' . $this->id . '>'];
        }

        if ($this->disposition) {
            $disposition = $this->disposition;
            if ($this->filename) {
                $disposition .= '; filename="' . $this->filename . '"';
            }
            $headers[] = ['Content-Disposition', $disposition];
        }

        if ($this->description) {
            $headers[] = ['Content-Description', $this->description];
        }

        if ($this->location) {
            $headers[] = ['Content-Location', $this->location];
        }

        if ($this->language) {
            $headers[] = ['Content-Language', $this->language];
        }

        return $headers;
    }

    /**
     * Return the headers for this part as a string
     *
     * @param string $EOL
     * @return String
     */
    public function getHeaders($EOL = Mime::LINEEND)
    {
        $res = '';
        foreach ($this->getHeadersArray($EOL) as $header) {
            $res .= $header[0] . ': ' . $header[1] . $EOL;
        }

        return $res;
    }
}
laminas-mime/src/Exception/ExceptionInterface.php000064400000000532147361032560016141 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-mime for the canonical source repository
 * @copyright https://github.com/laminas/laminas-mime/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-mime/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Mime\Exception;

interface ExceptionInterface
{
}
laminas-mime/src/Exception/InvalidArgumentException.php000064400000000640147361032560017332 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-mime for the canonical source repository
 * @copyright https://github.com/laminas/laminas-mime/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-mime/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Mime\Exception;

class InvalidArgumentException extends \InvalidArgumentException implements
    ExceptionInterface
{
}
laminas-mime/src/Exception/RuntimeException.php000064400000000675147361032560015674 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-mime for the canonical source repository
 * @copyright https://github.com/laminas/laminas-mime/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-mime/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Mime\Exception;

/**
 * Exception for Laminas\Mime component.
 */
class RuntimeException extends \RuntimeException implements ExceptionInterface
{
}
laminas-mime/src/Decode.php000064400000021031147361032560011604 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-mime for the canonical source repository
 * @copyright https://github.com/laminas/laminas-mime/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-mime/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Mime;

use Laminas\Mail\Headers;
use Laminas\Stdlib\ErrorHandler;

class Decode
{
    /**
     * Explode MIME multipart string into separate parts
     *
     * Parts consist of the header and the body of each MIME part.
     *
     * @param  string $body     raw body of message
     * @param  string $boundary boundary as found in content-type
     * @return array parts with content of each part, empty if no parts found
     * @throws Exception\RuntimeException
     */
    public static function splitMime($body, $boundary)
    {
        // TODO: we're ignoring \r for now - is this function fast enough and is it safe to assume noone needs \r?
        $body = str_replace("\r", '', $body);

        $start = 0;
        $res = [];
        // find every mime part limiter and cut out the
        // string before it.
        // the part before the first boundary string is discarded:
        $p = strpos($body, '--' . $boundary . "\n", $start);
        if ($p === false) {
            // no parts found!
            return [];
        }

        // position after first boundary line
        $start = $p + 3 + strlen($boundary);

        while (($p = strpos($body, '--' . $boundary . "\n", $start)) !== false) {
            $res[] = substr($body, $start, $p - $start);
            $start = $p + 3 + strlen($boundary);
        }

        // no more parts, find end boundary
        $p = strpos($body, '--' . $boundary . '--', $start);
        if ($p === false) {
            throw new Exception\RuntimeException('Not a valid Mime Message: End Missing');
        }

        // the remaining part also needs to be parsed:
        $res[] = substr($body, $start, $p - $start);
        return $res;
    }

    /**
     * decodes a mime encoded String and returns a
     * struct of parts with header and body
     *
     * @param  string $message  raw message content
     * @param  string $boundary boundary as found in content-type
     * @param  string $EOL EOL string; defaults to {@link Laminas\Mime\Mime::LINEEND}
     * @return array|null parts as array('header' => array(name => value), 'body' => content), null if no parts found
     * @throws Exception\RuntimeException
     */
    public static function splitMessageStruct($message, $boundary, $EOL = Mime::LINEEND)
    {
        $parts = static::splitMime($message, $boundary);
        if (! $parts) {
            return;
        }
        $result = [];
        $headers = null; // "Declare" variable before the first usage "for reading"
        $body    = null; // "Declare" variable before the first usage "for reading"
        foreach ($parts as $part) {
            static::splitMessage($part, $headers, $body, $EOL);
            $result[] = [
                'header' => $headers,
                'body'   => $body,
            ];
        }
        return $result;
    }

    /**
     * split a message in header and body part, if no header or an
     * invalid header is found $headers is empty
     *
     * The charset of the returned headers depend on your iconv settings.
     *
     * @param  string|Headers  $message raw message with header and optional content
     * @param  Headers         $headers output param, headers container
     * @param  string          $body    output param, content of message
     * @param  string          $EOL EOL string; defaults to {@link Laminas\Mime\Mime::LINEEND}
     * @param  bool            $strict  enable strict mode for parsing message
     * @return null
     */
    public static function splitMessage($message, &$headers, &$body, $EOL = Mime::LINEEND, $strict = false)
    {
        if ($message instanceof Headers) {
            $message = $message->toString();
        }
        // check for valid header at first line
        $firstlinePos = strpos($message, "\n");
        $firstline = $firstlinePos === false ? $message : substr($message, 0, $firstlinePos);
        if (! preg_match('%^[^\s]+[^:]*:%', $firstline)) {
            $headers = new Headers();
            // TODO: we're ignoring \r for now - is this function fast enough and is it safe to assume noone needs \r?
            $body = str_replace(["\r", "\n"], ['', $EOL], $message);
            return;
        }

        // see @Laminas-372, pops the first line off a message if it doesn't contain a header
        if (! $strict) {
            $parts = explode(':', $firstline, 2);
            if (count($parts) != 2) {
                $message = substr($message, strpos($message, $EOL) + 1);
            }
        }

        // @todo splitMime removes "\r" sequences, which breaks valid mime
        // messages as returned by many mail servers
        $headersEOL = $EOL;

        // find an empty line between headers and body
        // default is set new line
        // @todo Maybe this is too much "magic"; we should be more strict here
        if (strpos($message, $EOL . $EOL)) {
            list($headers, $body) = explode($EOL . $EOL, $message, 2);
        // next is the standard new line
        } elseif ($EOL != "\r\n" && strpos($message, "\r\n\r\n")) {
            list($headers, $body) = explode("\r\n\r\n", $message, 2);
            $headersEOL = "\r\n"; // Headers::fromString will fail with incorrect EOL
        // next is the other "standard" new line
        } elseif ($EOL != "\n" && strpos($message, "\n\n")) {
            list($headers, $body) = explode("\n\n", $message, 2);
            $headersEOL = "\n";
        // at last resort find anything that looks like a new line
        } else {
            ErrorHandler::start(E_NOTICE | E_WARNING);
            list($headers, $body) = preg_split("%([\r\n]+)\\1%U", $message, 2);
            ErrorHandler::stop();
        }

        $headers = Headers::fromString($headers, $headersEOL);
    }

    /**
     * split a content type in its different parts
     *
     * @param  string $type       content-type
     * @param  string $wantedPart the wanted part, else an array with all parts is returned
     * @return string|array wanted part or all parts as array('type' => content-type, partname => value)
     */
    public static function splitContentType($type, $wantedPart = null)
    {
        return static::splitHeaderField($type, $wantedPart, 'type');
    }

    /**
     * split a header field like content type in its different parts
     *
     * @param  string $field      header field
     * @param  string $wantedPart the wanted part, else an array with all parts is returned
     * @param  string $firstName  key name for the first part
     * @return string|array wanted part or all parts as array($firstName => firstPart, partname => value)
     * @throws Exception\RuntimeException
     */
    public static function splitHeaderField($field, $wantedPart = null, $firstName = '0')
    {
        $wantedPart = strtolower($wantedPart);
        $firstName = strtolower($firstName);

        // special case - a bit optimized
        if ($firstName === $wantedPart) {
            $field = strtok($field, ';');
            return $field[0] == '"' ? substr($field, 1, -1) : $field;
        }

        $field = $firstName . '=' . $field;
        if (! preg_match_all('%([^=\s]+)\s*=\s*("[^"]+"|[^;]+)(;\s*|$)%', $field, $matches)) {
            throw new Exception\RuntimeException('not a valid header field');
        }

        if ($wantedPart) {
            foreach ($matches[1] as $key => $name) {
                if (strcasecmp($name, $wantedPart)) {
                    continue;
                }
                if ($matches[2][$key][0] != '"') {
                    return $matches[2][$key];
                }
                return substr($matches[2][$key], 1, -1);
            }
            return;
        }

        $split = [];
        foreach ($matches[1] as $key => $name) {
            $name = strtolower($name);
            if ($matches[2][$key][0] == '"') {
                $split[$name] = substr($matches[2][$key], 1, -1);
            } else {
                $split[$name] = $matches[2][$key];
            }
        }

        return $split;
    }

    /**
     * decode a quoted printable encoded string
     *
     * The charset of the returned string depends on your iconv settings.
     *
     * @param  string $string encoded string
     * @return string decoded string
     */
    public static function decodeQuotedPrintable($string)
    {
        return iconv_mime_decode($string, ICONV_MIME_DECODE_CONTINUE_ON_ERROR, 'UTF-8');
    }
}
laminas-mime/README.md000064400000001520147361032560010401 0ustar00# laminas-mime

[![Build Status](https://travis-ci.com/laminas/laminas-mime.svg?branch=master)](https://travis-ci.com/laminas/laminas-mime)
[![Coverage Status](https://coveralls.io/repos/github/laminas/laminas-mime/badge.svg?branch=master)](https://coveralls.io/github/laminas/laminas-mime?branch=master)

`Laminas\Mime` is a support class for handling multipart MIME messages. It is used
by `Laminas\Mail` and `Laminas\Mime\Message` and may be used by applications requiring
MIME support.

## Installation

Run the following to install this library:

```bash
$ composer require laminas/laminas-mime
```

## Documentation

Browse the documentation online at https://docs.laminas.dev/laminas-mime/

## Support

* [Issues](https://github.com/laminas/laminas-mime/issues/)
* [Chat](https://laminas.dev/chat/)
* [Forum](https://discourse.laminas.dev/)
laminas-mime/CHANGELOG.md000064400000012200147361032560010730 0ustar00# Changelog

All notable changes to this project will be documented in this file, in reverse chronological order by release.

## 2.7.4 - 2020-03-29

### Added

- Nothing.

### Changed

- Nothing.

### Deprecated

- Nothing.

### Removed

- Nothing.

### Fixed

- Fixed `replace` version constraint in composer.json so repository can be used as replacement of `zendframework/zend-mime:^2.7.2`.

## 2.7.3 - 2020-03-06

### Added

- Nothing.

### Changed

- Nothing.

### Deprecated

- Nothing.

### Removed

- Nothing.

### Fixed

- [#10](https://github.com/laminas/laminas-mime/pull/10) improves implementation of `Mime::encodeQuotedPrintable()` for big strings by avoiding copying of the whole string in the loop.

## 2.7.2 - 2019-10-16

### Added

- [zendframework/zend-mime#37](https://github.com/zendframework/zend-mime/pull/37) adds support for PHP 7.3.

### Changed

- Nothing.

### Deprecated

- Nothing.

### Removed

- Nothing.

### Fixed

- [zendframework/zend-mime#36](https://github.com/zendframework/zend-mime/pull/36) fixes
  `Laminas\Mime\Decode::splitMessage` to set `Laminas\Mail\Headers`
  instance always for `$headers` parameter. Before, when messages
  without headers was provided, `$headers` was an empty array.

## 2.7.1 - 2018-05-14

### Added

- Nothing.

### Changed

- Nothing.

### Deprecated

- Nothing.

### Removed

- Nothing.

### Fixed

- [zendframework/zend-mime#32](https://github.com/zendframework/zend-mime/pull/32) corrects a potential infinite loop when parsing lines consisting of only spaces and dots.

## 2.7.0 - 2017-11-28

### Added

- [zendframework/zend-mime#27](https://github.com/zendframework/zend-mime/pull/27) adds a fluent
  interface to the various setters in `Laminas\Mime\Message`.

- [zendframework/zend-mime#28](https://github.com/zendframework/zend-mime/pull/28) adds support for PHP
  versions 7.1 and 7.2.

### Deprecated

- Nothing.

### Removed

- [zendframework/zend-mime#28](https://github.com/zendframework/zend-mime/pull/28) removes support for
  PHP 5.5.

- [zendframework/zend-mime#28](https://github.com/zendframework/zend-mime/pull/28) removes support for
  HHVM.

### Fixed

- [zendframework/zend-mime#26](https://github.com/zendframework/zend-mime/pull/26) ensures commas
  included within list data items are ASCII encoded, ensuring that the items
  will split on commas correctly (instead of splitting within an item).

- [zendframework/zend-mime#30](https://github.com/zendframework/zend-mime/pull/30) fixes how EOL
  characters are detected, to ensure that mail using `\r\n` as an EOL sequence
  (including mail emitted by Cyrus and Dovecot) will be properly parsed.

## 2.6.1 - 2017-01-16

### Added

- [zendframework/zend-mime#22](https://github.com/zendframework/zend-mime/pull/22) adds the ability to
  decode a single-part MIME message via `Laminas\Mime\Message::createFromMessage()`
  by omitting the `$boundary` argument.

### Changes

- [zendframework/zend-mime#14](https://github.com/zendframework/zend-mime/pull/14) adds checks for
  duplicate parts when adding them to a MIME message, and now throws an
  `InvalidArgumentException` when detected.

### Deprecated

- Nothing.

### Removed

- Nothing.

### Fixed

- [zendframework/zend-mime#13](https://github.com/zendframework/zend-mime/pull/13) fixes issues with
  qp-octets produced by Outlook.
- [zendframework/zend-mime#17](https://github.com/zendframework/zend-mime/pull/17) fixes a syntax error
  in how are thrown by `Laminas\Mime\Part::setContent()`.
- [zendframework/zend-mime#18](https://github.com/zendframework/zend-mime/pull/18) fixes how non-ASCII
  header values are encoded, ensuring that it allows the first word to be of
  arbitrary length.

## 2.6.0 - 2016-04-20

### Added

- [zendframework/zend-mime#6](https://github.com/zendframework/zend-mime/pull/6) adds
  `Mime::mimeDetectCharset()`, which can be used to detect the charset
  of a given string (usually a header) according to the rules specified in
  RFC-2047.

### Deprecated

- Nothing.

### Removed

- Nothing.

### Fixed

- Nothing.

## 2.5.2 - 2016-04-20

### Added

- [zendframework/zend-mime#8](https://github.com/zendframework/zend-mime/pull/8) and
  [zendframework/zend-mime#11](https://github.com/zendframework/zend-mime/pull/11) port documentation
  from the api-tools-documentation repo, and publish it to
  https://docs.laminas.dev/laminas-mime/

### Deprecated

- Nothing.

### Removed

- Nothing.

### Fixed

- [zendframework/zend-mime#2](https://github.com/zendframework/zend-mime/pull/2) fixes
  `Mime::encodeBase64()`'s behavior when presented with lines of invalid
  lengths (not multiples of 4).
- [zendframework/zend-mime#4](https://github.com/zendframework/zend-mime/pull/4) modifies
  `Mime::encodeQuotedPrintable()` to ensure it never creates a header line
  consisting of only a dot (concatenation character), a situation that can break
  parsing by Outlook.
- [zendframework/zend-mime#7](https://github.com/zendframework/zend-mime/pull/7) provides a patch that
  allows parsing MIME parts that have no headers.
- [zendframework/zend-mime#9](https://github.com/zendframework/zend-mime/pull/9) updates the
  dependencies to:
  - allow PHP 5.5+ or PHP 7+ versions.
  - allow laminas-stdlib 2.7+ or 3.0+ verions.
laminas-mime/LICENSE.md000064400000002732147361032560010534 0ustar00Copyright (c) 2019-2020, Laminas Foundation
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

- Redistributions of source code must retain the above copyright notice, this
  list of conditions and the following disclaimer.

- Redistributions in binary form must reproduce the above copyright notice,
  this list of conditions and the following disclaimer in the documentation
  and/or other materials provided with the distribution.

- Neither the name of Laminas Foundation nor the names of its contributors may
  be used to endorse or promote products derived from this software without
  specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
laminas-stdlib/COPYRIGHT.md000064400000000133147361032560011345 0ustar00Copyright (c) 2020 Laminas Project a Series of LF Projects, LLC. (https://getlaminas.org/)
laminas-stdlib/src/PriorityList.php000064400000012500147361032560013431 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-stdlib for the canonical source repository
 * @copyright https://github.com/laminas/laminas-stdlib/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-stdlib/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Stdlib;

use Countable;
use Iterator;

use function array_map;
use function current;
use function key;
use function next;
use function reset;
use function uasort;

class PriorityList implements Iterator, Countable
{
    const EXTR_DATA     = 0x00000001;
    const EXTR_PRIORITY = 0x00000002;
    const EXTR_BOTH     = 0x00000003;
    /**
     * Internal list of all items.
     *
     * @var array[]
     */
    protected $items = [];

    /**
     * Serial assigned to items to preserve LIFO.
     *
     * @var int
     */
    protected $serial = 0;

    /**
     * Serial order mode
     * @var integer
     */
    protected $isLIFO = 1;

    /**
     * Internal counter to avoid usage of count().
     *
     * @var int
     */
    protected $count = 0;

    /**
     * Whether the list was already sorted.
     *
     * @var bool
     */
    protected $sorted = false;

    /**
     * Insert a new item.
     *
     * @param  string  $name
     * @param  mixed   $value
     * @param  int     $priority
     *
     * @return void
     */
    public function insert($name, $value, $priority = 0)
    {
        if (! isset($this->items[$name])) {
            $this->count++;
        }

        $this->sorted = false;

        $this->items[$name] = [
            'data'     => $value,
            'priority' => (int) $priority,
            'serial'   => $this->serial++,
        ];
    }

    /**
     * @param string $name
     * @param int    $priority
     *
     * @return $this
     *
     * @throws \Exception
     */
    public function setPriority($name, $priority)
    {
        if (! isset($this->items[$name])) {
            throw new \Exception("item $name not found");
        }

        $this->items[$name]['priority'] = (int) $priority;
        $this->sorted                   = false;

        return $this;
    }

    /**
     * Remove a item.
     *
     * @param  string $name
     * @return void
     */
    public function remove($name)
    {
        if (isset($this->items[$name])) {
            $this->count--;
        }

        unset($this->items[$name]);
    }

    /**
     * Remove all items.
     *
     * @return void
     */
    public function clear()
    {
        $this->items  = [];
        $this->serial = 0;
        $this->count  = 0;
        $this->sorted = false;
    }

    /**
     * Get a item.
     *
     * @param  string $name
     * @return mixed
     */
    public function get($name)
    {
        if (! isset($this->items[$name])) {
            return;
        }

        return $this->items[$name]['data'];
    }

    /**
     * Sort all items.
     *
     * @return void
     */
    protected function sort()
    {
        if (! $this->sorted) {
            uasort($this->items, [$this, 'compare']);
            $this->sorted = true;
        }
    }

    /**
     * Compare the priority of two items.
     *
     * @param  array $item1,
     * @param  array $item2
     * @return int
     */
    protected function compare(array $item1, array $item2)
    {
        return ($item1['priority'] === $item2['priority'])
            ? ($item1['serial'] > $item2['serial'] ? -1 : 1) * $this->isLIFO
            : ($item1['priority'] > $item2['priority'] ? -1 : 1);
    }

    /**
     * Get/Set serial order mode
     *
     * @param bool|null $flag
     *
     * @return bool
     */
    public function isLIFO($flag = null)
    {
        if ($flag !== null) {
            $isLifo = $flag === true ? 1 : -1;

            if ($isLifo !== $this->isLIFO) {
                $this->isLIFO = $isLifo;
                $this->sorted = false;
            }
        }

        return 1 === $this->isLIFO;
    }

    /**
     * {@inheritDoc}
     */
    public function rewind()
    {
        $this->sort();
        reset($this->items);
    }

    /**
     * {@inheritDoc}
     */
    public function current()
    {
        $this->sorted || $this->sort();
        $node = current($this->items);

        return $node ? $node['data'] : false;
    }

    /**
     * {@inheritDoc}
     */
    public function key()
    {
        $this->sorted || $this->sort();
        return key($this->items);
    }

    /**
     * {@inheritDoc}
     */
    public function next()
    {
        $node = next($this->items);

        return $node ? $node['data'] : false;
    }

    /**
     * {@inheritDoc}
     */
    public function valid()
    {
        return current($this->items) !== false;
    }

    /**
     * @return self
     */
    public function getIterator()
    {
        return clone $this;
    }

    /**
     * {@inheritDoc}
     */
    public function count()
    {
        return $this->count;
    }

    /**
     * Return list as array
     *
     * @param int $flag
     *
     * @return array
     */
    public function toArray($flag = self::EXTR_DATA)
    {
        $this->sort();

        if ($flag == self::EXTR_BOTH) {
            return $this->items;
        }

        return array_map(
            function ($item) use ($flag) {
                return ($flag == PriorityList::EXTR_PRIORITY) ? $item['priority'] : $item['data'];
            },
            $this->items
        );
    }
}
laminas-stdlib/src/Guard/AllGuardsTrait.php000064400000000732147361032560014704 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-stdlib for the canonical source repository
 * @copyright https://github.com/laminas/laminas-stdlib/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-stdlib/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Stdlib\Guard;

/**
 * An aggregate for all guard traits
 */
trait AllGuardsTrait
{
    use ArrayOrTraversableGuardTrait;
    use EmptyGuardTrait;
    use NullGuardTrait;
}
laminas-stdlib/src/Guard/EmptyGuardTrait.php000064400000001764147361032560015115 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-stdlib for the canonical source repository
 * @copyright https://github.com/laminas/laminas-stdlib/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-stdlib/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Stdlib\Guard;

use function sprintf;

/**
 * Provide a guard method against empty data
 */
trait EmptyGuardTrait
{
    /**
     * Verify that the data is not empty
     *
     * @param  mixed  $data           the data to verify
     * @param  string $dataName       the data name
     * @param  string $exceptionClass FQCN for the exception
     * @throws \Exception
     */
    protected function guardAgainstEmpty(
        $data,
        $dataName = 'Argument',
        $exceptionClass = 'Laminas\Stdlib\Exception\InvalidArgumentException'
    ) {
        if (empty($data)) {
            $message = sprintf('%s cannot be empty', $dataName);
            throw new $exceptionClass($message);
        }
    }
}
laminas-stdlib/src/Guard/ArrayOrTraversableGuardTrait.php000064400000002515147361032560017564 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-stdlib for the canonical source repository
 * @copyright https://github.com/laminas/laminas-stdlib/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-stdlib/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Stdlib\Guard;

use Traversable;

use function get_class;
use function gettype;
use function is_array;
use function is_object;
use function sprintf;

/**
 * Provide a guard method for array or Traversable data
 */
trait ArrayOrTraversableGuardTrait
{
    /**
     * Verifies that the data is an array or Traversable
     *
     * @param  mixed  $data           the data to verify
     * @param  string $dataName       the data name
     * @param  string $exceptionClass FQCN for the exception
     * @throws \Exception
     */
    protected function guardForArrayOrTraversable(
        $data,
        $dataName = 'Argument',
        $exceptionClass = 'Laminas\Stdlib\Exception\InvalidArgumentException'
    ) {
        if (! is_array($data) && ! ($data instanceof Traversable)) {
            $message = sprintf(
                "%s must be an array or Traversable, [%s] given",
                $dataName,
                is_object($data) ? get_class($data) : gettype($data)
            );
            throw new $exceptionClass($message);
        }
    }
}
laminas-stdlib/src/Guard/NullGuardTrait.php000064400000001761147361032560014726 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-stdlib for the canonical source repository
 * @copyright https://github.com/laminas/laminas-stdlib/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-stdlib/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Stdlib\Guard;

use function sprintf;

/**
 * Provide a guard method against null data
 */
trait NullGuardTrait
{
    /**
     * Verify that the data is not null
     *
     * @param  mixed  $data           the data to verify
     * @param  string $dataName       the data name
     * @param  string $exceptionClass FQCN for the exception
     * @throws \Exception
     */
    protected function guardAgainstNull(
        $data,
        $dataName = 'Argument',
        $exceptionClass = 'Laminas\Stdlib\Exception\InvalidArgumentException'
    ) {
        if (null === $data) {
            $message = sprintf('%s cannot be null', $dataName);
            throw new $exceptionClass($message);
        }
    }
}
laminas-stdlib/src/InitializableInterface.php000064400000000774147361032560015367 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-stdlib for the canonical source repository
 * @copyright https://github.com/laminas/laminas-stdlib/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-stdlib/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Stdlib;

/**
 * Interface to allow objects to have initialization logic
 */
interface InitializableInterface
{
    /**
     * Init an object
     *
     * @return void
     */
    public function init();
}
laminas-stdlib/src/ArraySerializableInterface.php000064400000001221147361032560016200 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-stdlib for the canonical source repository
 * @copyright https://github.com/laminas/laminas-stdlib/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-stdlib/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Stdlib;

interface ArraySerializableInterface
{
    /**
     * Exchange internal values from provided array
     *
     * @param  array $array
     * @return void
     */
    public function exchangeArray(array $array);

    /**
     * Return an array representation of the object
     *
     * @return array
     */
    public function getArrayCopy();
}
laminas-stdlib/src/ErrorHandler.php000064400000005244147361032560013352 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-stdlib for the canonical source repository
 * @copyright https://github.com/laminas/laminas-stdlib/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-stdlib/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Stdlib;

use ErrorException;

use function array_pop;
use function count;
use function get_called_class;
use function restore_error_handler;
use function set_error_handler;

use const E_WARNING;

/**
 * ErrorHandler that can be used to catch internal PHP errors
 * and convert to an ErrorException instance.
 */
abstract class ErrorHandler
{
    /**
     * Active stack
     *
     * @var array
     */
    protected static $stack = [];

    /**
     * Check if this error handler is active
     *
     * @return bool
     */
    public static function started()
    {
        return (bool) static::getNestedLevel();
    }

    /**
     * Get the current nested level
     *
     * @return int
     */
    public static function getNestedLevel()
    {
        return count(static::$stack);
    }

    /**
     * Starting the error handler
     *
     * @param int $errorLevel
     */
    public static function start($errorLevel = E_WARNING)
    {
        if (! static::$stack) {
            set_error_handler([get_called_class(), 'addError'], $errorLevel);
        }

        static::$stack[] = null;
    }

    /**
     * Stopping the error handler
     *
     * @param  bool $throw Throw the ErrorException if any
     * @return null|ErrorException
     * @throws ErrorException If an error has been caught and $throw is true
     */
    public static function stop($throw = false)
    {
        $errorException = null;

        if (static::$stack) {
            $errorException = array_pop(static::$stack);

            if (! static::$stack) {
                restore_error_handler();
            }

            if ($errorException && $throw) {
                throw $errorException;
            }
        }

        return $errorException;
    }

    /**
     * Stop all active handler
     *
     * @return void
     */
    public static function clean()
    {
        if (static::$stack) {
            restore_error_handler();
        }

        static::$stack = [];
    }

    /**
     * Add an error to the stack
     *
     * @param int    $errno
     * @param string $errstr
     * @param string $errfile
     * @param int    $errline
     * @return void
     */
    public static function addError($errno, $errstr = '', $errfile = '', $errline = 0)
    {
        $stack = & static::$stack[count(static::$stack) - 1];
        $stack = new ErrorException($errstr, 0, $errno, $errfile, $errline, $stack);
    }
}
laminas-stdlib/src/Message.php000064400000005763147361032560012355 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-stdlib for the canonical source repository
 * @copyright https://github.com/laminas/laminas-stdlib/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-stdlib/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Stdlib;

use Traversable;

use function array_key_exists;
use function get_class;
use function gettype;
use function is_array;
use function is_object;
use function is_scalar;
use function sprintf;

class Message implements MessageInterface
{
    /**
     * @var array
     */
    protected $metadata = [];

    /**
     * @var mixed
     */
    protected $content = '';

    /**
     * Set message metadata
     *
     * Non-destructive setting of message metadata; always adds to the metadata, never overwrites
     * the entire metadata container.
     *
     * @param  string|int|array|Traversable $spec
     * @param  mixed $value
     * @throws Exception\InvalidArgumentException
     * @return Message
     */
    public function setMetadata($spec, $value = null)
    {
        if (is_scalar($spec)) {
            $this->metadata[$spec] = $value;
            return $this;
        }
        if (! is_array($spec) && ! $spec instanceof Traversable) {
            throw new Exception\InvalidArgumentException(sprintf(
                'Expected a string, array, or Traversable argument in first position; received "%s"',
                (is_object($spec) ? get_class($spec) : gettype($spec))
            ));
        }
        foreach ($spec as $key => $value) {
            $this->metadata[$key] = $value;
        }
        return $this;
    }

    /**
     * Retrieve all metadata or a single metadatum as specified by key
     *
     * @param  null|string|int $key
     * @param  null|mixed $default
     * @throws Exception\InvalidArgumentException
     * @return mixed
     */
    public function getMetadata($key = null, $default = null)
    {
        if (null === $key) {
            return $this->metadata;
        }

        if (! is_scalar($key)) {
            throw new Exception\InvalidArgumentException('Non-scalar argument provided for key');
        }

        if (array_key_exists($key, $this->metadata)) {
            return $this->metadata[$key];
        }

        return $default;
    }

    /**
     * Set message content
     *
     * @param  mixed $value
     * @return Message
     */
    public function setContent($value)
    {
        $this->content = $value;
        return $this;
    }

    /**
     * Get message content
     *
     * @return mixed
     */
    public function getContent()
    {
        return $this->content;
    }

    /**
     * @return string
     */
    public function toString()
    {
        $request = '';
        foreach ($this->getMetadata() as $key => $value) {
            $request .= sprintf(
                "%s: %s\r\n",
                (string) $key,
                (string) $value
            );
        }
        $request .= "\r\n" . $this->getContent();
        return $request;
    }
}
laminas-stdlib/src/ArrayObject.php000064400000023470147361032560013171 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-stdlib for the canonical source repository
 * @copyright https://github.com/laminas/laminas-stdlib/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-stdlib/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Stdlib;

use ArrayAccess;
use Countable;
use IteratorAggregate;
use Serializable;

use function array_keys;
use function asort;
use function class_exists;
use function count;
use function get_object_vars;
use function in_array;
use function is_array;
use function is_callable;
use function is_object;
use function ksort;
use function natcasesort;
use function natsort;
use function serialize;
use function strpos;
use function uasort;
use function uksort;
use function unserialize;

/**
 * Custom framework ArrayObject implementation
 *
 * Extends version-specific "abstract" implementation.
 */
class ArrayObject implements IteratorAggregate, ArrayAccess, Serializable, Countable
{
    /**
     * Properties of the object have their normal functionality
     * when accessed as list (var_dump, foreach, etc.).
     */
    const STD_PROP_LIST = 1;

    /**
     * Entries can be accessed as properties (read and write).
     */
    const ARRAY_AS_PROPS = 2;

    /**
     * @var array
     */
    protected $storage;

    /**
     * @var int
     */
    protected $flag;

    /**
     * @var string
     */
    protected $iteratorClass;

    /**
     * @var array
     */
    protected $protectedProperties;

    /**
     * Constructor
     *
     * @param array  $input
     * @param int    $flags
     * @param string $iteratorClass
     */
    public function __construct($input = [], $flags = self::STD_PROP_LIST, $iteratorClass = 'ArrayIterator')
    {
        $this->setFlags($flags);
        $this->storage = $input;
        $this->setIteratorClass($iteratorClass);
        $this->protectedProperties = array_keys(get_object_vars($this));
    }

    /**
     * Returns whether the requested key exists
     *
     * @param  mixed $key
     * @return bool
     */
    public function __isset($key)
    {
        if ($this->flag == self::ARRAY_AS_PROPS) {
            return $this->offsetExists($key);
        }
        if (in_array($key, $this->protectedProperties)) {
            throw new Exception\InvalidArgumentException('$key is a protected property, use a different key');
        }

        return isset($this->$key);
    }

    /**
     * Sets the value at the specified key to value
     *
     * @param  mixed $key
     * @param  mixed $value
     * @return void
     */
    public function __set($key, $value)
    {
        if ($this->flag == self::ARRAY_AS_PROPS) {
            return $this->offsetSet($key, $value);
        }
        if (in_array($key, $this->protectedProperties)) {
            throw new Exception\InvalidArgumentException('$key is a protected property, use a different key');
        }
        $this->$key = $value;
    }

    /**
     * Unsets the value at the specified key
     *
     * @param  mixed $key
     * @return void
     */
    public function __unset($key)
    {
        if ($this->flag == self::ARRAY_AS_PROPS) {
            return $this->offsetUnset($key);
        }
        if (in_array($key, $this->protectedProperties)) {
            throw new Exception\InvalidArgumentException('$key is a protected property, use a different key');
        }
        unset($this->$key);
    }

    /**
     * Returns the value at the specified key by reference
     *
     * @param  mixed $key
     * @return mixed
     */
    public function &__get($key)
    {
        $ret = null;
        if ($this->flag == self::ARRAY_AS_PROPS) {
            $ret =& $this->offsetGet($key);

            return $ret;
        }
        if (in_array($key, $this->protectedProperties)) {
            throw new Exception\InvalidArgumentException('$key is a protected property, use a different key');
        }

        return $this->$key;
    }

    /**
     * Appends the value
     *
     * @param  mixed $value
     * @return void
     */
    public function append($value)
    {
        $this->storage[] = $value;
    }

    /**
     * Sort the entries by value
     *
     * @return void
     */
    public function asort()
    {
        asort($this->storage);
    }

    /**
     * Get the number of public properties in the ArrayObject
     *
     * @return int
     */
    public function count()
    {
        return count($this->storage);
    }

    /**
     * Exchange the array for another one.
     *
     * @param  array|ArrayObject $data
     * @return array
     */
    public function exchangeArray($data)
    {
        if (! is_array($data) && ! is_object($data)) {
            throw new Exception\InvalidArgumentException(
                'Passed variable is not an array or object, using empty array instead'
            );
        }

        if (is_object($data) && ($data instanceof self || $data instanceof \ArrayObject)) {
            $data = $data->getArrayCopy();
        }
        if (! is_array($data)) {
            $data = (array) $data;
        }

        $storage = $this->storage;

        $this->storage = $data;

        return $storage;
    }

    /**
     * Creates a copy of the ArrayObject.
     *
     * @return array
     */
    public function getArrayCopy()
    {
        return $this->storage;
    }

    /**
     * Gets the behavior flags.
     *
     * @return int
     */
    public function getFlags()
    {
        return $this->flag;
    }

    /**
     * Create a new iterator from an ArrayObject instance
     *
     * @return \Iterator
     */
    public function getIterator()
    {
        $class = $this->iteratorClass;

        return new $class($this->storage);
    }

    /**
     * Gets the iterator classname for the ArrayObject.
     *
     * @return string
     */
    public function getIteratorClass()
    {
        return $this->iteratorClass;
    }

    /**
     * Sort the entries by key
     *
     * @return void
     */
    public function ksort()
    {
        ksort($this->storage);
    }

    /**
     * Sort an array using a case insensitive "natural order" algorithm
     *
     * @return void
     */
    public function natcasesort()
    {
        natcasesort($this->storage);
    }

    /**
     * Sort entries using a "natural order" algorithm
     *
     * @return void
     */
    public function natsort()
    {
        natsort($this->storage);
    }

    /**
     * Returns whether the requested key exists
     *
     * @param  mixed $key
     * @return bool
     */
    public function offsetExists($key)
    {
        return isset($this->storage[$key]);
    }

    /**
     * Returns the value at the specified key
     *
     * @param  mixed $key
     * @return mixed
     */
    public function &offsetGet($key)
    {
        $ret = null;
        if (! $this->offsetExists($key)) {
            return $ret;
        }
        $ret =& $this->storage[$key];

        return $ret;
    }

    /**
     * Sets the value at the specified key to value
     *
     * @param  mixed $key
     * @param  mixed $value
     * @return void
     */
    public function offsetSet($key, $value)
    {
        $this->storage[$key] = $value;
    }

    /**
     * Unsets the value at the specified key
     *
     * @param  mixed $key
     * @return void
     */
    public function offsetUnset($key)
    {
        if ($this->offsetExists($key)) {
            unset($this->storage[$key]);
        }
    }

    /**
     * Serialize an ArrayObject
     *
     * @return string
     */
    public function serialize()
    {
        return serialize(get_object_vars($this));
    }

    /**
     * Sets the behavior flags
     *
     * @param  int  $flags
     * @return void
     */
    public function setFlags($flags)
    {
        $this->flag = $flags;
    }

    /**
     * Sets the iterator classname for the ArrayObject
     *
     * @param  string $class
     * @return void
     */
    public function setIteratorClass($class)
    {
        if (class_exists($class)) {
            $this->iteratorClass = $class;

            return ;
        }

        if (strpos($class, '\\') === 0) {
            $class = '\\' . $class;
            if (class_exists($class)) {
                $this->iteratorClass = $class;

                return ;
            }
        }

        throw new Exception\InvalidArgumentException('The iterator class does not exist');
    }

    /**
     * Sort the entries with a user-defined comparison function and maintain key association
     *
     * @param  callable $function
     * @return void
     */
    public function uasort($function)
    {
        if (is_callable($function)) {
            uasort($this->storage, $function);
        }
    }

    /**
     * Sort the entries by keys using a user-defined comparison function
     *
     * @param  callable $function
     * @return void
     */
    public function uksort($function)
    {
        if (is_callable($function)) {
            uksort($this->storage, $function);
        }
    }

    /**
     * Unserialize an ArrayObject
     *
     * @param  string $data
     * @return void
     */
    public function unserialize($data)
    {
        $ar                        = unserialize($data);
        $this->protectedProperties = array_keys(get_object_vars($this));

        $this->setFlags($ar['flag']);
        $this->exchangeArray($ar['storage']);
        $this->setIteratorClass($ar['iteratorClass']);

        foreach ($ar as $k => $v) {
            switch ($k) {
                case 'flag':
                    $this->setFlags($v);
                    break;
                case 'storage':
                    $this->exchangeArray($v);
                    break;
                case 'iteratorClass':
                    $this->setIteratorClass($v);
                    break;
                case 'protectedProperties':
                    break;
                default:
                    $this->__set($k, $v);
            }
        }
    }
}
laminas-stdlib/src/PriorityQueue.php000064400000017511147361032560013611 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-stdlib for the canonical source repository
 * @copyright https://github.com/laminas/laminas-stdlib/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-stdlib/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Stdlib;

use Countable;
use IteratorAggregate;
use Serializable;

use function array_map;
use function count;
use function get_class;
use function serialize;
use function sprintf;
use function unserialize;

/**
 * Re-usable, serializable priority queue implementation
 *
 * SplPriorityQueue acts as a heap; on iteration, each item is removed from the
 * queue. If you wish to re-use such a queue, you need to clone it first. This
 * makes for some interesting issues if you wish to delete items from the queue,
 * or, as already stated, iterate over it multiple times.
 *
 * This class aggregates items for the queue itself, but also composes an
 * "inner" iterator in the form of an SplPriorityQueue object for performing
 * the actual iteration.
 */
class PriorityQueue implements Countable, IteratorAggregate, Serializable
{
    const EXTR_DATA     = 0x00000001;
    const EXTR_PRIORITY = 0x00000002;
    const EXTR_BOTH     = 0x00000003;

    /**
     * Inner queue class to use for iteration
     * @var string
     */
    protected $queueClass = 'Laminas\Stdlib\SplPriorityQueue';

    /**
     * Actual items aggregated in the priority queue. Each item is an array
     * with keys "data" and "priority".
     * @var array
     */
    protected $items      = [];

    /**
     * Inner queue object
     * @var SplPriorityQueue
     */
    protected $queue;

    /**
     * Insert an item into the queue
     *
     * Priority defaults to 1 (low priority) if none provided.
     *
     * @param  mixed $data
     * @param  int $priority
     * @return PriorityQueue
     */
    public function insert($data, $priority = 1)
    {
        $priority = (int) $priority;
        $this->items[] = [
            'data'     => $data,
            'priority' => $priority,
        ];
        $this->getQueue()->insert($data, $priority);
        return $this;
    }

    /**
     * Remove an item from the queue
     *
     * This is different than {@link extract()}; its purpose is to dequeue an
     * item.
     *
     * This operation is potentially expensive, as it requires
     * re-initialization and re-population of the inner queue.
     *
     * Note: this removes the first item matching the provided item found. If
     * the same item has been added multiple times, it will not remove other
     * instances.
     *
     * @param  mixed $datum
     * @return bool False if the item was not found, true otherwise.
     */
    public function remove($datum)
    {
        $found = false;
        foreach ($this->items as $key => $item) {
            if ($item['data'] === $datum) {
                $found = true;
                break;
            }
        }
        if ($found) {
            unset($this->items[$key]);
            $this->queue = null;

            if (! $this->isEmpty()) {
                $queue = $this->getQueue();
                foreach ($this->items as $item) {
                    $queue->insert($item['data'], $item['priority']);
                }
            }
            return true;
        }
        return false;
    }

    /**
     * Is the queue empty?
     *
     * @return bool
     */
    public function isEmpty()
    {
        return (0 === $this->count());
    }

    /**
     * How many items are in the queue?
     *
     * @return int
     */
    public function count()
    {
        return count($this->items);
    }

    /**
     * Peek at the top node in the queue, based on priority.
     *
     * @return mixed
     */
    public function top()
    {
        return $this->getIterator()->top();
    }

    /**
     * Extract a node from the inner queue and sift up
     *
     * @return mixed
     */
    public function extract()
    {
        return $this->getQueue()->extract();
    }

    /**
     * Retrieve the inner iterator
     *
     * SplPriorityQueue acts as a heap, which typically implies that as items
     * are iterated, they are also removed. This does not work for situations
     * where the queue may be iterated multiple times. As such, this class
     * aggregates the values, and also injects an SplPriorityQueue. This method
     * retrieves the inner queue object, and clones it for purposes of
     * iteration.
     *
     * @return SplPriorityQueue
     */
    public function getIterator()
    {
        $queue = $this->getQueue();
        return clone $queue;
    }

    /**
     * Serialize the data structure
     *
     * @return string
     */
    public function serialize()
    {
        return serialize($this->items);
    }

    /**
     * Unserialize a string into a PriorityQueue object
     *
     * Serialization format is compatible with {@link Laminas\Stdlib\SplPriorityQueue}
     *
     * @param  string $data
     * @return void
     */
    public function unserialize($data)
    {
        foreach (unserialize($data) as $item) {
            $this->insert($item['data'], $item['priority']);
        }
    }

    /**
     * Serialize to an array
     *
     * By default, returns only the item data, and in the order registered (not
     * sorted). You may provide one of the EXTR_* flags as an argument, allowing
     * the ability to return priorities or both data and priority.
     *
     * @param  int $flag
     * @return array
     */
    public function toArray($flag = self::EXTR_DATA)
    {
        switch ($flag) {
            case self::EXTR_BOTH:
                return $this->items;
            case self::EXTR_PRIORITY:
                return array_map(function ($item) {
                    return $item['priority'];
                }, $this->items);
            case self::EXTR_DATA:
            default:
                return array_map(function ($item) {
                    return $item['data'];
                }, $this->items);
        }
    }

    /**
     * Specify the internal queue class
     *
     * Please see {@link getIterator()} for details on the necessity of an
     * internal queue class. The class provided should extend SplPriorityQueue.
     *
     * @param  string $class
     * @return PriorityQueue
     */
    public function setInternalQueueClass($class)
    {
        $this->queueClass = (string) $class;
        return $this;
    }

    /**
     * Does the queue contain the given datum?
     *
     * @param  mixed $datum
     * @return bool
     */
    public function contains($datum)
    {
        foreach ($this->items as $item) {
            if ($item['data'] === $datum) {
                return true;
            }
        }
        return false;
    }

    /**
     * Does the queue have an item with the given priority?
     *
     * @param  int $priority
     * @return bool
     */
    public function hasPriority($priority)
    {
        foreach ($this->items as $item) {
            if ($item['priority'] === $priority) {
                return true;
            }
        }
        return false;
    }

    /**
     * Get the inner priority queue instance
     *
     * @throws Exception\DomainException
     * @return SplPriorityQueue
     */
    protected function getQueue()
    {
        if (null === $this->queue) {
            $this->queue = new $this->queueClass();
            if (! $this->queue instanceof \SplPriorityQueue) {
                throw new Exception\DomainException(sprintf(
                    'PriorityQueue expects an internal queue of type SplPriorityQueue; received "%s"',
                    get_class($this->queue)
                ));
            }
        }
        return $this->queue;
    }

    /**
     * Add support for deep cloning
     *
     * @return void
     */
    public function __clone()
    {
        if (null !== $this->queue) {
            $this->queue = clone $this->queue;
        }
    }
}
laminas-stdlib/src/DispatchableInterface.php000064400000001136147361032560015163 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-stdlib for the canonical source repository
 * @copyright https://github.com/laminas/laminas-stdlib/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-stdlib/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Stdlib;

interface DispatchableInterface
{
    /**
     * Dispatch a request
     *
     * @param RequestInterface $request
     * @param null|ResponseInterface $response
     * @return Response|mixed
     */
    public function dispatch(RequestInterface $request, ResponseInterface $response = null);
}
laminas-stdlib/src/StringWrapper/MbString.php000064400000006735147361032560015325 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-stdlib for the canonical source repository
 * @copyright https://github.com/laminas/laminas-stdlib/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-stdlib/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Stdlib\StringWrapper;

use Laminas\Stdlib\Exception;

use function array_map;
use function array_search;
use function extension_loaded;
use function mb_convert_encoding;
use function mb_list_encodings;
use function mb_strlen;
use function mb_strpos;
use function mb_substr;

class MbString extends AbstractStringWrapper
{
    /**
     * List of supported character sets (upper case)
     *
     * @var null|string[]
     * @link http://php.net/manual/mbstring.supported-encodings.php
     */
    protected static $encodings = null;

    /**
     * Get a list of supported character encodings
     *
     * @return string[]
     */
    public static function getSupportedEncodings()
    {
        if (static::$encodings === null) {
            static::$encodings = array_map('strtoupper', mb_list_encodings());

            // FIXME: Converting € (UTF-8) to ISO-8859-16 gives a wrong result
            $indexIso885916 = array_search('ISO-8859-16', static::$encodings, true);
            if ($indexIso885916 !== false) {
                unset(static::$encodings[$indexIso885916]);
            }
        }

        return static::$encodings;
    }

    /**
     * Constructor
     *
     * @throws Exception\ExtensionNotLoadedException
     */
    public function __construct()
    {
        if (! extension_loaded('mbstring')) {
            throw new Exception\ExtensionNotLoadedException(
                'PHP extension "mbstring" is required for this wrapper'
            );
        }
    }

    /**
     * Returns the length of the given string
     *
     * @param string $str
     * @return int|false
     */
    public function strlen($str)
    {
        return mb_strlen($str, $this->getEncoding());
    }

    /**
     * Returns the portion of string specified by the start and length parameters
     *
     * @param string   $str
     * @param int      $offset
     * @param int|null $length
     * @return string|false
     */
    public function substr($str, $offset = 0, $length = null)
    {
        return mb_substr($str, $offset, $length, $this->getEncoding());
    }

    /**
     * Find the position of the first occurrence of a substring in a string
     *
     * @param string $haystack
     * @param string $needle
     * @param int    $offset
     * @return int|false
     */
    public function strpos($haystack, $needle, $offset = 0)
    {
        return mb_strpos($haystack, $needle, $offset, $this->getEncoding());
    }

    /**
     * Convert a string from defined encoding to the defined convert encoding
     *
     * @param string  $str
     * @param bool $reverse
     * @return string|false
     */
    public function convert($str, $reverse = false)
    {
        $encoding        = $this->getEncoding();
        $convertEncoding = $this->getConvertEncoding();

        if ($convertEncoding === null) {
            throw new Exception\LogicException(
                'No convert encoding defined'
            );
        }

        if ($encoding === $convertEncoding) {
            return $str;
        }

        $fromEncoding = $reverse ? $convertEncoding : $encoding;
        $toEncoding   = $reverse ? $encoding : $convertEncoding;
        return mb_convert_encoding($str, $toEncoding, $fromEncoding);
    }
}
laminas-stdlib/src/StringWrapper/Native.php000064400000007477147361032560015032 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-stdlib for the canonical source repository
 * @copyright https://github.com/laminas/laminas-stdlib/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-stdlib/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Stdlib\StringWrapper;

use Laminas\Stdlib\Exception;
use Laminas\Stdlib\StringUtils;

use function in_array;
use function strlen;
use function strpos;
use function strtoupper;
use function substr;

class Native extends AbstractStringWrapper
{
    /**
     * The character encoding working on
     * (overwritten to change default encoding)
     *
     * @var string
     */
    protected $encoding = 'ASCII';

    /**
     * Check if the given character encoding is supported by this wrapper
     * and the character encoding to convert to is also supported.
     *
     * @param  string      $encoding
     * @param  string|null $convertEncoding
     * @return bool
     */
    public static function isSupported($encoding, $convertEncoding = null)
    {
        $encodingUpper      = strtoupper($encoding);
        $supportedEncodings = static::getSupportedEncodings();

        if (! in_array($encodingUpper, $supportedEncodings)) {
            return false;
        }

        // This adapter doesn't support to convert between encodings
        if ($convertEncoding !== null && $encodingUpper !== strtoupper($convertEncoding)) {
            return false;
        }

        return true;
    }

    /**
     * Get a list of supported character encodings
     *
     * @return string[]
     */
    public static function getSupportedEncodings()
    {
        return StringUtils::getSingleByteEncodings();
    }

    /**
     * Set character encoding working with and convert to
     *
     * @param string      $encoding         The character encoding to work with
     * @param string|null $convertEncoding  The character encoding to convert to
     * @return StringWrapperInterface
     */
    public function setEncoding($encoding, $convertEncoding = null)
    {
        $supportedEncodings = static::getSupportedEncodings();

        $encodingUpper = strtoupper($encoding);
        if (! in_array($encodingUpper, $supportedEncodings)) {
            throw new Exception\InvalidArgumentException(
                'Wrapper doesn\'t support character encoding "' . $encoding . '"'
            );
        }

        if ($encodingUpper !== strtoupper($convertEncoding)) {
            $this->convertEncoding = $encodingUpper;
        }

        if ($convertEncoding !== null) {
            if ($encodingUpper !== strtoupper($convertEncoding)) {
                throw new Exception\InvalidArgumentException(
                    'Wrapper doesn\'t support to convert between character encodings'
                );
            }

            $this->convertEncoding = $encodingUpper;
        } else {
            $this->convertEncoding = null;
        }
        $this->encoding = $encodingUpper;

        return $this;
    }

    /**
     * Returns the length of the given string
     *
     * @param string $str
     * @return int|false
     */
    public function strlen($str)
    {
        return strlen($str);
    }

    /**
     * Returns the portion of string specified by the start and length parameters
     *
     * @param string   $str
     * @param int      $offset
     * @param int|null $length
     * @return string|false
     */
    public function substr($str, $offset = 0, $length = null)
    {
        return substr($str, $offset, $length);
    }

    /**
     * Find the position of the first occurrence of a substring in a string
     *
     * @param string $haystack
     * @param string $needle
     * @param int    $offset
     * @return int|false
     */
    public function strpos($haystack, $needle, $offset = 0)
    {
        return strpos($haystack, $needle, $offset);
    }
}
laminas-stdlib/src/StringWrapper/Iconv.php000064400000015137147361032560014652 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-stdlib for the canonical source repository
 * @copyright https://github.com/laminas/laminas-stdlib/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-stdlib/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Stdlib\StringWrapper;

use Laminas\Stdlib\Exception;

use function extension_loaded;
use function iconv;
use function iconv_strlen;
use function iconv_strpos;
use function iconv_substr;

class Iconv extends AbstractStringWrapper
{
    /**
     * List of supported character sets (upper case)
     *
     * @var string[]
     * @link http://www.gnu.org/software/libiconv/
     */
    protected static $encodings = [
        // European languages
        'ASCII',
        'ISO-8859-1',
        'ISO-8859-2',
        'ISO-8859-3',
        'ISO-8859-4',
        'ISO-8859-5',
        'ISO-8859-7',
        'ISO-8859-9',
        'ISO-8859-10',
        'ISO-8859-13',
        'ISO-8859-14',
        'ISO-8859-15',
        'ISO-8859-16',
        'KOI8-R',
        'KOI8-U',
        'KOI8-RU',
        'CP1250',
        'CP1251',
        'CP1252',
        'CP1253',
        'CP1254',
        'CP1257',
        'CP850',
        'CP866',
        'CP1131',
        'MACROMAN',
        'MACCENTRALEUROPE',
        'MACICELAND',
        'MACCROATIAN',
        'MACROMANIA',
        'MACCYRILLIC',
        'MACUKRAINE',
        'MACGREEK',
        'MACTURKISH',
        'MACINTOSH',

        // Semitic languages
        'ISO-8859-6',
        'ISO-8859-8',
        'CP1255',
        'CP1256',
        'CP862',
        'MACHEBREW',
        'MACARABIC',

        // Japanese
        'EUC-JP',
        'SHIFT_JIS',
        'CP932',
        'ISO-2022-JP',
        'ISO-2022-JP-2',
        'ISO-2022-JP-1',

        // Chinese
        'EUC-CN',
        'HZ',
        'GBK',
        'CP936',
        'GB18030',
        'EUC-TW',
        'BIG5',
        'CP950',
        'BIG5-HKSCS',
        'BIG5-HKSCS:2004',
        'BIG5-HKSCS:2001',
        'BIG5-HKSCS:1999',
        'ISO-2022-CN',
        'ISO-2022-CN-EXT',

        // Korean
        'EUC-KR',
        'CP949',
        'ISO-2022-KR',
        'JOHAB',

        // Armenian
        'ARMSCII-8',

        // Georgian
        'GEORGIAN-ACADEMY',
        'GEORGIAN-PS',

        // Tajik
        'KOI8-T',

        // Kazakh
        'PT154',
        'RK1048',

        // Thai
        'ISO-8859-11',
        'TIS-620',
        'CP874',
        'MACTHAI',

        // Laotian
        'MULELAO-1',
        'CP1133',

        // Vietnamese
        'VISCII',
        'TCVN',
        'CP1258',

        // Platform specifics
        'HP-ROMAN8',
        'NEXTSTEP',

        // Full Unicode
        'UTF-8',
        'UCS-2',
        'UCS-2BE',
        'UCS-2LE',
        'UCS-4',
        'UCS-4BE',
        'UCS-4LE',
        'UTF-16',
        'UTF-16BE',
        'UTF-16LE',
        'UTF-32',
        'UTF-32BE',
        'UTF-32LE',
        'UTF-7',
        'C99',
        'JAVA',

        /* Commented out because that's internal encodings not existing in real world
        // Full Unicode, in terms of uint16_t or uint32_t (with machine dependent endianness and alignment)
        'UCS-2-INTERNAL',
        'UCS-4-INTERNAL',

        // Locale dependent, in terms of `char' or `wchar_t' (with machine dependent endianness and alignment,
        // and with OS and locale dependent semantics)
        'char',
        'wchar_t',
        '', // The empty encoding name is equivalent to "char": it denotes the locale dependent character encoding.
        */

        // When configured with the option --enable-extra-encodings,
        // it also provides support for a few extra encodings:

        // European languages
        'CP437',
        'CP737',
        'CP775',
        'CP852',
        'CP853',
        'CP855',
        'CP857',
        'CP858',
        'CP860',
        'CP861',
        'CP863',
        'CP865',
        'CP869',
        'CP1125',

        // Semitic languages
        'CP864',

        // Japanese
        'EUC-JISX0213',
        'Shift_JISX0213',
        'ISO-2022-JP-3',

        // Chinese
        'BIG5-2003', // (experimental)

        // Turkmen
        'TDS565',

        // Platform specifics
        'ATARIST',
        'RISCOS-LATIN1',
    ];

    /**
     * Get a list of supported character encodings
     *
     * @return string[]
     */
    public static function getSupportedEncodings()
    {
        return static::$encodings;
    }

    /**
     * Constructor
     *
     * @throws Exception\ExtensionNotLoadedException
     */
    public function __construct()
    {
        if (! extension_loaded('iconv')) {
            throw new Exception\ExtensionNotLoadedException(
                'PHP extension "iconv" is required for this wrapper'
            );
        }
    }

    /**
     * Returns the length of the given string
     *
     * @param string $str
     * @return int|false
     */
    public function strlen($str)
    {
        return iconv_strlen($str, $this->getEncoding());
    }

    /**
     * Returns the portion of string specified by the start and length parameters
     *
     * @param string   $str
     * @param int      $offset
     * @param int|null $length
     * @return string|false
     */
    public function substr($str, $offset = 0, $length = null)
    {
        return iconv_substr($str, $offset, $length, $this->getEncoding());
    }

    /**
     * Find the position of the first occurrence of a substring in a string
     *
     * @param string $haystack
     * @param string $needle
     * @param int    $offset
     * @return int|false
     */
    public function strpos($haystack, $needle, $offset = 0)
    {
        return iconv_strpos($haystack, $needle, $offset, $this->getEncoding());
    }

    /**
     * Convert a string from defined encoding to the defined convert encoding
     *
     * @param string  $str
     * @param bool $reverse
     * @return string|false
     */
    public function convert($str, $reverse = false)
    {
        $encoding        = $this->getEncoding();
        $convertEncoding = $this->getConvertEncoding();
        if ($convertEncoding === null) {
            throw new Exception\LogicException(
                'No convert encoding defined'
            );
        }

        if ($encoding === $convertEncoding) {
            return $str;
        }

        $fromEncoding = $reverse ? $convertEncoding : $encoding;
        $toEncoding   = $reverse ? $encoding : $convertEncoding;

        // automatically add "//IGNORE" to not stop converting on invalid characters
        // invalid characters triggers a notice anyway
        return iconv($fromEncoding, $toEncoding . '//IGNORE', $str);
    }
}
laminas-stdlib/src/StringWrapper/Intl.php000064400000004364147361032560014502 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-stdlib for the canonical source repository
 * @copyright https://github.com/laminas/laminas-stdlib/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-stdlib/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Stdlib\StringWrapper;

use Laminas\Stdlib\Exception;

use function extension_loaded;
use function grapheme_strlen;
use function grapheme_strpos;
use function grapheme_substr;

class Intl extends AbstractStringWrapper
{
    /**
     * List of supported character sets (upper case)
     *
     * @var string[]
     */
    protected static $encodings = ['UTF-8'];

    /**
     * Get a list of supported character encodings
     *
     * @return string[]
     */
    public static function getSupportedEncodings()
    {
        return static::$encodings;
    }

    /**
     * Constructor
     *
     * @throws Exception\ExtensionNotLoadedException
     */
    public function __construct()
    {
        if (! extension_loaded('intl')) {
            throw new Exception\ExtensionNotLoadedException(
                'PHP extension "intl" is required for this wrapper'
            );
        }
    }

    /**
     * Returns the length of the given string
     *
     * @param string $str
     * @return int|false
     */
    public function strlen($str)
    {
        return grapheme_strlen($str);
    }

    /**
     * Returns the portion of string specified by the start and length parameters
     *
     * @param string   $str
     * @param int      $offset
     * @param int|null $length
     * @return string|false
     */
    public function substr($str, $offset = 0, $length = null)
    {
        // Due fix of PHP #62759 The third argument returns an empty string if is 0 or null.
        if ($length !== null) {
            return grapheme_substr($str, $offset, $length);
        }

        return grapheme_substr($str, $offset);
    }

    /**
     * Find the position of the first occurrence of a substring in a string
     *
     * @param string $haystack
     * @param string $needle
     * @param int    $offset
     * @return int|false
     */
    public function strpos($haystack, $needle, $offset = 0)
    {
        return grapheme_strpos($haystack, $needle, $offset);
    }
}
laminas-stdlib/src/StringWrapper/AbstractStringWrapper.php000064400000021145147361032560020063 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-stdlib for the canonical source repository
 * @copyright https://github.com/laminas/laminas-stdlib/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-stdlib/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Stdlib\StringWrapper;

use Laminas\Stdlib\Exception;
use Laminas\Stdlib\StringUtils;

use function floor;
use function in_array;
use function sprintf;
use function str_pad;
use function str_repeat;
use function strtoupper;
use function wordwrap;

use const STR_PAD_BOTH;
use const STR_PAD_LEFT;
use const STR_PAD_RIGHT;

abstract class AbstractStringWrapper implements StringWrapperInterface
{
    /**
     * The character encoding working on
     * @var string|null
     */
    protected $encoding = 'UTF-8';

    /**
     * An optionally character encoding to convert to
     * @var string|null
     */
    protected $convertEncoding;

    /**
     * Check if the given character encoding is supported by this wrapper
     * and the character encoding to convert to is also supported.
     *
     * @param  string      $encoding
     * @param  string|null $convertEncoding
     * @return bool
     */
    public static function isSupported($encoding, $convertEncoding = null)
    {
        $supportedEncodings = static::getSupportedEncodings();

        if (! in_array(strtoupper($encoding), $supportedEncodings)) {
            return false;
        }

        if ($convertEncoding !== null && ! in_array(strtoupper($convertEncoding), $supportedEncodings)) {
            return false;
        }

        return true;
    }

    /**
     * Set character encoding working with and convert to
     *
     * @param string      $encoding         The character encoding to work with
     * @param string|null $convertEncoding  The character encoding to convert to
     * @return StringWrapperInterface
     */
    public function setEncoding($encoding, $convertEncoding = null)
    {
        $supportedEncodings = static::getSupportedEncodings();

        $encodingUpper = strtoupper($encoding);
        if (! in_array($encodingUpper, $supportedEncodings)) {
            throw new Exception\InvalidArgumentException(
                'Wrapper doesn\'t support character encoding "' . $encoding . '"'
            );
        }

        if ($convertEncoding !== null) {
            $convertEncodingUpper = strtoupper($convertEncoding);
            if (! in_array($convertEncodingUpper, $supportedEncodings)) {
                throw new Exception\InvalidArgumentException(
                    'Wrapper doesn\'t support character encoding "' . $convertEncoding . '"'
                );
            }

            $this->convertEncoding = $convertEncodingUpper;
        } else {
            $this->convertEncoding = null;
        }
        $this->encoding = $encodingUpper;

        return $this;
    }

    /**
     * Get the defined character encoding to work with
     *
     * @return string
     * @throws Exception\LogicException If no encoding was defined
     */
    public function getEncoding()
    {
        return $this->encoding;
    }

    /**
     * Get the defined character encoding to convert to
     *
     * @return string|null
    */
    public function getConvertEncoding()
    {
        return $this->convertEncoding;
    }

    /**
     * Convert a string from defined character encoding to the defined convert encoding
     *
     * @param string  $str
     * @param bool $reverse
     * @return string|false
     */
    public function convert($str, $reverse = false)
    {
        $encoding        = $this->getEncoding();
        $convertEncoding = $this->getConvertEncoding();
        if ($convertEncoding === null) {
            throw new Exception\LogicException(
                'No convert encoding defined'
            );
        }

        if ($encoding === $convertEncoding) {
            return $str;
        }

        $from = $reverse ? $convertEncoding : $encoding;
        $to   = $reverse ? $encoding : $convertEncoding;
        throw new Exception\RuntimeException(sprintf(
            'Converting from "%s" to "%s" isn\'t supported by this string wrapper',
            $from,
            $to
        ));
    }

    /**
     * Wraps a string to a given number of characters
     *
     * @param  string  $string
     * @param  int $width
     * @param  string  $break
     * @param  bool $cut
     * @return string|false
     */
    public function wordWrap($string, $width = 75, $break = "\n", $cut = false)
    {
        $string = (string) $string;
        if ($string === '') {
            return '';
        }

        $break = (string) $break;
        if ($break === '') {
            throw new Exception\InvalidArgumentException('Break string cannot be empty');
        }

        $width = (int) $width;
        if ($width === 0 && $cut) {
            throw new Exception\InvalidArgumentException('Cannot force cut when width is zero');
        }

        if (StringUtils::isSingleByteEncoding($this->getEncoding())) {
            return wordwrap($string, $width, $break, $cut);
        }

        $stringWidth = $this->strlen($string);
        $breakWidth  = $this->strlen($break);

        $result    = '';
        $lastStart = $lastSpace = 0;

        for ($current = 0; $current < $stringWidth; $current++) {
            $char = $this->substr($string, $current, 1);

            $possibleBreak = $char;
            if ($breakWidth !== 1) {
                $possibleBreak = $this->substr($string, $current, $breakWidth);
            }

            if ($possibleBreak === $break) {
                $result    .= $this->substr($string, $lastStart, $current - $lastStart + $breakWidth);
                $current   += $breakWidth - 1;
                $lastStart  = $lastSpace = $current + 1;
                continue;
            }

            if ($char === ' ') {
                if ($current - $lastStart >= $width) {
                    $result    .= $this->substr($string, $lastStart, $current - $lastStart) . $break;
                    $lastStart  = $current + 1;
                }

                $lastSpace = $current;
                continue;
            }

            if ($current - $lastStart >= $width && $cut && $lastStart >= $lastSpace) {
                $result    .= $this->substr($string, $lastStart, $current - $lastStart) . $break;
                $lastStart  = $lastSpace = $current;
                continue;
            }

            if ($current - $lastStart >= $width && $lastStart < $lastSpace) {
                $result    .= $this->substr($string, $lastStart, $lastSpace - $lastStart) . $break;
                $lastStart  = $lastSpace = $lastSpace + 1;
                continue;
            }
        }

        if ($lastStart !== $current) {
            $result .= $this->substr($string, $lastStart, $current - $lastStart);
        }

        return $result;
    }

    /**
     * Pad a string to a certain length with another string
     *
     * @param  string  $input
     * @param  int $padLength
     * @param  string  $padString
     * @param  int $padType
     * @return string
     */
    public function strPad($input, $padLength, $padString = ' ', $padType = STR_PAD_RIGHT)
    {
        if (StringUtils::isSingleByteEncoding($this->getEncoding())) {
            return str_pad($input, $padLength, $padString, $padType);
        }

        $lengthOfPadding = $padLength - $this->strlen($input);
        if ($lengthOfPadding <= 0) {
            return $input;
        }

        $padStringLength = $this->strlen($padString);
        if ($padStringLength === 0) {
            return $input;
        }

        $repeatCount = floor($lengthOfPadding / $padStringLength);

        if ($padType === STR_PAD_BOTH) {
            $repeatCountLeft = $repeatCountRight = ($repeatCount - $repeatCount % 2) / 2;

            $lastStringLength       = $lengthOfPadding - 2 * $repeatCountLeft * $padStringLength;
            $lastStringLeftLength   = $lastStringRightLength = floor($lastStringLength / 2);
            $lastStringRightLength += $lastStringLength % 2;

            $lastStringLeft  = $this->substr($padString, 0, $lastStringLeftLength);
            $lastStringRight = $this->substr($padString, 0, $lastStringRightLength);

            return str_repeat($padString, $repeatCountLeft) . $lastStringLeft
                . $input
                . str_repeat($padString, $repeatCountRight) . $lastStringRight;
        }

        $lastString = $this->substr($padString, 0, $lengthOfPadding % $padStringLength);

        if ($padType === STR_PAD_LEFT) {
            return str_repeat($padString, $repeatCount) . $lastString . $input;
        }

        return $input . str_repeat($padString, $repeatCount) . $lastString;
    }
}
laminas-stdlib/src/StringWrapper/StringWrapperInterface.php000064400000006011147361032560020213 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-stdlib for the canonical source repository
 * @copyright https://github.com/laminas/laminas-stdlib/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-stdlib/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Stdlib\StringWrapper;

use const STR_PAD_RIGHT;

interface StringWrapperInterface
{
    /**
     * Check if the given character encoding is supported by this wrapper
     * and the character encoding to convert to is also supported.
     *
     * @param string      $encoding
     * @param string|null $convertEncoding
     */
    public static function isSupported($encoding, $convertEncoding = null);

    /**
     * Get a list of supported character encodings
     *
     * @return string[]
     */
    public static function getSupportedEncodings();

    /**
     * Set character encoding working with and convert to
     *
     * @param string      $encoding         The character encoding to work with
     * @param string|null $convertEncoding  The character encoding to convert to
     * @return StringWrapperInterface
     */
    public function setEncoding($encoding, $convertEncoding = null);

    /**
     * Get the defined character encoding to work with (upper case)
     *
     * @return string
     */
    public function getEncoding();

    /**
     * Get the defined character encoding to convert to (upper case)
     *
     * @return string|null
     */
    public function getConvertEncoding();

    /**
     * Returns the length of the given string
     *
     * @param string $str
     * @return int|false
     */
    public function strlen($str);

    /**
     * Returns the portion of string specified by the start and length parameters
     *
     * @param string   $str
     * @param int      $offset
     * @param int|null $length
     * @return string|false
     */
    public function substr($str, $offset = 0, $length = null);

    /**
     * Find the position of the first occurrence of a substring in a string
     *
     * @param string $haystack
     * @param string $needle
     * @param int    $offset
     * @return int|false
     */
    public function strpos($haystack, $needle, $offset = 0);

    /**
     * Convert a string from defined encoding to the defined convert encoding
     *
     * @param string  $str
     * @param bool $reverse
     * @return string|false
     */
    public function convert($str, $reverse = false);

    /**
     * Wraps a string to a given number of characters
     *
     * @param  string  $str
     * @param  int $width
     * @param  string  $break
     * @param  bool $cut
     * @return string
     */
    public function wordWrap($str, $width = 75, $break = "\n", $cut = false);

    /**
     * Pad a string to a certain length with another string
     *
     * @param  string  $input
     * @param  int $padLength
     * @param  string  $padString
     * @param  int $padType
     * @return string
     */
    public function strPad($input, $padLength, $padString = ' ', $padType = STR_PAD_RIGHT);
}
laminas-stdlib/src/SplStack.php000064400000002151147361032560012501 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-stdlib for the canonical source repository
 * @copyright https://github.com/laminas/laminas-stdlib/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-stdlib/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Stdlib;

use Serializable;

use function serialize;
use function unserialize;

/**
 * Serializable version of SplStack
 */
class SplStack extends \SplStack implements Serializable
{
    /**
     * Serialize to an array representing the stack
     *
     * @return array
     */
    public function toArray()
    {
        $array = [];
        foreach ($this as $item) {
            $array[] = $item;
        }
        return $array;
    }

    /**
     * Serialize
     *
     * @return string
     */
    public function serialize()
    {
        return serialize($this->toArray());
    }

    /**
     * Unserialize
     *
     * @param  string $data
     * @return void
     */
    public function unserialize($data)
    {
        foreach (unserialize($data) as $item) {
            $this->unshift($item);
        }
    }
}
laminas-stdlib/src/ArrayUtils.php000064400000022256147361032560013064 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-stdlib for the canonical source repository
 * @copyright https://github.com/laminas/laminas-stdlib/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-stdlib/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Stdlib;

use Laminas\Stdlib\ArrayUtils\MergeRemoveKey;
use Laminas\Stdlib\ArrayUtils\MergeReplaceKeyInterface;
use Traversable;

use function array_filter;
use function array_key_exists;
use function array_keys;
use function array_values;
use function in_array;
use function is_array;
use function is_callable;
use function is_float;
use function is_int;
use function is_object;
use function is_scalar;
use function is_string;
use function iterator_to_array;
use function method_exists;
use function sprintf;

/**
 * Utility class for testing and manipulation of PHP arrays.
 *
 * Declared abstract, as we have no need for instantiation.
 */
abstract class ArrayUtils
{
    /**
     * Compatibility Flag for ArrayUtils::filter
     */
    const ARRAY_FILTER_USE_BOTH = 1;

    /**
     * Compatibility Flag for ArrayUtils::filter
     */
    const ARRAY_FILTER_USE_KEY  = 2;

    /**
     * Test whether an array contains one or more string keys
     *
     * @param  mixed $value
     * @param  bool  $allowEmpty    Should an empty array() return true
     * @return bool
     */
    public static function hasStringKeys($value, $allowEmpty = false)
    {
        if (! is_array($value)) {
            return false;
        }

        if (! $value) {
            return $allowEmpty;
        }

        return [] !== array_filter(array_keys($value), 'is_string');
    }

    /**
     * Test whether an array contains one or more integer keys
     *
     * @param  mixed $value
     * @param  bool  $allowEmpty    Should an empty array() return true
     * @return bool
     */
    public static function hasIntegerKeys($value, $allowEmpty = false)
    {
        if (! is_array($value)) {
            return false;
        }

        if (! $value) {
            return $allowEmpty;
        }

        return [] !== array_filter(array_keys($value), 'is_int');
    }

    /**
     * Test whether an array contains one or more numeric keys.
     *
     * A numeric key can be one of the following:
     * - an integer 1,
     * - a string with a number '20'
     * - a string with negative number: '-1000'
     * - a float: 2.2120, -78.150999
     * - a string with float:  '4000.99999', '-10.10'
     *
     * @param  mixed $value
     * @param  bool  $allowEmpty    Should an empty array() return true
     * @return bool
     */
    public static function hasNumericKeys($value, $allowEmpty = false)
    {
        if (! is_array($value)) {
            return false;
        }

        if (! $value) {
            return $allowEmpty;
        }

        return [] !== array_filter(array_keys($value), 'is_numeric');
    }

    /**
     * Test whether an array is a list
     *
     * A list is a collection of values assigned to continuous integer keys
     * starting at 0 and ending at count() - 1.
     *
     * For example:
     * <code>
     * $list = array('a', 'b', 'c', 'd');
     * $list = array(
     *     0 => 'foo',
     *     1 => 'bar',
     *     2 => array('foo' => 'baz'),
     * );
     * </code>
     *
     * @param  mixed $value
     * @param  bool  $allowEmpty    Is an empty list a valid list?
     * @return bool
     */
    public static function isList($value, $allowEmpty = false)
    {
        if (! is_array($value)) {
            return false;
        }

        if (! $value) {
            return $allowEmpty;
        }

        return (array_values($value) === $value);
    }

    /**
     * Test whether an array is a hash table.
     *
     * An array is a hash table if:
     *
     * 1. Contains one or more non-integer keys, or
     * 2. Integer keys are non-continuous or misaligned (not starting with 0)
     *
     * For example:
     * <code>
     * $hash = array(
     *     'foo' => 15,
     *     'bar' => false,
     * );
     * $hash = array(
     *     1995  => 'Birth of PHP',
     *     2009  => 'PHP 5.3.0',
     *     2012  => 'PHP 5.4.0',
     * );
     * $hash = array(
     *     'formElement,
     *     'options' => array( 'debug' => true ),
     * );
     * </code>
     *
     * @param  mixed $value
     * @param  bool  $allowEmpty    Is an empty array() a valid hash table?
     * @return bool
     */
    public static function isHashTable($value, $allowEmpty = false)
    {
        if (! is_array($value)) {
            return false;
        }

        if (! $value) {
            return $allowEmpty;
        }

        return (array_values($value) !== $value);
    }

    /**
     * Checks if a value exists in an array.
     *
     * Due to "foo" == 0 === TRUE with in_array when strict = false, an option
     * has been added to prevent this. When $strict = 0/false, the most secure
     * non-strict check is implemented. if $strict = -1, the default in_array
     * non-strict behaviour is used.
     *
     * @param mixed $needle
     * @param array $haystack
     * @param int|bool $strict
     * @return bool
     */
    public static function inArray($needle, array $haystack, $strict = false)
    {
        if (! $strict) {
            if (is_int($needle) || is_float($needle)) {
                $needle = (string) $needle;
            }
            if (is_string($needle)) {
                foreach ($haystack as &$h) {
                    if (is_int($h) || is_float($h)) {
                        $h = (string) $h;
                    }
                }
            }
        }
        return in_array($needle, $haystack, $strict);
    }

    /**
     * Convert an iterator to an array.
     *
     * Converts an iterator to an array. The $recursive flag, on by default,
     * hints whether or not you want to do so recursively.
     *
     * @param  array|Traversable  $iterator     The array or Traversable object to convert
     * @param  bool               $recursive    Recursively check all nested structures
     * @throws Exception\InvalidArgumentException if $iterator is not an array or a Traversable object
     * @return array
     */
    public static function iteratorToArray($iterator, $recursive = true)
    {
        if (! is_array($iterator) && ! $iterator instanceof Traversable) {
            throw new Exception\InvalidArgumentException(__METHOD__ . ' expects an array or Traversable object');
        }

        if (! $recursive) {
            if (is_array($iterator)) {
                return $iterator;
            }

            return iterator_to_array($iterator);
        }

        if (is_object($iterator) && method_exists($iterator, 'toArray')) {
            return $iterator->toArray();
        }

        $array = [];
        foreach ($iterator as $key => $value) {
            if (is_scalar($value)) {
                $array[$key] = $value;
                continue;
            }

            if ($value instanceof Traversable) {
                $array[$key] = static::iteratorToArray($value, $recursive);
                continue;
            }

            if (is_array($value)) {
                $array[$key] = static::iteratorToArray($value, $recursive);
                continue;
            }

            $array[$key] = $value;
        }

        return $array;
    }

    /**
     * Merge two arrays together.
     *
     * If an integer key exists in both arrays and preserveNumericKeys is false, the value
     * from the second array will be appended to the first array. If both values are arrays, they
     * are merged together, else the value of the second array overwrites the one of the first array.
     *
     * @param  array $a
     * @param  array $b
     * @param  bool  $preserveNumericKeys
     * @return array
     */
    public static function merge(array $a, array $b, $preserveNumericKeys = false)
    {
        foreach ($b as $key => $value) {
            if ($value instanceof MergeReplaceKeyInterface) {
                $a[$key] = $value->getData();
            } elseif (isset($a[$key]) || array_key_exists($key, $a)) {
                if ($value instanceof MergeRemoveKey) {
                    unset($a[$key]);
                } elseif (! $preserveNumericKeys && is_int($key)) {
                    $a[] = $value;
                } elseif (is_array($value) && is_array($a[$key])) {
                    $a[$key] = static::merge($a[$key], $value, $preserveNumericKeys);
                } else {
                    $a[$key] = $value;
                }
            } else {
                if (! $value instanceof MergeRemoveKey) {
                    $a[$key] = $value;
                }
            }
        }

        return $a;
    }

    /**
     * @deprecated Since 3.2.0; use the native array_filter methods
     *
     * @param array $data
     * @param callable $callback
     * @param null|int $flag
     * @return array
     * @throws Exception\InvalidArgumentException
     */
    public static function filter(array $data, $callback, $flag = null)
    {
        if (! is_callable($callback)) {
            throw new Exception\InvalidArgumentException(sprintf(
                'Second parameter of %s must be callable',
                __METHOD__
            ));
        }

        return array_filter($data, $callback, $flag);
    }
}
laminas-stdlib/src/ParametersInterface.php000064400000003445147361032560014710 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-stdlib for the canonical source repository
 * @copyright https://github.com/laminas/laminas-stdlib/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-stdlib/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Stdlib;

use ArrayAccess;
use Countable;
use Serializable;
use Traversable;

/*
 * Basically, an ArrayObject. You could simply define something like:
 *     class QueryParams extends ArrayObject implements Parameters {}
 * and have 90% of the functionality
 */
interface ParametersInterface extends ArrayAccess, Countable, Serializable, Traversable
{
    /**
     * Constructor
     *
     * @param array $values
     */
    public function __construct(array $values = null);

    /**
     * From array
     *
     * Allow deserialization from standard array
     *
     * @param array $values
     * @return mixed
     */
    public function fromArray(array $values);

    /**
     * From string
     *
     * Allow deserialization from raw body; e.g., for PUT requests
     *
     * @param $string
     * @return mixed
     */
    public function fromString($string);

    /**
     * To array
     *
     * Allow serialization back to standard array
     *
     * @return mixed
     */
    public function toArray();

    /**
     * To string
     *
     * Allow serialization to query format; e.g., for PUT or POST requests
     *
     * @return mixed
     */
    public function toString();

    /**
     * Get
     *
     * @param string $name
     * @param mixed|null $default
     * @return mixed
     */
    public function get($name, $default = null);

    /**
     * Set
     *
     * @param string $name
     * @param mixed $value
     * @return ParametersInterface
     */
    public function set($name, $value);
}
laminas-stdlib/src/RequestInterface.php000064400000000557147361032560014236 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-stdlib for the canonical source repository
 * @copyright https://github.com/laminas/laminas-stdlib/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-stdlib/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Stdlib;

interface RequestInterface extends MessageInterface
{
}
laminas-stdlib/src/SplPriorityQueue.php000064400000004306147361032560014266 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-stdlib for the canonical source repository
 * @copyright https://github.com/laminas/laminas-stdlib/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-stdlib/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Stdlib;

use Serializable;

use function is_array;
use function serialize;
use function unserialize;

/**
 * Serializable version of SplPriorityQueue
 *
 * Also, provides predictable heap order for datums added with the same priority
 * (i.e., they will be emitted in the same order they are enqueued).
 */
class SplPriorityQueue extends \SplPriorityQueue implements Serializable
{
    /**
     * @var int Seed used to ensure queue order for items of the same priority
     */
    protected $serial = PHP_INT_MAX;

    /**
     * Insert a value with a given priority
     *
     * Utilizes {@var $serial} to ensure that values of equal priority are
     * emitted in the same order in which they are inserted.
     *
     * @param  mixed $datum
     * @param  mixed $priority
     * @return void
     */
    public function insert($datum, $priority)
    {
        if (! is_array($priority)) {
            $priority = [$priority, $this->serial--];
        }
        parent::insert($datum, $priority);
    }

    /**
     * Serialize to an array
     *
     * Array will be priority => data pairs
     *
     * @return array
     */
    public function toArray()
    {
        $array = [];
        foreach (clone $this as $item) {
            $array[] = $item;
        }
        return $array;
    }

    /**
     * Serialize
     *
     * @return string
     */
    public function serialize()
    {
        $clone = clone $this;
        $clone->setExtractFlags(self::EXTR_BOTH);

        $data = [];
        foreach ($clone as $item) {
            $data[] = $item;
        }

        return serialize($data);
    }

    /**
     * Deserialize
     *
     * @param  string $data
     * @return void
     */
    public function unserialize($data)
    {
        $this->serial = PHP_INT_MAX;
        foreach (unserialize($data) as $item) {
            $this->serial--;
            $this->insert($item['data'], $item['priority']);
        }
    }
}
laminas-stdlib/src/Response.php000064400000000636147361032560012561 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-stdlib for the canonical source repository
 * @copyright https://github.com/laminas/laminas-stdlib/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-stdlib/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Stdlib;

class Response extends Message implements ResponseInterface
{
    // generic response implementation
}
laminas-stdlib/src/ArrayUtils/MergeReplaceKey.php000064400000001244147361032560016062 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-stdlib for the canonical source repository
 * @copyright https://github.com/laminas/laminas-stdlib/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-stdlib/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Stdlib\ArrayUtils;

final class MergeReplaceKey implements MergeReplaceKeyInterface
{
    /**
     * @var mixed
     */
    protected $data;

    /**
     * @param mixed $data
     */
    public function __construct($data)
    {
        $this->data = $data;
    }

    /**
     * {@inheritDoc}
     */
    public function getData()
    {
        return $this->data;
    }
}
laminas-stdlib/src/ArrayUtils/MergeRemoveKey.php000064400000000541147361032560015743 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-stdlib for the canonical source repository
 * @copyright https://github.com/laminas/laminas-stdlib/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-stdlib/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Stdlib\ArrayUtils;

final class MergeRemoveKey
{
}
laminas-stdlib/src/ArrayUtils/MergeReplaceKeyInterface.php000064400000001032147361032560017676 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-stdlib for the canonical source repository
 * @copyright https://github.com/laminas/laminas-stdlib/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-stdlib/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Stdlib\ArrayUtils;

/**
 * Marker interface: can be used to replace keys completely in {@see ArrayUtils::merge()} operations
 */
interface MergeReplaceKeyInterface
{
    /**
     * @return mixed
     */
    public function getData();
}
laminas-stdlib/src/Parameters.php000064400000004631147361032560013065 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-stdlib for the canonical source repository
 * @copyright https://github.com/laminas/laminas-stdlib/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-stdlib/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Stdlib;

use ArrayObject as PhpArrayObject;

use function http_build_query;
use function parse_str;

class Parameters extends PhpArrayObject implements ParametersInterface
{
    /**
     * Constructor
     *
     * Enforces that we have an array, and enforces parameter access to array
     * elements.
     *
     * @param  array $values
     */
    public function __construct(array $values = null)
    {
        if (null === $values) {
            $values = [];
        }
        parent::__construct($values, ArrayObject::ARRAY_AS_PROPS);
    }

    /**
     * Populate from native PHP array
     *
     * @param  array $values
     * @return void
     */
    public function fromArray(array $values)
    {
        $this->exchangeArray($values);
    }

    /**
     * Populate from query string
     *
     * @param  string $string
     * @return void
     */
    public function fromString($string)
    {
        $array = [];
        parse_str($string, $array);
        $this->fromArray($array);
    }

    /**
     * Serialize to native PHP array
     *
     * @return array
     */
    public function toArray()
    {
        return $this->getArrayCopy();
    }

    /**
     * Serialize to query string
     *
     * @return string
     */
    public function toString()
    {
        return http_build_query($this->toArray());
    }

    /**
     * Retrieve by key
     *
     * Returns null if the key does not exist.
     *
     * @param  string $name
     * @return mixed
     */
    public function offsetGet($name)
    {
        if ($this->offsetExists($name)) {
            return parent::offsetGet($name);
        }
        return;
    }

    /**
     * @param string $name
     * @param mixed $default optional default value
     * @return mixed
     */
    public function get($name, $default = null)
    {
        if ($this->offsetExists($name)) {
            return parent::offsetGet($name);
        }
        return $default;
    }

    /**
     * @param string $name
     * @param mixed $value
     * @return Parameters
     */
    public function set($name, $value)
    {
        $this[$name] = $value;
        return $this;
    }
}
laminas-stdlib/src/JsonSerializable.php000064400000000676147361032560014227 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-stdlib for the canonical source repository
 * @copyright https://github.com/laminas/laminas-stdlib/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-stdlib/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Stdlib;

/**
 * @deprecated Since 3.1.0; use the native JsonSerializable interface
 */
interface JsonSerializable extends \JsonSerializable
{
}
laminas-stdlib/src/Request.php000064400000000633147361032560012410 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-stdlib for the canonical source repository
 * @copyright https://github.com/laminas/laminas-stdlib/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-stdlib/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Stdlib;

class Request extends Message implements RequestInterface
{
    // generic request implementation
}
laminas-stdlib/src/FastPriorityQueue.php000064400000023205147361032560014424 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-stdlib for the canonical source repository
 * @copyright https://github.com/laminas/laminas-stdlib/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-stdlib/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Stdlib;

use Countable;
use Iterator;
use Serializable;
use SplPriorityQueue as PhpSplPriorityQueue;

use function current;
use function in_array;
use function is_int;
use function key;
use function max;
use function next;
use function reset;
use function serialize;
use function unserialize;

/**
 * This is an efficient implementation of an integer priority queue in PHP
 *
 * This class acts like a queue with insert() and extract(), removing the
 * elements from the queue and it also acts like an Iterator without removing
 * the elements. This behaviour can be used in mixed scenarios with high
 * performance boost.
 */
class FastPriorityQueue implements Iterator, Countable, Serializable
{
    const EXTR_DATA     = PhpSplPriorityQueue::EXTR_DATA;
    const EXTR_PRIORITY = PhpSplPriorityQueue::EXTR_PRIORITY;
    const EXTR_BOTH     = PhpSplPriorityQueue::EXTR_BOTH;

    /**
     * @var integer
     */
    protected $extractFlag = self::EXTR_DATA;

    /**
     * Elements of the queue, divided by priorities
     *
     * @var array
     */
    protected $values = [];

    /**
     * Array of priorities
     *
     * @var array
     */
    protected $priorities = [];

    /**
     * Array of priorities used for the iteration
     *
     * @var array
     */
    protected $subPriorities = [];

    /**
     * Max priority
     *
     * @var integer|null
     */
    protected $maxPriority = null;

    /**
     * Total number of elements in the queue
     *
     * @var integer
     */
    protected $count = 0;

    /**
     * Index of the current element in the queue
     *
     * @var integer
     */
    protected $index = 0;

    /**
     * Sub index of the current element in the same priority level
     *
     * @var integer
     */
    protected $subIndex = 0;

    /**
     * Insert an element in the queue with a specified priority
     *
     * @param mixed $value
     * @param integer $priority
     */
    public function insert($value, $priority)
    {
        if (! is_int($priority)) {
            throw new Exception\InvalidArgumentException('The priority must be an integer');
        }
        $this->values[$priority][] = $value;
        if (! isset($this->priorities[$priority])) {
            $this->priorities[$priority] = $priority;
            $this->maxPriority           = $this->maxPriority === null ? $priority : max($priority, $this->maxPriority);
        }
        ++$this->count;
    }

    /**
     * Extract an element in the queue according to the priority and the
     * order of insertion
     *
     * @return mixed
     */
    public function extract()
    {
        if (! $this->valid()) {
            return false;
        }
        $value = $this->current();
        $this->nextAndRemove();
        return $value;
    }

    /**
     * Remove an item from the queue
     *
     * This is different than {@link extract()}; its purpose is to dequeue an
     * item.
     *
     * Note: this removes the first item matching the provided item found. If
     * the same item has been added multiple times, it will not remove other
     * instances.
     *
     * @param  mixed $datum
     * @return bool False if the item was not found, true otherwise.
     */
    public function remove($datum)
    {
        $currentIndex    = $this->index;
        $currentSubIndex = $this->subIndex;
        $currentPriority = $this->maxPriority;

        $this->rewind();
        while ($this->valid()) {
            if (current($this->values[$this->maxPriority]) === $datum) {
                $index = key($this->values[$this->maxPriority]);
                unset($this->values[$this->maxPriority][$index]);

                // The `next()` method advances the internal array pointer, so we need to use the `reset()` function,
                // otherwise we would lose all elements before the place the pointer points.
                reset($this->values[$this->maxPriority]);

                $this->index    = $currentIndex;
                $this->subIndex = $currentSubIndex;

                // If the array is empty we need to destroy the unnecessary priority,
                // otherwise we would end up with an incorrect value of `$this->count`
                // {@see \Laminas\Stdlib\FastPriorityQueue::nextAndRemove()}.
                if (empty($this->values[$this->maxPriority])) {
                    unset($this->values[$this->maxPriority]);
                    unset($this->priorities[$this->maxPriority]);
                    if ($this->maxPriority === $currentPriority) {
                        $this->subIndex = 0;
                    }
                }

                $this->maxPriority = empty($this->priorities) ? null : max($this->priorities);
                --$this->count;
                return true;
            }
            $this->next();
        }
        return false;
    }

    /**
     * Get the total number of elements in the queue
     *
     * @return integer
     */
    public function count()
    {
        return $this->count;
    }

    /**
     * Get the current element in the queue
     *
     * @return mixed
     */
    public function current()
    {
        switch ($this->extractFlag) {
            case self::EXTR_DATA:
                return current($this->values[$this->maxPriority]);
            case self::EXTR_PRIORITY:
                return $this->maxPriority;
            case self::EXTR_BOTH:
                return [
                    'data'     => current($this->values[$this->maxPriority]),
                    'priority' => $this->maxPriority
                ];
        }
    }

    /**
     * Get the index of the current element in the queue
     *
     * @return integer
     */
    public function key()
    {
        return $this->index;
    }

    /**
     * Set the iterator pointer to the next element in the queue
     * removing the previous element
     */
    protected function nextAndRemove()
    {
        $key = key($this->values[$this->maxPriority]);

        if (false === next($this->values[$this->maxPriority])) {
            unset($this->priorities[$this->maxPriority]);
            unset($this->values[$this->maxPriority]);
            $this->maxPriority = empty($this->priorities) ? null : max($this->priorities);
            $this->subIndex    = -1;
        } else {
            unset($this->values[$this->maxPriority][$key]);
        }
        ++$this->index;
        ++$this->subIndex;
        --$this->count;
    }

    /**
     * Set the iterator pointer to the next element in the queue
     * without removing the previous element
     */
    public function next()
    {
        if (false === next($this->values[$this->maxPriority])) {
            unset($this->subPriorities[$this->maxPriority]);
            reset($this->values[$this->maxPriority]);
            $this->maxPriority = empty($this->subPriorities) ? null : max($this->subPriorities);
            $this->subIndex    = -1;
        }
        ++$this->index;
        ++$this->subIndex;
    }

    /**
     * Check if the current iterator is valid
     *
     * @return boolean
     */
    public function valid()
    {
        return isset($this->values[$this->maxPriority]);
    }

    /**
     * Rewind the current iterator
     */
    public function rewind()
    {
        $this->subPriorities = $this->priorities;
        $this->maxPriority   = empty($this->priorities) ? 0 : max($this->priorities);
        $this->index         = 0;
        $this->subIndex      = 0;
    }

    /**
     * Serialize to an array
     *
     * Array will be priority => data pairs
     *
     * @return array
     */
    public function toArray()
    {
        $array = [];
        foreach (clone $this as $item) {
            $array[] = $item;
        }
        return $array;
    }

    /**
     * Serialize
     *
     * @return string
     */
    public function serialize()
    {
        $clone = clone $this;
        $clone->setExtractFlags(self::EXTR_BOTH);

        $data = [];
        foreach ($clone as $item) {
            $data[] = $item;
        }

        return serialize($data);
    }

    /**
     * Deserialize
     *
     * @param  string $data
     * @return void
     */
    public function unserialize($data)
    {
        foreach (unserialize($data) as $item) {
            $this->insert($item['data'], $item['priority']);
        }
    }

    /**
     * Set the extract flag
     *
     * @param integer $flag
     */
    public function setExtractFlags($flag)
    {
        switch ($flag) {
            case self::EXTR_DATA:
            case self::EXTR_PRIORITY:
            case self::EXTR_BOTH:
                $this->extractFlag = $flag;
                break;
            default:
                throw new Exception\InvalidArgumentException("The extract flag specified is not valid");
        }
    }

    /**
     * Check if the queue is empty
     *
     * @return boolean
     */
    public function isEmpty()
    {
        return empty($this->values);
    }

    /**
     * Does the queue contain the given datum?
     *
     * @param  mixed $datum
     * @return bool
     */
    public function contains($datum)
    {
        foreach ($this->values as $values) {
            if (in_array($datum, $values)) {
                return true;
            }
        }
        return false;
    }

    /**
     * Does the queue have an item with the given priority?
     *
     * @param  int $priority
     * @return bool
     */
    public function hasPriority($priority)
    {
        return isset($this->values[$priority]);
    }
}
laminas-stdlib/src/StringUtils.php000064400000012754147361032560013256 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-stdlib for the canonical source repository
 * @copyright https://github.com/laminas/laminas-stdlib/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-stdlib/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Stdlib;

use Laminas\Stdlib\StringWrapper\StringWrapperInterface;

use function array_search;
use function defined;
use function extension_loaded;
use function in_array;
use function is_string;
use function preg_match;
use function strtoupper;

/**
 * Utility class for handling strings of different character encodings
 * using available PHP extensions.
 *
 * Declared abstract, as we have no need for instantiation.
 */
abstract class StringUtils
{
    /**
     * Ordered list of registered string wrapper instances
     *
     * @var StringWrapperInterface[]
     */
    protected static $wrapperRegistry = null;

    /**
     * A list of known single-byte character encodings (upper-case)
     *
     * @var string[]
     */
    protected static $singleByteEncodings = [
        'ASCII', '7BIT', '8BIT',
        'ISO-8859-1', 'ISO-8859-2', 'ISO-8859-3', 'ISO-8859-4', 'ISO-8859-5',
        'ISO-8859-6', 'ISO-8859-7', 'ISO-8859-8', 'ISO-8859-9', 'ISO-8859-10',
        'ISO-8859-11', 'ISO-8859-13', 'ISO-8859-14', 'ISO-8859-15', 'ISO-8859-16',
        'CP-1251', 'CP-1252',
        // TODO
    ];

    /**
     * Is PCRE compiled with Unicode support?
     *
     * @var bool
     **/
    protected static $hasPcreUnicodeSupport = null;

    /**
     * Get registered wrapper classes
     *
     * @return string[]
     */
    public static function getRegisteredWrappers()
    {
        if (static::$wrapperRegistry === null) {
            static::$wrapperRegistry = [];

            if (extension_loaded('intl')) {
                static::$wrapperRegistry[] = 'Laminas\Stdlib\StringWrapper\Intl';
            }

            if (extension_loaded('mbstring')) {
                static::$wrapperRegistry[] = 'Laminas\Stdlib\StringWrapper\MbString';
            }

            if (extension_loaded('iconv')) {
                static::$wrapperRegistry[] = 'Laminas\Stdlib\StringWrapper\Iconv';
            }

            static::$wrapperRegistry[] = 'Laminas\Stdlib\StringWrapper\Native';
        }

        return static::$wrapperRegistry;
    }

    /**
     * Register a string wrapper class
     *
     * @param string $wrapper
     * @return void
     */
    public static function registerWrapper($wrapper)
    {
        $wrapper = (string) $wrapper;
        if (! in_array($wrapper, static::$wrapperRegistry, true)) {
            static::$wrapperRegistry[] = $wrapper;
        }
    }

    /**
     * Unregister a string wrapper class
     *
     * @param string $wrapper
     * @return void
     */
    public static function unregisterWrapper($wrapper)
    {
        $index = array_search((string) $wrapper, static::$wrapperRegistry, true);
        if ($index !== false) {
            unset(static::$wrapperRegistry[$index]);
        }
    }

    /**
     * Reset all registered wrappers so the default wrappers will be used
     *
     * @return void
     */
    public static function resetRegisteredWrappers()
    {
        static::$wrapperRegistry = null;
    }

    /**
     * Get the first string wrapper supporting the given character encoding
     * and supports to convert into the given convert encoding.
     *
     * @param string      $encoding        Character encoding to support
     * @param string|null $convertEncoding OPTIONAL character encoding to convert in
     * @return StringWrapperInterface
     * @throws Exception\RuntimeException If no wrapper supports given character encodings
     */
    public static function getWrapper($encoding = 'UTF-8', $convertEncoding = null)
    {
        foreach (static::getRegisteredWrappers() as $wrapperClass) {
            if ($wrapperClass::isSupported($encoding, $convertEncoding)) {
                $wrapper = new $wrapperClass($encoding, $convertEncoding);
                $wrapper->setEncoding($encoding, $convertEncoding);
                return $wrapper;
            }
        }

        throw new Exception\RuntimeException(
            'No wrapper found supporting "' . $encoding . '"'
            . (($convertEncoding !== null) ? ' and "' . $convertEncoding . '"' : '')
        );
    }

    /**
     * Get a list of all known single-byte character encodings
     *
     * @return string[]
     */
    public static function getSingleByteEncodings()
    {
        return static::$singleByteEncodings;
    }

    /**
     * Check if a given encoding is a known single-byte character encoding
     *
     * @param string $encoding
     * @return bool
     */
    public static function isSingleByteEncoding($encoding)
    {
        return in_array(strtoupper($encoding), static::$singleByteEncodings);
    }

    /**
     * Check if a given string is valid UTF-8 encoded
     *
     * @param string $str
     * @return bool
     */
    public static function isValidUtf8($str)
    {
        return is_string($str) && ($str === '' || preg_match('/^./su', $str) == 1);
    }

    /**
     * Is PCRE compiled with Unicode support?
     *
     * @return bool
     */
    public static function hasPcreUnicodeSupport()
    {
        if (static::$hasPcreUnicodeSupport === null) {
            ErrorHandler::start();
            static::$hasPcreUnicodeSupport = defined('PREG_BAD_UTF8_OFFSET_ERROR') && preg_match('/\pL/u', 'a') == 1;
            ErrorHandler::stop();
        }
        return static::$hasPcreUnicodeSupport;
    }
}
laminas-stdlib/src/ParameterObjectInterface.php000064400000001405147361032560015646 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-stdlib for the canonical source repository
 * @copyright https://github.com/laminas/laminas-stdlib/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-stdlib/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Stdlib;

interface ParameterObjectInterface
{
    /**
     * @param string $key
     * @param mixed $value
     * @return void
     */
    public function __set($key, $value);

    /**
     * @param string $key
     * @return mixed
     */
    public function __get($key);

    /**
     * @param string $key
     * @return bool
     */
    public function __isset($key);

    /**
     * @param string $key
     * @return void
     */
    public function __unset($key);
}
laminas-stdlib/src/Exception/LogicException.php000064400000000653147361032560015634 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-stdlib for the canonical source repository
 * @copyright https://github.com/laminas/laminas-stdlib/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-stdlib/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Stdlib\Exception;

/**
 * Logic exception
 */
class LogicException extends \LogicException implements ExceptionInterface
{
}
laminas-stdlib/src/Exception/ExceptionInterface.php000064400000000610147361032560016470 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-stdlib for the canonical source repository
 * @copyright https://github.com/laminas/laminas-stdlib/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-stdlib/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Stdlib\Exception;

/**
 * Exception marker interface
 */
interface ExceptionInterface
{
}
laminas-stdlib/src/Exception/DomainException.php000064400000000656147361032560016011 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-stdlib for the canonical source repository
 * @copyright https://github.com/laminas/laminas-stdlib/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-stdlib/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Stdlib\Exception;

/**
 * Domain exception
 */
class DomainException extends \DomainException implements ExceptionInterface
{
}
laminas-stdlib/src/Exception/InvalidArgumentException.php000064400000000712147361032560017664 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-stdlib for the canonical source repository
 * @copyright https://github.com/laminas/laminas-stdlib/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-stdlib/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Stdlib\Exception;

/**
 * Invalid Argument Exception
 */
class InvalidArgumentException extends \InvalidArgumentException implements ExceptionInterface
{
}
laminas-stdlib/src/Exception/ExtensionNotLoadedException.php000064400000000652147361032560020344 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-stdlib for the canonical source repository
 * @copyright https://github.com/laminas/laminas-stdlib/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-stdlib/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Stdlib\Exception;

/**
 * Extension not loaded exception
 */
class ExtensionNotLoadedException extends RuntimeException
{
}
laminas-stdlib/src/Exception/BadMethodCallException.php000064400000000705147361032560017220 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-stdlib for the canonical source repository
 * @copyright https://github.com/laminas/laminas-stdlib/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-stdlib/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Stdlib\Exception;

/**
 * Bad method call exception
 */
class BadMethodCallException extends \BadMethodCallException implements ExceptionInterface
{
}
laminas-stdlib/src/Exception/RuntimeException.php000064400000000661147361032560016221 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-stdlib for the canonical source repository
 * @copyright https://github.com/laminas/laminas-stdlib/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-stdlib/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Stdlib\Exception;

/**
 * Runtime exception
 */
class RuntimeException extends \RuntimeException implements ExceptionInterface
{
}
laminas-stdlib/src/Glob.php000064400000013440147361032560011643 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-stdlib for the canonical source repository
 * @copyright https://github.com/laminas/laminas-stdlib/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-stdlib/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Stdlib;

use function array_merge;
use function array_unique;
use function defined;
use function glob;
use function strlen;
use function strpos;
use function substr;

use const GLOB_BRACE;
use const GLOB_ERR;
use const GLOB_MARK;
use const GLOB_NOCHECK;
use const GLOB_NOESCAPE;
use const GLOB_NOSORT;
use const GLOB_ONLYDIR;

/**
 * Wrapper for glob with fallback if GLOB_BRACE is not available.
 */
abstract class Glob
{
    /**#@+
     * Glob constants.
     */
    const GLOB_MARK     = 0x01;
    const GLOB_NOSORT   = 0x02;
    const GLOB_NOCHECK  = 0x04;
    const GLOB_NOESCAPE = 0x08;
    const GLOB_BRACE    = 0x10;
    const GLOB_ONLYDIR  = 0x20;
    const GLOB_ERR      = 0x40;
    /**#@-*/

    /**
     * Find pathnames matching a pattern.
     *
     * @see    http://docs.php.net/glob
     * @param  string  $pattern
     * @param  int $flags
     * @param  bool $forceFallback
     * @return array
     * @throws Exception\RuntimeException
     */
    public static function glob($pattern, $flags = 0, $forceFallback = false)
    {
        if (! defined('GLOB_BRACE') || $forceFallback) {
            return static::fallbackGlob($pattern, $flags);
        }

        return static::systemGlob($pattern, $flags);
    }

    /**
     * Use the glob function provided by the system.
     *
     * @param  string  $pattern
     * @param  int     $flags
     * @return array
     * @throws Exception\RuntimeException
     */
    protected static function systemGlob($pattern, $flags)
    {
        if ($flags) {
            $flagMap = [
                self::GLOB_MARK     => GLOB_MARK,
                self::GLOB_NOSORT   => GLOB_NOSORT,
                self::GLOB_NOCHECK  => GLOB_NOCHECK,
                self::GLOB_NOESCAPE => GLOB_NOESCAPE,
                self::GLOB_BRACE    => defined('GLOB_BRACE') ? GLOB_BRACE : 0,
                self::GLOB_ONLYDIR  => GLOB_ONLYDIR,
                self::GLOB_ERR      => GLOB_ERR,
            ];

            $globFlags = 0;

            foreach ($flagMap as $internalFlag => $globFlag) {
                if ($flags & $internalFlag) {
                    $globFlags |= $globFlag;
                }
            }
        } else {
            $globFlags = 0;
        }

        ErrorHandler::start();
        $res = glob($pattern, $globFlags);
        $err = ErrorHandler::stop();
        if ($res === false) {
            throw new Exception\RuntimeException("glob('{$pattern}', {$globFlags}) failed", 0, $err);
        }
        return $res;
    }

    /**
     * Expand braces manually, then use the system glob.
     *
     * @param  string  $pattern
     * @param  int     $flags
     * @return array
     * @throws Exception\RuntimeException
     */
    protected static function fallbackGlob($pattern, $flags)
    {
        if (! $flags & self::GLOB_BRACE) {
            return static::systemGlob($pattern, $flags);
        }

        $flags &= ~self::GLOB_BRACE;
        $length = strlen($pattern);
        $paths  = [];

        if ($flags & self::GLOB_NOESCAPE) {
            $begin = strpos($pattern, '{');
        } else {
            $begin = 0;

            while (true) {
                if ($begin === $length) {
                    $begin = false;
                    break;
                } elseif ($pattern[$begin] === '\\' && ($begin + 1) < $length) {
                    $begin++;
                } elseif ($pattern[$begin] === '{') {
                    break;
                }

                $begin++;
            }
        }

        if ($begin === false) {
            return static::systemGlob($pattern, $flags);
        }

        $next = static::nextBraceSub($pattern, $begin + 1, $flags);

        if ($next === null) {
            return static::systemGlob($pattern, $flags);
        }

        $rest = $next;

        while ($pattern[$rest] !== '}') {
            $rest = static::nextBraceSub($pattern, $rest + 1, $flags);

            if ($rest === null) {
                return static::systemGlob($pattern, $flags);
            }
        }

        $p = $begin + 1;

        while (true) {
            $subPattern = substr($pattern, 0, $begin)
                        . substr($pattern, $p, $next - $p)
                        . substr($pattern, $rest + 1);

            $result = static::fallbackGlob($subPattern, $flags | self::GLOB_BRACE);

            if ($result) {
                $paths = array_merge($paths, $result);
            }

            if ($pattern[$next] === '}') {
                break;
            }

            $p    = $next + 1;
            $next = static::nextBraceSub($pattern, $p, $flags);
        }

        return array_unique($paths);
    }

    /**
     * Find the end of the sub-pattern in a brace expression.
     *
     * @param  string  $pattern
     * @param  int $begin
     * @param  int $flags
     * @return int|null
     */
    protected static function nextBraceSub($pattern, $begin, $flags)
    {
        $length  = strlen($pattern);
        $depth   = 0;
        $current = $begin;

        while ($current < $length) {
            if (! $flags & self::GLOB_NOESCAPE && $pattern[$current] === '\\') {
                if (++$current === $length) {
                    break;
                }

                $current++;
            } else {
                if (($pattern[$current] === '}' && $depth-- === 0) || ($pattern[$current] === ',' && $depth === 0)) {
                    break;
                } elseif ($pattern[$current++] === '{') {
                    $depth++;
                }
            }
        }

        return ($current < $length ? $current : null);
    }
}
laminas-stdlib/src/ConsoleHelper.php000064400000011320147361032560013515 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-stdlib for the canonical source repository
 * @copyright https://github.com/laminas/laminas-stdlib/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-stdlib/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Stdlib;

use function function_exists;
use function fwrite;
use function getenv;
use function posix_isatty;
use function preg_replace;
use function sprintf;
use function str_replace;

use const DIRECTORY_SEPARATOR;
use const PHP_EOL;
use const STDERR;
use const STDOUT;

/**
 * Utilities for console tooling.
 *
 * Provides the following facilities:
 *
 * - Colorize strings using markup (e.g., `<info>message</info>`,
 *   `<error>message</error>`)
 * - Write output to a specified stream, optionally with colorization.
 * - Write a line of output to a specified stream, optionally with
 *   colorization, using the system EOL sequence..
 * - Write an error message to STDERR.
 *
 * Colorization will only occur when expected sequences are discovered, and
 * then, only if the console terminal allows it.
 *
 * Essentially, provides the bare minimum to allow you to provide messages to
 * the current console.
 */
class ConsoleHelper
{
    const COLOR_GREEN = "\033[32m";
    const COLOR_RED   = "\033[31m";
    const COLOR_RESET = "\033[0m";

    const HIGHLIGHT_INFO  = 'info';
    const HIGHLIGHT_ERROR = 'error';

    private $highlightMap = [
        self::HIGHLIGHT_INFO  => self::COLOR_GREEN,
        self::HIGHLIGHT_ERROR => self::COLOR_RED,
    ];

    /**
     * @var string Exists only for testing.
     */
    private $eol = PHP_EOL;

    /**
     * @var resource Exists only for testing.
     */
    private $stderr = STDERR;

    /**
     * @var bool
     */
    private $supportsColor;

    /**
     * @param resource $resource
     */
    public function __construct($resource = STDOUT)
    {
        $this->supportsColor = $this->detectColorCapabilities($resource);
    }

    /**
     * Colorize a string for use with the terminal.
     *
     * Takes strings formatted as `<key>string</key>` and formats them per the
     * $highlightMap; if color support is disabled, simply removes the formatting
     * tags.
     *
     * @param string $string
     * @return string
     */
    public function colorize($string)
    {
        $reset = $this->supportsColor ? self::COLOR_RESET : '';
        foreach ($this->highlightMap as $key => $color) {
            $pattern = sprintf('#<%s>(.*?)</%s>#s', $key, $key);
            $color   = $this->supportsColor ? $color : '';
            $string  = preg_replace($pattern, $color . '$1' . $reset, $string);
        }
        return $string;
    }

    /**
     * @param string $string
     * @param bool $colorize Whether or not to colorize the string
     * @param resource $resource Defaults to STDOUT
     * @return void
     */
    public function write($string, $colorize = true, $resource = STDOUT)
    {
        if ($colorize) {
            $string = $this->colorize($string);
        }

        $string = $this->formatNewlines($string);

        fwrite($resource, $string);
    }

    /**
     * @param string $string
     * @param bool $colorize Whether or not to colorize the line
     * @param resource $resource Defaults to STDOUT
     * @return void
     */
    public function writeLine($string, $colorize = true, $resource = STDOUT)
    {
        $this->write($string . $this->eol, $colorize, $resource);
    }

    /**
     * Emit an error message.
     *
     * Wraps the message in `<error></error>`, and passes it to `writeLine()`,
     * using STDERR as the resource; emits an additional empty line when done,
     * also to STDERR.
     *
     * @param string $message
     * @return void
     */
    public function writeErrorMessage($message)
    {
        $this->writeLine(sprintf('<error>%s</error>', $message), true, $this->stderr);
        $this->writeLine('', false, $this->stderr);
    }

    /**
     * @param resource $resource
     * @return bool
     */
    private function detectColorCapabilities($resource = STDOUT)
    {
        if ('\\' === DIRECTORY_SEPARATOR) {
            // Windows
            return false !== getenv('ANSICON')
                || 'ON' === getenv('ConEmuANSI')
                || 'xterm' === getenv('TERM');
        }

        return function_exists('posix_isatty') && posix_isatty($resource);
    }

    /**
     * Ensure newlines are appropriate for the current terminal.
     *
     * @param string
     * @return string
     */
    private function formatNewlines($string)
    {
        $string = str_replace($this->eol, "\0PHP_EOL\0", $string);
        $string = preg_replace("/(\r\n|\n|\r)/", $this->eol, $string);
        return str_replace("\0PHP_EOL\0", $this->eol, $string);
    }
}
laminas-stdlib/src/SplQueue.php000064400000002140147361032560012516 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-stdlib for the canonical source repository
 * @copyright https://github.com/laminas/laminas-stdlib/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-stdlib/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Stdlib;

use Serializable;

use function serialize;
use function unserialize;

/**
 * Serializable version of SplQueue
 */
class SplQueue extends \SplQueue implements Serializable
{
    /**
     * Return an array representing the queue
     *
     * @return array
     */
    public function toArray()
    {
        $array = [];
        foreach ($this as $item) {
            $array[] = $item;
        }
        return $array;
    }

    /**
     * Serialize
     *
     * @return string
     */
    public function serialize()
    {
        return serialize($this->toArray());
    }

    /**
     * Unserialize
     *
     * @param  string $data
     * @return void
     */
    public function unserialize($data)
    {
        foreach (unserialize($data) as $item) {
            $this->push($item);
        }
    }
}
laminas-stdlib/src/ResponseInterface.php000064400000000560147361032560014376 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-stdlib for the canonical source repository
 * @copyright https://github.com/laminas/laminas-stdlib/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-stdlib/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Stdlib;

interface ResponseInterface extends MessageInterface
{
}
laminas-stdlib/src/ArrayStack.php000064400000001535147361032560013026 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-stdlib for the canonical source repository
 * @copyright https://github.com/laminas/laminas-stdlib/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-stdlib/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Stdlib;

use ArrayIterator;
use ArrayObject as PhpArrayObject;

use function array_reverse;

/**
 * ArrayObject that acts as a stack with regards to iteration
 */
class ArrayStack extends PhpArrayObject
{
    /**
     * Retrieve iterator
     *
     * Retrieve an array copy of the object, reverse its order, and return an
     * ArrayIterator with that reversed array.
     *
     * @return ArrayIterator
     */
    public function getIterator()
    {
        $array = $this->getArrayCopy();
        return new ArrayIterator(array_reverse($array));
    }
}
laminas-stdlib/src/AbstractOptions.php000064400000011601147361032560014074 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-stdlib for the canonical source repository
 * @copyright https://github.com/laminas/laminas-stdlib/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-stdlib/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Stdlib;

use Traversable;

use function array_shift;
use function is_array;
use function is_callable;
use function method_exists;
use function preg_replace_callback;
use function sprintf;
use function str_replace;
use function strtolower;
use function ucwords;

abstract class AbstractOptions implements ParameterObjectInterface
{
    // @codingStandardsIgnoreStart
    /**
     * We use the __ prefix to avoid collisions with properties in
     * user-implementations.
     *
     * @var bool
     */
    protected $__strictMode__ = true;
    // @codingStandardsIgnoreEnd

    /**
     * Constructor
     *
     * @param  array|Traversable|null $options
     */
    public function __construct($options = null)
    {
        if (null !== $options) {
            $this->setFromArray($options);
        }
    }

    /**
     * Set one or more configuration properties
     *
     * @param  array|Traversable|AbstractOptions $options
     * @throws Exception\InvalidArgumentException
     * @return AbstractOptions Provides fluent interface
     */
    public function setFromArray($options)
    {
        if ($options instanceof self) {
            $options = $options->toArray();
        }

        if (! is_array($options) && ! $options instanceof Traversable) {
            throw new Exception\InvalidArgumentException(
                sprintf(
                    'Parameter provided to %s must be an %s, %s or %s',
                    __METHOD__,
                    'array',
                    'Traversable',
                    'Laminas\Stdlib\AbstractOptions'
                )
            );
        }

        foreach ($options as $key => $value) {
            $this->__set($key, $value);
        }

        return $this;
    }

    /**
     * Cast to array
     *
     * @return array
     */
    public function toArray()
    {
        $array = [];
        $transform = function ($letters) {
            $letter = array_shift($letters);
            return '_' . strtolower($letter);
        };
        foreach ($this as $key => $value) {
            if ($key === '__strictMode__') {
                continue;
            }
            $normalizedKey = preg_replace_callback('/([A-Z])/', $transform, $key);
            $array[$normalizedKey] = $value;
        }
        return $array;
    }

    /**
     * Set a configuration property
     *
     * @see ParameterObject::__set()
     * @param string $key
     * @param mixed $value
     * @throws Exception\BadMethodCallException
     * @return void
     */
    public function __set($key, $value)
    {
        $setter = 'set' . str_replace('_', '', $key);

        if (is_callable([$this, $setter])) {
            $this->{$setter}($value);

            return;
        }

        if ($this->__strictMode__) {
            throw new Exception\BadMethodCallException(sprintf(
                'The option "%s" does not have a callable "%s" ("%s") setter method which must be defined',
                $key,
                'set' . str_replace(' ', '', ucwords(str_replace('_', ' ', $key))),
                $setter
            ));
        }
    }

    /**
     * Get a configuration property
     *
     * @see ParameterObject::__get()
     * @param string $key
     * @throws Exception\BadMethodCallException
     * @return mixed
     */
    public function __get($key)
    {
        $getter = 'get' . str_replace('_', '', $key);

        if (is_callable([$this, $getter])) {
            return $this->{$getter}();
        }

        throw new Exception\BadMethodCallException(sprintf(
            'The option "%s" does not have a callable "%s" getter method which must be defined',
            $key,
            'get' . str_replace(' ', '', ucwords(str_replace('_', ' ', $key)))
        ));
    }

    /**
     * Test if a configuration property is null
     * @see ParameterObject::__isset()
     * @param string $key
     * @return bool
     */
    public function __isset($key)
    {
        $getter = 'get' . str_replace('_', '', $key);

        return method_exists($this, $getter) && null !== $this->__get($key);
    }

    /**
     * Set a configuration property to NULL
     *
     * @see ParameterObject::__unset()
     * @param string $key
     * @throws Exception\InvalidArgumentException
     * @return void
     */
    public function __unset($key)
    {
        try {
            $this->__set($key, null);
        } catch (Exception\BadMethodCallException $e) {
            throw new Exception\InvalidArgumentException(
                'The class property $' . $key . ' cannot be unset as'
                . ' NULL is an invalid value for it',
                0,
                $e
            );
        }
    }
}
laminas-stdlib/src/MessageInterface.php000064400000001604147361032560014164 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-stdlib for the canonical source repository
 * @copyright https://github.com/laminas/laminas-stdlib/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-stdlib/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Stdlib;

interface MessageInterface
{
    /**
     * Set metadata
     *
     * @param  string|int|array|\Traversable $spec
     * @param  mixed $value
     */
    public function setMetadata($spec, $value = null);

    /**
     * Get metadata
     *
     * @param  null|string|int $key
     * @return mixed
     */
    public function getMetadata($key = null);

    /**
     * Set content
     *
     * @param  mixed $content
     * @return mixed
     */
    public function setContent($content);

    /**
     * Get content
     *
     * @return mixed
     */
    public function getContent();
}
laminas-stdlib/README.md000064400000001674147361032560010745 0ustar00# laminas-stdlib

[![Build Status](https://travis-ci.com/laminas/laminas-stdlib.svg?branch=master)](https://travis-ci.com/laminas/laminas-stdlib)
[![Coverage Status](https://coveralls.io/repos/github/laminas/laminas-stdlib/badge.svg?branch=master)](https://coveralls.io/github/laminas/laminas-stdlib?branch=master)

`Laminas\Stdlib` is a set of components that implements general purpose utility
class for different scopes like:

- array utilities functions;
- general messaging systems;
- string wrappers;
- etc.

---

- File issues at https://github.com/laminas/laminas-stdlib/issues
- Documentation is at https://docs.laminas.dev/laminas-stdlib/

## Benchmarks

We provide scripts for benchmarking laminas-stdlib using the
[PHPBench](https://github.com/phpbench/phpbench) framework; these can be
found in the `benchmark/` directory.

To execute the benchmarks you can run the following command:

```bash
$ vendor/bin/phpbench run --report=aggregate
```
laminas-stdlib/CHANGELOG.md000064400000024573147361032560011302 0ustar00# Changelog

All notable changes to this project will be documented in this file, in reverse chronological order by release.

## 3.3.0 - 2020-08-25

### Added

- [#9](https://github.com/laminas/laminas-stdlib/pull/9) adds support for the upcoming PHP 8.0 release.

### Changed

- Nothing.

### Deprecated

- Nothing.

### Removed

- [#10](https://github.com/laminas/laminas-stdlib/pull/10) removes support for PHP versions prior to PHP 7.3.

### Fixed

- Nothing.

## 3.2.1 - 2018-08-28

### Added

- Nothing.

### Changed

- Nothing.

### Deprecated

- Nothing.

### Removed

- Nothing.

### Fixed

- [zendframework/zend-stdlib#92](https://github.com/zendframework/zend-stdlib/pull/92) fixes serialization of `SplPriorityQueue` by ensuring its `$serial`
  property is also serialized.

- [zendframework/zend-stdlib#91](https://github.com/zendframework/zend-stdlib/pull/91) fixes behavior in the `ArrayObject` implementation that was not
  compatible with PHP 7.3.

## 3.2.0 - 2018-04-30

### Added

- [zendframework/zend-stdlib#87](https://github.com/zendframework/zend-stdlib/pull/87) adds support for PHP 7.2.

### Changed

- Nothing.

### Deprecated

- Nothing.

### Removed

- [zendframework/zend-stdlib#87](https://github.com/zendframework/zend-stdlib/pull/87) removes support for HHVM.

### Fixed

- Nothing.

## 3.1.1 - 2018-04-12

### Added

- Nothing.

### Changed

- [zendframework/zend-stdlib#67](https://github.com/zendframework/zend-stdlib/pull/67) changes the typehint of the `$content` property
  of the `Message` class to indicate it is a string. All known implementations
  already assumed this.

### Deprecated

- Nothing.

### Removed

- Nothing.

### Fixed

- [zendframework/zend-stdlib#60](https://github.com/zendframework/zend-stdlib/pull/60) fixes an issue whereby calling `remove()` would
  incorrectly re-calculate the maximum priority stored in the queue.

- [zendframework/zend-stdlib#60](https://github.com/zendframework/zend-stdlib/pull/60) fixes an infinite loop condition that can occur when
  inserting an item at 0 priority.

## 3.1.0 - 2016-09-13

### Added

- [zendframework/zend-stdlib#63](https://github.com/zendframework/zend-stdlib/pull/63) adds a new
  `Laminas\Stdlib\ConsoleHelper` class, providing minimal support for writing
  output to `STDOUT` and `STDERR`, with optional colorization, when the console
  supports that feature.

### Deprecated

- [zendframework/zend-stdlib#38](https://github.com/zendframework/zend-stdlib/pull/38) deprecates
  `Laminas\Stdlib\JsonSerializable`, as all supported version of PHP now support
  it.

### Removed

- Nothing.

### Fixed

- Nothing.

## 3.0.1 - 2016-04-12

### Added

- Nothing.

### Deprecated

- Nothing.

### Removed

- Nothing.

### Fixed

- [zendframework/zend-stdlib#59](https://github.com/zendframework/zend-stdlib/pull/59) fixes a notice
  when defining the `Laminas\Json\Json::GLOB_BRACE` constant on systems using
  non-gcc glob implementations.

## 3.0.0 - 2016-02-03

### Added

- [zendframework/zend-stdlib#51](https://github.com/zendframework/zend-stdlib/pull/51) adds PHP 7 as a
  supported PHP version.
- [zendframework/zend-stdlib#51](https://github.com/zendframework/zend-stdlib/pull/51) adds a migration
  document from v2 to v3. Hint: if you use hydrators, you need to be using
  laminas-hydrator instead!
- [zendframework/zend-stdlib#51](https://github.com/zendframework/zend-stdlib/pull/51) adds automated
  documentation builds to gh-pages.

### Deprecated

- Nothing.

### Removed

- [zendframework/zend-stdlib#33](https://github.com/zendframework/zend-stdlib/pull/33) - removed
  deprecated classes
  - *All Hydrator classes* see zendframework/zend-stdlib#22.
  - `Laminas\Stdlib\CallbackHandler` see zendframework/zend-stdlib#35
- [zendframework/zend-stdlib#37](https://github.com/zendframework/zend-stdlib/pull/37) - removed
  deprecated classes and polyfills:
  - `Laminas\Stdlib\DateTime`; this had been deprecated since 2.5, and only
    existed as a polyfill for the `createFromISO8601()` support, now standard
    in all PHP versions we support.
  - `Laminas\Stdlib\Exception\InvalidCallbackException`, which was unused since zendframework/zend-stdlib#33.
  - `Laminas\Stdlib\Guard\GuardUtils`, which duplicated `Laminas\Stdlib\Guard\AllGuardsTrait`
    to allow usage with pre-PHP 5.4 versions.
  - `src/compatibility/autoload.php`, which has been dprecated since 2.5.
- [zendframework/zend-stdlib#37](https://github.com/zendframework/zend-stdlib/pull/37) - removed
  unneeded dependencies:
  - laminas-config (used only in testing ArrayUtils, and the test was redundant)
  - laminas-serializer (no longer used)
- [zendframework/zend-stdlib#51](https://github.com/zendframework/zend-stdlib/pull/51) removes the
  documentation for hydrators, as those are part of the laminas-hydrator
  component.

### Fixed

- Nothing.

## 2.7.4 - 2015-10-15

### Added

- Nothing.

### Deprecated

- [zendframework/zend-stdlib#35](https://github.com/zendframework/zend-stdlib/pull/35) deprecates
  `Laminas\Stdlib\CallbackHandler`, as the one component that used it,
  laminas-eventmanager, will no longer depend on it starting in v3.

### Removed

- Nothing.

### Fixed

- Nothing.

## 2.7.3 - 2015-09-24

### Added

- Nothing.

### Deprecated

- Nothing.

### Removed

- Nothing.

### Fixed

- [zendframework/zend-stdlib#27](https://github.com/zendframework/zend-stdlib/pull/27) fixes a race
  condition in the `FastPriorityQueue::remove()` logic that occurs when removing
  items iteratively from the same priority of a queue.

## 2.7.2 - 2015-09-23

### Added

- Nothing.

### Deprecated

- Nothing.

### Removed

- Nothing.

### Fixed

- [zendframework/zend-stdlib#26](https://github.com/zendframework/zend-stdlib/pull/26) fixes a subtle
  inheritance issue with deprecation in the hydrators, and updates the
  `HydratorInterface` to also extend the laminas-hydrator `HydratorInterface` to
  ensure LSP is preserved.

## 2.7.1 - 2015-09-22

### Added

- Nothing.

### Deprecated

- Nothing.

### Removed

- Nothing.

### Fixed

- [zendframework/zend-stdlib#24](https://github.com/zendframework/zend-stdlib/pull/24) fixes an import in
  `FastPriorityQueue` to alias `SplPriorityQueue` in order to disambiguate with
  the local override present in the component.

## 2.7.0 - 2015-09-22

### Added

- [zendframework/zend-stdlib#19](https://github.com/zendframework/zend-stdlib/pull/19) adds a new
  `FastPriorityQueue` implementation. It follows the same signature as
  `SplPriorityQueue`, but uses a performance-optimized algorithm:

  - inserts are 2x faster than `SplPriorityQueue` and 3x faster than the
    `Laminas\Stdlib\PriorityQueue` implementation.
  - extracts are 4x faster than `SplPriorityQueue` and 4-5x faster than the
    `Laminas\Stdlib\PriorityQueue` implementation.

  The intention is to use this as a drop-in replacement in the
  `laminas-eventmanager` component to provide performance benefits.

### Deprecated

- [zendframework/zend-stdlib#20](https://github.com/zendframework/zend-stdlib/pull/20) deprecates *all
  hydrator* classes, in favor of the new [laminas-hydrator](https://github.com/laminas/laminas-hydrator)
  component. All classes were updated to extend their laminas-hydrator equivalents,
  and marked as `@deprecated`, indicating the equivalent class from the other
  repository.

  Users *should* immediately start changing their code to use the laminas-hydrator
  equivalents; in most cases, this can be as easy as removing the `Stdlib`
  namespace from import statements or hydrator configuration. Hydrators will be
  removed entirely from laminas-stdlib in v3.0, and all future updates to hydrators
  will occur in the laminas-hydrator library.

  Changes with backwards compatibility implications:

  - Users implementing `Laminas\Stdlib\Hydrator\HydratorAwareInterface` will need to
    update their `setHydrator()` implementation to typehint on
    `Laminas\Hydrator\HydratorInterface`. This can be done by changing the import
    statement for that interface as follows:

    ```php
    // Replace this:
    use Laminas\Stdlib\Hydrator\HydratorInterface;
    // with this:
    use Laminas\Hydrator\HydratorInterface;
    ```

    If you are not using imports, change the typehint within the signature itself:

    ```php
    // Replace this:
    public function setHydrator(\Laminas\Stdlib\Hydrator\HydratorInterface $hydrator)
    // with this:
    public function setHydrator(\Laminas\Hydrator\HydratorInterface $hydrator)
    ```

    If you are using `Laminas\Stdlib\Hydrator\HydratorAwareTrait`, no changes are
    necessary, unless you override that method.

  - If you were catching hydrator-generated exceptions, these were previously in
    the `Laminas\Stdlib\Exception` namespace. You will need to update your code to
    catch exceptions in the `Laminas\Hydrator\Exception` namespace.

  - Users who *do* migrate to laminas-hydrator may end up in a situation where
    their code will not work with existing libraries that are still type-hinting
    on the laminas-stdlib interfaces. We will be attempting to address that ASAP,
    but the deprecation within laminas-stdlib is necessary as a first step.

    In the meantime, you can write hydrators targeting laminas-stdlib still in
    order to guarantee compatibility.

### Removed

- Nothing.

### Fixed

- Nothing.

## 2.6.0 - 2015-07-21

### Added

- [zendframework/zend-stdlib#13](https://github.com/zendframework/zend-stdlib/pull/13) adds
  `Laminas\Stdlib\Hydrator\Iterator`, which provides mechanisms for hydrating
  objects when iterating a traversable. This allows creating generic collection
  resultsets; the original idea was pulled from
  [PhlyMongo](https://github.com/phly/PhlyMongo), where it was used to hydrate
  collections retrieved from MongoDB.

### Deprecated

- Nothing.

### Removed

- Nothing.

### Fixed

- Nothing.

## 2.5.2 - 2015-07-21

### Added

- Nothing.

### Deprecated

- Nothing.

### Removed

- Nothing.

### Fixed

- [zendframework/zend-stdlib#9](https://github.com/zendframework/zend-stdlib/pull/9) fixes an issue with
  count incrementation during insert in PriorityList, ensuring that incrementation only
  occurs when the item inserted was not previously present in the list.

## 2.4.4 - 2015-07-21

### Added

- Nothing.

### Deprecated

- Nothing.

### Removed

- Nothing.

### Fixed

- [zendframework/zend-stdlib#9](https://github.com/zendframework/zend-stdlib/pull/9) fixes an issue with
  count incrementation during insert in PriorityList, ensuring that incrementation only
  occurs when the item inserted was not previously present in the list.
laminas-stdlib/LICENSE.md000064400000002732147361032560011066 0ustar00Copyright (c) 2020 Laminas Project a Series of LF Projects, LLC.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

- Redistributions of source code must retain the above copyright notice, this
  list of conditions and the following disclaimer.

- Redistributions in binary form must reproduce the above copyright notice,
  this list of conditions and the following disclaimer in the documentation
  and/or other materials provided with the distribution.

- Neither the name of Laminas Foundation nor the names of its contributors may
  be used to endorse or promote products derived from this software without
  specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
laminas-loader/COPYRIGHT.md000064400000000127147361032560011335 0ustar00Copyright (c) 2019, Laminas Foundation.
All rights reserved. (https://getlaminas.org/)
laminas-loader/src/ModuleAutoloader.php000064400000031624147361032560014216 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-loader for the canonical source repository
 * @copyright https://github.com/laminas/laminas-loader/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-loader/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Loader;

// Grab SplAutoloader interface
require_once __DIR__ . '/SplAutoloader.php';

use GlobIterator;
use Phar;
use PharFileInfo;
use SplFileInfo;
use Traversable;

class ModuleAutoloader implements SplAutoloader
{
    /**
     * @var array An array of module paths to scan
     */
    protected $paths = [];

    /**
     * @var array An array of modulename => path
     */
    protected $explicitPaths = [];

    /**
     * @var array An array of namespaceName => namespacePath
     */
    protected $namespacedPaths = [];

    /**
     * @var string Will contain the absolute phar:// path to the executable when packaged as phar file
     */
    protected $pharBasePath = "";

    /**
     * @var array An array of supported phar extensions (filled on constructor)
     */
    protected $pharExtensions = [];

    /**
     * @var array An array of module classes to their containing files
     */
    protected $moduleClassMap = [];

    /**
     * Constructor
     *
     * Allow configuration of the autoloader via the constructor.
     *
     * @param  null|array|Traversable $options
     */
    public function __construct($options = null)
    {
        if (extension_loaded('phar')) {
            $this->pharBasePath = Phar::running(true);
            $this->pharExtensions = [
                'phar',
                'phar.tar',
                'tar',
            ];

            // ext/zlib enabled -> phar can read gzip & zip compressed files
            if (extension_loaded('zlib')) {
                $this->pharExtensions[] = 'phar.gz';
                $this->pharExtensions[] = 'phar.tar.gz';
                $this->pharExtensions[] = 'tar.gz';

                $this->pharExtensions[] = 'phar.zip';
                $this->pharExtensions[] = 'zip';
            }

            // ext/bzip2 enabled -> phar can read bz2 compressed files
            if (extension_loaded('bzip2')) {
                $this->pharExtensions[] = 'phar.bz2';
                $this->pharExtensions[] = 'phar.tar.bz2';
                $this->pharExtensions[] = 'tar.bz2';
            }
        }

        if (null !== $options) {
            $this->setOptions($options);
        }
    }

    /**
     * Configure the autoloader
     *
     * In most cases, $options should be either an associative array or
     * Traversable object.
     *
     * @param  array|Traversable $options
     * @return ModuleAutoloader
     */
    public function setOptions($options)
    {
        $this->registerPaths($options);
        return $this;
    }

    /**
     * Retrieves the class map for all loaded modules.
     *
     * @return array
     */
    public function getModuleClassMap()
    {
        return $this->moduleClassMap;
    }

    /**
     * Sets the class map used to speed up the module autoloading.
     *
     * @param  array $classmap
     * @return ModuleAutoloader
     */
    public function setModuleClassMap(array $classmap)
    {
        $this->moduleClassMap = $classmap;

        return $this;
    }

    /**
     * Autoload a class
     *
     * @param   $class
     * @return  mixed
     *          False [if unable to load $class]
     *          get_class($class) [if $class is successfully loaded]
     */
    public function autoload($class)
    {
        // Limit scope of this autoloader
        if (substr($class, -7) !== '\Module') {
            return false;
        }

        if (isset($this->moduleClassMap[$class])) {
            require_once $this->moduleClassMap[$class];
            return $class;
        }

        $moduleName = substr($class, 0, -7);
        if (isset($this->explicitPaths[$moduleName])) {
            $classLoaded = $this->loadModuleFromDir($this->explicitPaths[$moduleName], $class);
            if ($classLoaded) {
                return $classLoaded;
            }

            $classLoaded = $this->loadModuleFromPhar($this->explicitPaths[$moduleName], $class);
            if ($classLoaded) {
                return $classLoaded;
            }
        }

        if (count($this->namespacedPaths) >= 1) {
            foreach ($this->namespacedPaths as $namespace => $path) {
                if (false === strpos($moduleName, $namespace)) {
                    continue;
                }

                $moduleNameBuffer = str_replace($namespace . "\\", "", $moduleName);
                $path .= DIRECTORY_SEPARATOR . $moduleNameBuffer . DIRECTORY_SEPARATOR;

                $classLoaded = $this->loadModuleFromDir($path, $class);
                if ($classLoaded) {
                    return $classLoaded;
                }

                $classLoaded = $this->loadModuleFromPhar($path, $class);
                if ($classLoaded) {
                    return $classLoaded;
                }
            }
        }

        $moduleClassPath   = str_replace('\\', DIRECTORY_SEPARATOR, $moduleName);

        $pharSuffixPattern = null;
        if ($this->pharExtensions) {
            $pharSuffixPattern = '(' . implode('|', array_map('preg_quote', $this->pharExtensions)) . ')';
        }

        foreach ($this->paths as $path) {
            $path = $path . $moduleClassPath;

            if ($path == '.' || substr($path, 0, 2) == './' || substr($path, 0, 2) == '.\\') {
                if (! $basePath = $this->pharBasePath) {
                    $basePath = realpath('.');
                }

                if (false === $basePath) {
                    $basePath = getcwd();
                }

                $path = rtrim($basePath, '\/\\') . substr($path, 1);
            }

            $classLoaded = $this->loadModuleFromDir($path, $class);
            if ($classLoaded) {
                return $classLoaded;
            }

            // No directory with Module.php, searching for phars
            if ($pharSuffixPattern) {
                foreach (new GlobIterator($path . '.*') as $entry) {
                    if ($entry->isDir()) {
                        continue;
                    }

                    if (! preg_match('#.+\.' . $pharSuffixPattern . '$#', $entry->getPathname())) {
                        continue;
                    }

                    $classLoaded = $this->loadModuleFromPhar($entry->getPathname(), $class);
                    if ($classLoaded) {
                        return $classLoaded;
                    }
                }
            }
        }

        return false;
    }

    /**
     * loadModuleFromDir
     *
     * @param  string $dirPath
     * @param  string $class
     * @return  mixed
     *          False [if unable to load $class]
     *          get_class($class) [if $class is successfully loaded]
     */
    protected function loadModuleFromDir($dirPath, $class)
    {
        $modulePath = $dirPath . '/Module.php';
        if (substr($modulePath, 0, 7) === 'phar://') {
            $file = new PharFileInfo($modulePath);
        } else {
            $file = new SplFileInfo($modulePath);
        }

        if (($file->isReadable() && $file->isFile())) {
            // Found directory with Module.php in it
            $absModulePath = $this->pharBasePath ? (string) $file : $file->getRealPath();
            require_once $absModulePath;
            if (class_exists($class)) {
                $this->moduleClassMap[$class] = $absModulePath;
                return $class;
            }
        }
        return false;
    }

    /**
     * loadModuleFromPhar
     *
     * @param  string $pharPath
     * @param  string $class
     * @return  mixed
     *          False [if unable to load $class]
     *          get_class($class) [if $class is successfully loaded]
     */
    protected function loadModuleFromPhar($pharPath, $class)
    {
        $pharPath = static::normalizePath($pharPath, false);
        $file = new SplFileInfo($pharPath);
        if (! $file->isReadable() || ! $file->isFile()) {
            return false;
        }

        $fileRealPath = $file->getRealPath();

        // Phase 0: Check for executable phar with Module class in stub
        if (strpos($fileRealPath, '.phar') !== false) {
            // First see if the stub makes the Module class available
            require_once $fileRealPath;
            if (class_exists($class)) {
                $this->moduleClassMap[$class] = $fileRealPath;
                return $class;
            }
        }

        // Phase 1: Not executable phar, no stub, or stub did not provide Module class; try Module.php directly
        $moduleClassFile = 'phar://' . $fileRealPath . '/Module.php';
        $moduleFile = new SplFileInfo($moduleClassFile);
        if ($moduleFile->isReadable() && $moduleFile->isFile()) {
            require_once $moduleClassFile;
            if (class_exists($class)) {
                $this->moduleClassMap[$class] = $moduleClassFile;
                return $class;
            }
        }

        // Phase 2: Check for nested module directory within archive
        // Checks for /path/to/MyModule.tar/MyModule/Module.php
        // (shell-integrated zip/tar utilities wrap directories like this)
        $pharBaseName = $this->pharFileToModuleName($fileRealPath);
        $moduleClassFile = 'phar://' . $fileRealPath . '/' . $pharBaseName  . '/Module.php';
        $moduleFile = new SplFileInfo($moduleClassFile);
        if ($moduleFile->isReadable() && $moduleFile->isFile()) {
            require_once $moduleClassFile;
            if (class_exists($class)) {
                $this->moduleClassMap[$class] = $moduleClassFile;
                return $class;
            }
        }

        return false;
    }

    /**
     * Register the autoloader with spl_autoload registry
     *
     * @return void
     */
    public function register()
    {
        spl_autoload_register([$this, 'autoload']);
    }

    /**
     * Unregister the autoloader with spl_autoload registry
     *
     * @return void
     */
    public function unregister()
    {
        spl_autoload_unregister([$this, 'autoload']);
    }

    /**
     * registerPaths
     *
     * @param  array|Traversable $paths
     * @throws \InvalidArgumentException
     * @return ModuleAutoloader
     */
    public function registerPaths($paths)
    {
        if (! is_array($paths) && ! $paths instanceof Traversable) {
            require_once __DIR__ . '/Exception/InvalidArgumentException.php';
            throw new Exception\InvalidArgumentException(
                'Parameter to \\Laminas\\Loader\\ModuleAutoloader\'s '
                . 'registerPaths method must be an array or '
                . 'implement the Traversable interface'
            );
        }

        foreach ($paths as $module => $path) {
            if (is_string($module)) {
                $this->registerPath($path, $module);
            } else {
                $this->registerPath($path);
            }
        }

        return $this;
    }

    /**
     * registerPath
     *
     * @param  string $path
     * @param  bool|string $moduleName
     * @throws \InvalidArgumentException
     * @return ModuleAutoloader
     */
    public function registerPath($path, $moduleName = false)
    {
        if (! is_string($path)) {
            require_once __DIR__ . '/Exception/InvalidArgumentException.php';
            throw new Exception\InvalidArgumentException(sprintf(
                'Invalid path provided; must be a string, received %s',
                gettype($path)
            ));
        }
        if ($moduleName) {
            if (in_array(substr($moduleName, -2), ['\\*', '\\%'])) {
                $this->namespacedPaths[substr($moduleName, 0, -2)] = static::normalizePath($path);
            } else {
                $this->explicitPaths[$moduleName] = static::normalizePath($path);
            }
        } else {
            $this->paths[] = static::normalizePath($path);
        }
        return $this;
    }

    /**
     * getPaths
     *
     * This is primarily for unit testing, but could have other uses.
     *
     * @return array
     */
    public function getPaths()
    {
        return $this->paths;
    }

    /**
     * Returns the base module name from the path to a phar
     *
     * @param  string $pharPath
     * @return string
     */
    protected function pharFileToModuleName($pharPath)
    {
        do {
            $pathinfo = pathinfo($pharPath);
            $pharPath = $pathinfo['filename'];
        } while (isset($pathinfo['extension']));
        return $pathinfo['filename'];
    }

    /**
     * Normalize a path for insertion in the stack
     *
     * @param  string $path
     * @param  bool   $trailingSlash Whether trailing slash should be included
     * @return string
     */
    public static function normalizePath($path, $trailingSlash = true)
    {
        $path = rtrim($path, '/');
        $path = rtrim($path, '\\');
        if ($trailingSlash) {
            $path .= DIRECTORY_SEPARATOR;
        }
        return $path;
    }
}
laminas-loader/src/SplAutoloader.php000064400000003001147361032560013513 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-loader for the canonical source repository
 * @copyright https://github.com/laminas/laminas-loader/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-loader/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Loader;

use Traversable;

if (interface_exists('Laminas\Loader\SplAutoloader')) {
    return;
}

/**
 * Defines an interface for classes that may register with the spl_autoload
 * registry
 */
interface SplAutoloader
{
    /**
     * Constructor
     *
     * Allow configuration of the autoloader via the constructor.
     *
     * @param  null|array|Traversable $options
     */
    public function __construct($options = null);

    /**
     * Configure the autoloader
     *
     * In most cases, $options should be either an associative array or
     * Traversable object.
     *
     * @param  array|Traversable $options
     * @return SplAutoloader
     */
    public function setOptions($options);

    /**
     * Autoload a class
     *
     * @param   $class
     * @return  mixed
     *          False [if unable to load $class]
     *          get_class($class) [if $class is successfully loaded]
     */
    public function autoload($class);

    /**
     * Register the autoloader with spl_autoload registry
     *
     * Typically, the body of this will simply be:
     * <code>
     * spl_autoload_register(array($this, 'autoload'));
     * </code>
     *
     * @return void
     */
    public function register();
}
laminas-loader/src/PluginClassLocator.php000064400000001761147361032560014520 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-loader for the canonical source repository
 * @copyright https://github.com/laminas/laminas-loader/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-loader/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Loader;

use IteratorAggregate;
use Traversable;

/**
 * Plugin class locator interface
 */
interface PluginClassLocator extends ShortNameLocator, IteratorAggregate
{
    /**
     * Register a class to a given short name
     *
     * @param  string $shortName
     * @param  string $className
     * @return PluginClassLocator
     */
    public function registerPlugin($shortName, $className);

    /**
     * Unregister a short name lookup
     *
     * @param  mixed $shortName
     * @return void
     */
    public function unregisterPlugin($shortName);

    /**
     * Get a list of all registered plugins
     *
     * @return array|Traversable
     */
    public function getRegisteredPlugins();
}
laminas-loader/src/ClassMapAutoloader.php000064400000013406147361032560014472 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-loader for the canonical source repository
 * @copyright https://github.com/laminas/laminas-loader/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-loader/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Loader;

use Traversable;

// Grab SplAutoloader interface
require_once __DIR__ . '/SplAutoloader.php';

/**
 * Class-map autoloader
 *
 * Utilizes class-map files to lookup classfile locations.
 */
class ClassMapAutoloader implements SplAutoloader
{
    /**
     * Registry of map files that have already been loaded
     * @var array
     */
    protected $mapsLoaded = [];

    /**
     * Class name/filename map
     * @var array
     */
    protected $map = [];

    /**
     * Constructor
     *
     * Create a new instance, and optionally configure the autoloader.
     *
     * @param  null|array|Traversable $options
     */
    public function __construct($options = null)
    {
        if (null !== $options) {
            $this->setOptions($options);
        }
    }

    /**
     * Configure the autoloader
     *
     * Proxies to {@link registerAutoloadMaps()}.
     *
     * @param  array|Traversable $options
     * @return ClassMapAutoloader
     */
    public function setOptions($options)
    {
        $this->registerAutoloadMaps($options);
        return $this;
    }

    /**
     * Register an autoload map
     *
     * An autoload map may be either an associative array, or a file returning
     * an associative array.
     *
     * An autoload map should be an associative array containing
     * classname/file pairs.
     *
     * @param  string|array $map
     * @throws Exception\InvalidArgumentException
     * @return ClassMapAutoloader
     */
    public function registerAutoloadMap($map)
    {
        if (is_string($map)) {
            $location = $map;
            if ($this === ($map = $this->loadMapFromFile($location))) {
                return $this;
            }
        }

        if (! is_array($map)) {
            require_once __DIR__ . '/Exception/InvalidArgumentException.php';
            throw new Exception\InvalidArgumentException(sprintf(
                'Map file provided does not return a map. Map file: "%s"',
                (isset($location) && is_string($location) ? $location : 'unexpected type: ' . gettype($map))
            ));
        }

        $this->map = $map + $this->map;

        if (isset($location)) {
            $this->mapsLoaded[] = $location;
        }

        return $this;
    }

    /**
     * Register many autoload maps at once
     *
     * @param  array $locations
     * @throws Exception\InvalidArgumentException
     * @return ClassMapAutoloader
     */
    public function registerAutoloadMaps($locations)
    {
        if (! is_array($locations) && ! ($locations instanceof Traversable)) {
            require_once __DIR__ . '/Exception/InvalidArgumentException.php';
            throw new Exception\InvalidArgumentException('Map list must be an array or implement Traversable');
        }
        foreach ($locations as $location) {
            $this->registerAutoloadMap($location);
        }
        return $this;
    }

    /**
     * Retrieve current autoload map
     *
     * @return array
     */
    public function getAutoloadMap()
    {
        return $this->map;
    }

    /**
     * {@inheritDoc}
     */
    public function autoload($class)
    {
        if (isset($this->map[$class])) {
            require_once $this->map[$class];

            return $class;
        }

        return false;
    }

    /**
     * Register the autoloader with spl_autoload registry
     *
     * @return void
     */
    public function register()
    {
        spl_autoload_register([$this, 'autoload'], true, true);
    }

    /**
     * Load a map from a file
     *
     * If the map has been previously loaded, returns the current instance;
     * otherwise, returns whatever was returned by calling include() on the
     * location.
     *
     * @param  string $location
     * @return ClassMapAutoloader|mixed
     * @throws Exception\InvalidArgumentException for nonexistent locations
     */
    protected function loadMapFromFile($location)
    {
        if (! file_exists($location)) {
            require_once __DIR__ . '/Exception/InvalidArgumentException.php';
            throw new Exception\InvalidArgumentException(sprintf(
                'Map file provided does not exist. Map file: "%s"',
                (is_string($location) ? $location : 'unexpected type: ' . gettype($location))
            ));
        }

        if (! $path = static::realPharPath($location)) {
            $path = realpath($location);
        }

        if (in_array($path, $this->mapsLoaded)) {
            // Already loaded this map
            return $this;
        }

        $map = include $path;

        return $map;
    }

    /**
     * Resolve the real_path() to a file within a phar.
     *
     * @see https://bugs.php.net/bug.php?id=52769
     * @param  string $path
     * @return string
     */
    public static function realPharPath($path)
    {
        if (! preg_match('|^phar:(/{2,3})|', $path, $match)) {
            return;
        }

        $prefixLength  = 5 + strlen($match[1]);
        $parts = explode('/', str_replace(['/', '\\'], '/', substr($path, $prefixLength)));
        $parts = array_values(array_filter($parts, function ($p) {
            return ($p !== '' && $p !== '.');
        }));

        array_walk($parts, function ($value, $key) use (&$parts) {
            if ($value === '..') {
                unset($parts[$key], $parts[$key - 1]);
                $parts = array_values($parts);
            }
        });

        if (file_exists($realPath = str_pad('phar:', $prefixLength, '/') . implode('/', $parts))) {
            return $realPath;
        }
    }
}
laminas-loader/src/ShortNameLocator.php000064400000001526147361032560014173 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-loader for the canonical source repository
 * @copyright https://github.com/laminas/laminas-loader/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-loader/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Loader;

/**
 * Short name locator interface
 */
interface ShortNameLocator
{
    /**
     * Whether or not a Helper by a specific name
     *
     * @param  string $name
     * @return bool
     */
    public function isLoaded($name);

    /**
     * Return full class name for a named helper
     *
     * @param  string $name
     * @return string
     */
    public function getClassName($name);

    /**
     * Load a helper via the name provided
     *
     * @param  string $name
     * @return string
     */
    public function load($name);
}
laminas-loader/src/Exception/MissingResourceNamespaceException.php000064400000000721147361032560021516 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-loader for the canonical source repository
 * @copyright https://github.com/laminas/laminas-loader/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-loader/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Loader\Exception;

require_once __DIR__ . '/ExceptionInterface.php';

class MissingResourceNamespaceException extends \Exception implements ExceptionInterface
{
}
laminas-loader/src/Exception/SecurityException.php000064400000000645147361032560016374 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-loader for the canonical source repository
 * @copyright https://github.com/laminas/laminas-loader/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-loader/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Loader\Exception;

require_once __DIR__ . '/DomainException.php';

class SecurityException extends DomainException
{
}
laminas-loader/src/Exception/ExceptionInterface.php000064400000000542147361032560016461 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-loader for the canonical source repository
 * @copyright https://github.com/laminas/laminas-loader/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-loader/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Loader\Exception;

interface ExceptionInterface
{
}
laminas-loader/src/Exception/PluginLoaderException.php000064400000000723147361032560017147 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-loader for the canonical source repository
 * @copyright https://github.com/laminas/laminas-loader/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-loader/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Loader\Exception;

require_once __DIR__ . '/DomainException.php';

/**
 * Plugin class loader exceptions
 */
class PluginLoaderException extends DomainException
{
}
laminas-loader/src/Exception/DomainException.php000064400000000705147361032560015771 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-loader for the canonical source repository
 * @copyright https://github.com/laminas/laminas-loader/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-loader/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Loader\Exception;

require_once __DIR__ . '/ExceptionInterface.php';

class DomainException extends \DomainException implements ExceptionInterface
{
}
laminas-loader/src/Exception/InvalidPathException.php000064400000000704147361032560016764 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-loader for the canonical source repository
 * @copyright https://github.com/laminas/laminas-loader/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-loader/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Loader\Exception;

require_once __DIR__ . '/ExceptionInterface.php';

class InvalidPathException extends \Exception implements ExceptionInterface
{
}
laminas-loader/src/Exception/InvalidArgumentException.php000064400000000727147361032560017657 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-loader for the canonical source repository
 * @copyright https://github.com/laminas/laminas-loader/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-loader/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Loader\Exception;

require_once __DIR__ . '/ExceptionInterface.php';

class InvalidArgumentException extends \InvalidArgumentException implements ExceptionInterface
{
}
laminas-loader/src/Exception/BadMethodCallException.php000064400000000727147361032560017211 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-loader for the canonical source repository
 * @copyright https://github.com/laminas/laminas-loader/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-loader/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Loader\Exception;

require_once __DIR__ . '/ExceptionInterface.php';

class BadMethodCallException extends \BadMethodCallException implements
    ExceptionInterface
{
}
laminas-loader/src/Exception/RuntimeException.php000064400000000707147361032560016207 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-loader for the canonical source repository
 * @copyright https://github.com/laminas/laminas-loader/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-loader/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Loader\Exception;

require_once __DIR__ . '/ExceptionInterface.php';

class RuntimeException extends \RuntimeException implements ExceptionInterface
{
}
laminas-loader/src/StandardAutoloader.php000064400000024027147361032560014530 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-loader for the canonical source repository
 * @copyright https://github.com/laminas/laminas-loader/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-loader/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Loader;

// Grab SplAutoloader interface
require_once __DIR__ . '/SplAutoloader.php';

/**
 * PSR-0 compliant autoloader
 *
 * Allows autoloading both namespaced and vendor-prefixed classes. Class
 * lookups are performed on the filesystem. If a class file for the referenced
 * class is not found, a PHP warning will be raised by include().
 */
class StandardAutoloader implements SplAutoloader
{
    const NS_SEPARATOR     = '\\';
    const PREFIX_SEPARATOR = '_';
    const LOAD_NS          = 'namespaces';
    const LOAD_PREFIX      = 'prefixes';
    const ACT_AS_FALLBACK  = 'fallback_autoloader';
    /** @deprecated Use AUTOREGISTER_LAMINAS instead */
    const AUTOREGISTER_ZF  = 'autoregister_laminas';
    const AUTOREGISTER_LAMINAS  = 'autoregister_laminas';

    /**
     * @var array Namespace/directory pairs to search; Laminas library added by default
     */
    protected $namespaces = [];

    /**
     * @var array Prefix/directory pairs to search
     */
    protected $prefixes = [];

    /**
     * @var bool Whether or not the autoloader should also act as a fallback autoloader
     */
    protected $fallbackAutoloaderFlag = false;

    /**
     * Constructor
     *
     * @param  null|array|\Traversable $options
     */
    public function __construct($options = null)
    {
        if (null !== $options) {
            $this->setOptions($options);
        }
    }

    /**
     * Configure autoloader
     *
     * Allows specifying both "namespace" and "prefix" pairs, using the
     * following structure:
     * <code>
     * array(
     *     'namespaces' => array(
     *         'Laminas'     => '/path/to/Laminas/library',
     *         'Doctrine' => '/path/to/Doctrine/library',
     *     ),
     *     'prefixes' => array(
     *         'Phly_'     => '/path/to/Phly/library',
     *     ),
     *     'fallback_autoloader' => true,
     * )
     * </code>
     *
     * @param  array|\Traversable $options
     * @throws Exception\InvalidArgumentException
     * @return StandardAutoloader
     */
    public function setOptions($options)
    {
        if (! is_array($options) && ! ($options instanceof \Traversable)) {
            require_once __DIR__ . '/Exception/InvalidArgumentException.php';
            throw new Exception\InvalidArgumentException('Options must be either an array or Traversable');
        }

        foreach ($options as $type => $pairs) {
            switch ($type) {
                case self::AUTOREGISTER_LAMINAS:
                    if ($pairs) {
                        $this->registerNamespace('Laminas', dirname(__DIR__));
                    }
                    break;
                case self::LOAD_NS:
                    if (is_array($pairs) || $pairs instanceof \Traversable) {
                        $this->registerNamespaces($pairs);
                    }
                    break;
                case self::LOAD_PREFIX:
                    if (is_array($pairs) || $pairs instanceof \Traversable) {
                        $this->registerPrefixes($pairs);
                    }
                    break;
                case self::ACT_AS_FALLBACK:
                    $this->setFallbackAutoloader($pairs);
                    break;
                default:
                    // ignore
            }
        }
        return $this;
    }

    /**
     * Set flag indicating fallback autoloader status
     *
     * @param  bool $flag
     * @return StandardAutoloader
     */
    public function setFallbackAutoloader($flag)
    {
        $this->fallbackAutoloaderFlag = (bool) $flag;
        return $this;
    }

    /**
     * Is this autoloader acting as a fallback autoloader?
     *
     * @return bool
     */
    public function isFallbackAutoloader()
    {
        return $this->fallbackAutoloaderFlag;
    }

    /**
     * Register a namespace/directory pair
     *
     * @param  string $namespace
     * @param  string $directory
     * @return StandardAutoloader
     */
    public function registerNamespace($namespace, $directory)
    {
        $namespace = rtrim($namespace, self::NS_SEPARATOR) . self::NS_SEPARATOR;
        $this->namespaces[$namespace] = $this->normalizeDirectory($directory);
        return $this;
    }

    /**
     * Register many namespace/directory pairs at once
     *
     * @param  array $namespaces
     * @throws Exception\InvalidArgumentException
     * @return StandardAutoloader
     */
    public function registerNamespaces($namespaces)
    {
        if (! is_array($namespaces) && ! $namespaces instanceof \Traversable) {
            require_once __DIR__ . '/Exception/InvalidArgumentException.php';
            throw new Exception\InvalidArgumentException('Namespace pairs must be either an array or Traversable');
        }

        foreach ($namespaces as $namespace => $directory) {
            $this->registerNamespace($namespace, $directory);
        }
        return $this;
    }

    /**
     * Register a prefix/directory pair
     *
     * @param  string $prefix
     * @param  string $directory
     * @return StandardAutoloader
     */
    public function registerPrefix($prefix, $directory)
    {
        $prefix = rtrim($prefix, self::PREFIX_SEPARATOR). self::PREFIX_SEPARATOR;
        $this->prefixes[$prefix] = $this->normalizeDirectory($directory);
        return $this;
    }

    /**
     * Register many namespace/directory pairs at once
     *
     * @param  array $prefixes
     * @throws Exception\InvalidArgumentException
     * @return StandardAutoloader
     */
    public function registerPrefixes($prefixes)
    {
        if (! is_array($prefixes) && ! $prefixes instanceof \Traversable) {
            require_once __DIR__ . '/Exception/InvalidArgumentException.php';
            throw new Exception\InvalidArgumentException('Prefix pairs must be either an array or Traversable');
        }

        foreach ($prefixes as $prefix => $directory) {
            $this->registerPrefix($prefix, $directory);
        }
        return $this;
    }

    /**
     * Defined by Autoloadable; autoload a class
     *
     * @param  string $class
     * @return false|string
     */
    public function autoload($class)
    {
        $isFallback = $this->isFallbackAutoloader();
        if (false !== strpos($class, self::NS_SEPARATOR)) {
            if ($this->loadClass($class, self::LOAD_NS)) {
                return $class;
            } elseif ($isFallback) {
                return $this->loadClass($class, self::ACT_AS_FALLBACK);
            }
            return false;
        }
        if (false !== strpos($class, self::PREFIX_SEPARATOR)) {
            if ($this->loadClass($class, self::LOAD_PREFIX)) {
                return $class;
            } elseif ($isFallback) {
                return $this->loadClass($class, self::ACT_AS_FALLBACK);
            }
            return false;
        }
        if ($isFallback) {
            return $this->loadClass($class, self::ACT_AS_FALLBACK);
        }
        return false;
    }

    /**
     * Register the autoloader with spl_autoload
     *
     * @return void
     */
    public function register()
    {
        spl_autoload_register([$this, 'autoload']);
    }

    /**
     * Transform the class name to a filename
     *
     * @param  string $class
     * @param  string $directory
     * @return string
     */
    protected function transformClassNameToFilename($class, $directory)
    {
        // $class may contain a namespace portion, in  which case we need
        // to preserve any underscores in that portion.
        $matches = [];
        preg_match('/(?P<namespace>.+\\\)?(?P<class>[^\\\]+$)/', $class, $matches);

        $class     = (isset($matches['class'])) ? $matches['class'] : '';
        $namespace = (isset($matches['namespace'])) ? $matches['namespace'] : '';

        return $directory
             . str_replace(self::NS_SEPARATOR, '/', $namespace)
             . str_replace(self::PREFIX_SEPARATOR, '/', $class)
             . '.php';
    }

    /**
     * Load a class, based on its type (namespaced or prefixed)
     *
     * @param  string $class
     * @param  string $type
     * @return bool|string
     * @throws Exception\InvalidArgumentException
     */
    protected function loadClass($class, $type)
    {
        if (! in_array($type, [self::LOAD_NS, self::LOAD_PREFIX, self::ACT_AS_FALLBACK])) {
            require_once __DIR__ . '/Exception/InvalidArgumentException.php';
            throw new Exception\InvalidArgumentException();
        }

        // Fallback autoloading
        if ($type === self::ACT_AS_FALLBACK) {
            // create filename
            $filename     = $this->transformClassNameToFilename($class, '');
            $resolvedName = stream_resolve_include_path($filename);
            if ($resolvedName !== false) {
                return include $resolvedName;
            }
            return false;
        }

        // Namespace and/or prefix autoloading
        foreach ($this->$type as $leader => $path) {
            if (0 === strpos($class, $leader)) {
                // Trim off leader (namespace or prefix)
                $trimmedClass = substr($class, strlen($leader));

                // create filename
                $filename = $this->transformClassNameToFilename($trimmedClass, $path);
                if (file_exists($filename)) {
                    return include $filename;
                }
            }
        }
        return false;
    }

    /**
     * Normalize the directory to include a trailing directory separator
     *
     * @param  string $directory
     * @return string
     */
    protected function normalizeDirectory($directory)
    {
        $last = $directory[strlen($directory) - 1];
        if (in_array($last, ['/', '\\'])) {
            $directory[strlen($directory) - 1] = DIRECTORY_SEPARATOR;
            return $directory;
        }
        $directory .= DIRECTORY_SEPARATOR;
        return $directory;
    }
}
laminas-loader/src/PluginClassLoader.php000064400000012712147361032560014321 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-loader for the canonical source repository
 * @copyright https://github.com/laminas/laminas-loader/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-loader/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Loader;

use ArrayIterator;
use IteratorAggregate;
use Traversable;

/**
 * Plugin class locator interface
 */
class PluginClassLoader implements PluginClassLocator
{
    /**
     * List of plugin name => class name pairs
     * @var array
     */
    protected $plugins = [];

    /**
     * Static map allow global seeding of plugin loader
     * @var array
     */
    protected static $staticMap = [];

    /**
     * Constructor
     *
     * @param  null|array|Traversable $map If provided, seeds the loader with a map
     */
    public function __construct($map = null)
    {
        // Merge in static overrides
        if (! empty(static::$staticMap)) {
            $this->registerPlugins(static::$staticMap);
        }

        // Merge in constructor arguments
        if ($map !== null) {
            $this->registerPlugins($map);
        }
    }

    /**
     * Add a static map of plugins
     *
     * A null value will clear the static map.
     *
     * @param  null|array|Traversable $map
     * @throws Exception\InvalidArgumentException
     * @return void
     */
    public static function addStaticMap($map)
    {
        if (null === $map) {
            static::$staticMap = [];
            return;
        }

        if (! is_array($map) && ! $map instanceof Traversable) {
            throw new Exception\InvalidArgumentException('Expects an array or Traversable object');
        }
        foreach ($map as $key => $value) {
            static::$staticMap[$key] = $value;
        }
    }

    /**
     * Register a class to a given short name
     *
     * @param  string $shortName
     * @param  string $className
     * @return PluginClassLoader
     */
    public function registerPlugin($shortName, $className)
    {
        $this->plugins[strtolower($shortName)] = $className;
        return $this;
    }

    /**
     * Register many plugins at once
     *
     * If $map is a string, assumes that the map is the class name of a
     * Traversable object (likely a ShortNameLocator); it will then instantiate
     * this class and use it to register plugins.
     *
     * If $map is an array or Traversable object, it will iterate it to
     * register plugin names/classes.
     *
     * For all other arguments, or if the string $map is not a class or not a
     * Traversable class, an exception will be raised.
     *
     * @param  string|array|Traversable $map
     * @return PluginClassLoader
     * @throws Exception\InvalidArgumentException
     */
    public function registerPlugins($map)
    {
        if (is_string($map)) {
            if (! class_exists($map)) {
                throw new Exception\InvalidArgumentException('Map class provided is invalid');
            }
            $map = new $map;
        }
        if (is_array($map)) {
            $map = new ArrayIterator($map);
        }
        if (! $map instanceof Traversable) {
            throw new Exception\InvalidArgumentException('Map provided is invalid; must be traversable');
        }

        // iterator_apply doesn't work as expected with IteratorAggregate
        if ($map instanceof IteratorAggregate) {
            $map = $map->getIterator();
        }

        foreach ($map as $name => $class) {
            if (is_int($name) || is_numeric($name)) {
                if (! is_object($class) && class_exists($class)) {
                    $class = new $class();
                }

                if ($class instanceof Traversable) {
                    $this->registerPlugins($class);
                    continue;
                }
            }

            $this->registerPlugin($name, $class);
        }

        return $this;
    }

    /**
     * Unregister a short name lookup
     *
     * @param  mixed $shortName
     * @return PluginClassLoader
     */
    public function unregisterPlugin($shortName)
    {
        $lookup = strtolower($shortName);
        if (array_key_exists($lookup, $this->plugins)) {
            unset($this->plugins[$lookup]);
        }
        return $this;
    }

    /**
     * Get a list of all registered plugins
     *
     * @return array|Traversable
     */
    public function getRegisteredPlugins()
    {
        return $this->plugins;
    }

    /**
     * Whether or not a plugin by a specific name has been registered
     *
     * @param  string $name
     * @return bool
     */
    public function isLoaded($name)
    {
        $lookup = strtolower($name);
        return isset($this->plugins[$lookup]);
    }

    /**
     * Return full class name for a named helper
     *
     * @param  string $name
     * @return string|false
     */
    public function getClassName($name)
    {
        return $this->load($name);
    }

    /**
     * Load a helper via the name provided
     *
     * @param  string $name
     * @return string|false
     */
    public function load($name)
    {
        if (! $this->isLoaded($name)) {
            return false;
        }
        return $this->plugins[strtolower($name)];
    }

    /**
     * Defined by IteratorAggregate
     *
     * Returns an instance of ArrayIterator, containing a map of
     * all plugins
     *
     * @return ArrayIterator
     */
    public function getIterator()
    {
        return new ArrayIterator($this->plugins);
    }
}
laminas-loader/src/AutoloaderFactory.php000064400000016032147361032560014374 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-loader for the canonical source repository
 * @copyright https://github.com/laminas/laminas-loader/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-loader/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Loader;

use Traversable;

if (class_exists('Laminas\Loader\AutoloaderFactory')) {
    return;
}

abstract class AutoloaderFactory
{
    const STANDARD_AUTOLOADER = 'Laminas\Loader\StandardAutoloader';

    /**
     * @var array All autoloaders registered using the factory
     */
    protected static $loaders = [];

    /**
     * @var StandardAutoloader StandardAutoloader instance for resolving
     * autoloader classes via the include_path
     */
    protected static $standardAutoloader;

    /**
     * Factory for autoloaders
     *
     * Options should be an array or Traversable object of the following structure:
     * <code>
     * array(
     *     '<autoloader class name>' => $autoloaderOptions,
     * )
     * </code>
     *
     * The factory will then loop through and instantiate each autoloader with
     * the specified options, and register each with the spl_autoloader.
     *
     * You may retrieve the concrete autoloader instances later using
     * {@link getRegisteredAutoloaders()}.
     *
     * Note that the class names must be resolvable on the include_path or via
     * the Laminas library, using PSR-0 rules (unless the class has already been
     * loaded).
     *
     * @param  array|Traversable $options (optional) options to use. Defaults to Laminas\Loader\StandardAutoloader
     * @return void
     * @throws Exception\InvalidArgumentException for invalid options
     * @throws Exception\InvalidArgumentException for unloadable autoloader classes
     * @throws Exception\DomainException for autoloader classes not implementing SplAutoloader
     */
    public static function factory($options = null)
    {
        if (null === $options) {
            if (! isset(static::$loaders[static::STANDARD_AUTOLOADER])) {
                $autoloader = static::getStandardAutoloader();
                $autoloader->register();
                static::$loaders[static::STANDARD_AUTOLOADER] = $autoloader;
            }

            // Return so we don't hit the next check's exception (we're done here anyway)
            return;
        }

        if (! is_array($options) && ! ($options instanceof Traversable)) {
            require_once __DIR__ . '/Exception/InvalidArgumentException.php';
            throw new Exception\InvalidArgumentException(
                'Options provided must be an array or Traversable'
            );
        }

        foreach ($options as $class => $autoloaderOptions) {
            if (! isset(static::$loaders[$class])) {
                $autoloader = static::getStandardAutoloader();
                if (! class_exists($class) && ! $autoloader->autoload($class)) {
                    require_once 'Exception/InvalidArgumentException.php';
                    throw new Exception\InvalidArgumentException(
                        sprintf('Autoloader class "%s" not loaded', $class)
                    );
                }

                if (! is_subclass_of($class, 'Laminas\Loader\SplAutoloader')) {
                    require_once 'Exception/InvalidArgumentException.php';
                    throw new Exception\InvalidArgumentException(
                        sprintf('Autoloader class %s must implement Laminas\\Loader\\SplAutoloader', $class)
                    );
                }

                if ($class === static::STANDARD_AUTOLOADER) {
                    $autoloader->setOptions($autoloaderOptions);
                } else {
                    $autoloader = new $class($autoloaderOptions);
                }
                $autoloader->register();
                static::$loaders[$class] = $autoloader;
            } else {
                static::$loaders[$class]->setOptions($autoloaderOptions);
            }
        }
    }

    /**
     * Get a list of all autoloaders registered with the factory
     *
     * Returns an array of autoloader instances.
     *
     * @return array
     */
    public static function getRegisteredAutoloaders()
    {
        return static::$loaders;
    }

    /**
     * Retrieves an autoloader by class name
     *
     * @param  string $class
     * @return SplAutoloader
     * @throws Exception\InvalidArgumentException for non-registered class
     */
    public static function getRegisteredAutoloader($class)
    {
        if (! isset(static::$loaders[$class])) {
            require_once 'Exception/InvalidArgumentException.php';
            throw new Exception\InvalidArgumentException(sprintf('Autoloader class "%s" not loaded', $class));
        }
        return static::$loaders[$class];
    }

    /**
     * Unregisters all autoloaders that have been registered via the factory.
     * This will NOT unregister autoloaders registered outside of the fctory.
     *
     * @return void
     */
    public static function unregisterAutoloaders()
    {
        foreach (static::getRegisteredAutoloaders() as $class => $autoloader) {
            spl_autoload_unregister([$autoloader, 'autoload']);
            unset(static::$loaders[$class]);
        }
    }

    /**
     * Unregister a single autoloader by class name
     *
     * @param  string $autoloaderClass
     * @return bool
     */
    public static function unregisterAutoloader($autoloaderClass)
    {
        if (! isset(static::$loaders[$autoloaderClass])) {
            return false;
        }

        $autoloader = static::$loaders[$autoloaderClass];
        spl_autoload_unregister([$autoloader, 'autoload']);
        unset(static::$loaders[$autoloaderClass]);
        return true;
    }

    /**
     * Get an instance of the standard autoloader
     *
     * Used to attempt to resolve autoloader classes, using the
     * StandardAutoloader. The instance is marked as a fallback autoloader, to
     * allow resolving autoloaders not under the "Laminas" namespace.
     *
     * @return SplAutoloader
     */
    protected static function getStandardAutoloader()
    {
        if (null !== static::$standardAutoloader) {
            return static::$standardAutoloader;
        }


        if (! class_exists(static::STANDARD_AUTOLOADER)) {
            // Extract the filename from the classname
            $stdAutoloader = substr(strrchr(static::STANDARD_AUTOLOADER, '\\'), 1);
            require_once __DIR__ . "/$stdAutoloader.php";
        }
        $loader = new StandardAutoloader();
        static::$standardAutoloader = $loader;
        return static::$standardAutoloader;
    }

    /**
     * Checks if the object has this class as one of its parents
     *
     * @see https://bugs.php.net/bug.php?id=53727
     * @see https://github.com/zendframework/zf2/pull/1807
     *
     * @deprecated since laminas 2.3 requires PHP >= 5.3.23
     *
     * @param  string $className
     * @param  string $type
     * @return bool
     */
    protected static function isSubclassOf($className, $type)
    {
        return is_subclass_of($className, $type);
    }
}
laminas-loader/README.md000064400000001010147361032560010712 0ustar00# laminas-loader

[![Build Status](https://travis-ci.org/laminas/laminas-loader.svg?branch=master)](https://travis-ci.org/laminas/laminas-loader)
[![Coverage Status](https://coveralls.io/repos/github/laminas/laminas-loader/badge.svg?branch=master)](https://coveralls.io/github/laminas/laminas-loader?branch=master)

laminas-loader provides different strategies for autoloading PHP classes.

- File issues at https://github.com/laminas/laminas-loader/issues
- Documentation is at https://docs.laminas.dev/laminas-loader/
laminas-loader/CHANGELOG.md000064400000001747147361032560011265 0ustar00# Changelog

All notable changes to this project will be documented in this file, in reverse chronological order by release.

## 2.6.1 - 2019-09-04

### Added

- [zendframework/zend-loader#18](https://github.com/zendframework/zend-loader/pull/18) adds support for PHP 7.3.

### Changed

- Nothing.

### Deprecated

- Nothing.

### Removed

- Nothing.

### Fixed

- Nothing.

## 2.6.0 - 2018-04-30

### Added

- [zendframework/zend-loader#16](https://github.com/zendframework/zend-loader/pull/16) adds support for PHP 7.1 and 7.2.

- [zendframework/zend-loader#8](https://github.com/zendframework/zend-loader/pull/8) adds documentation at https://docs.laminas.dev/laminas-loader/

### Changed

- Nothing.

### Deprecated

- Nothing.

### Removed

- [zendframework/zend-loader#16](https://github.com/zendframework/zend-loader/pull/16) removes support for PHP 5.5.

- [zendframework/zend-loader#16](https://github.com/zendframework/zend-loader/pull/16) removes support for HHVM.

### Fixed

- Nothing.
laminas-loader/LICENSE.md000064400000002725147361032560011055 0ustar00Copyright (c) 2019, Laminas Foundation
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

- Redistributions of source code must retain the above copyright notice, this
  list of conditions and the following disclaimer.

- Redistributions in binary form must reproduce the above copyright notice,
  this list of conditions and the following disclaimer in the documentation
  and/or other materials provided with the distribution.

- Neither the name of Laminas Foundation nor the names of its contributors may
  be used to endorse or promote products derived from this software without
  specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
laminas-validator/COPYRIGHT.md000064400000000134147361032560012052 0ustar00Copyright (c) 2019-2020, Laminas Foundation.
All rights reserved. (https://getlaminas.org/)
laminas-validator/bin/update_hostname_validator.php000064400000012744147361032560016700 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-validator for the canonical source repository
 * @copyright https://github.com/laminas/laminas-validator/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-validator/blob/master/LICENSE.md New BSD License
 */

use Laminas\Http\Client;
use Laminas\Validator\Hostname;

require __DIR__ . '/../vendor/autoload.php';

define('IANA_URL', 'https://data.iana.org/TLD/tlds-alpha-by-domain.txt');
define('LAMINAS_HOSTNAME_VALIDATOR_FILE', __DIR__.'/../src/Hostname.php');


if (! file_exists(LAMINAS_HOSTNAME_VALIDATOR_FILE) || ! is_readable(LAMINAS_HOSTNAME_VALIDATOR_FILE)) {
    printf("Error: cannot read file '%s'%s", LAMINAS_HOSTNAME_VALIDATOR_FILE, PHP_EOL);
    exit(1);
}

if (! is_writable(LAMINAS_HOSTNAME_VALIDATOR_FILE)) {
    printf("Error: cannot update file '%s'%s", LAMINAS_HOSTNAME_VALIDATOR_FILE, PHP_EOL);
    exit(1);
}

$newFileContent   = [];    // new file content
$insertDone       = false; // becomes 'true' when we find start of $validTlds declaration
$insertFinish     = false; // becomes 'true' when we find end of $validTlds declaration
$checkOnly        = isset($argv[1]) ? $argv[1] === '--check-only' : false;
$response         = getOfficialTLDs();
$ianaVersion      = getVersionFromString('Version', strtok($response->getBody(), "\n"));
$validatorVersion = getVersionFromString('IanaVersion', file_get_contents(LAMINAS_HOSTNAME_VALIDATOR_FILE));

if ($checkOnly && $ianaVersion > $validatorVersion) {
    printf(
        'TLDs must be updated, please run `php bin/update_hostname_validator.php` and push your changes%s',
        PHP_EOL
    );
    exit(1);
}

if ($checkOnly) {
    printf('TLDs are up-to-date%s', PHP_EOL);
    exit(0);
}

foreach (file(LAMINAS_HOSTNAME_VALIDATOR_FILE) as $line) {
    // Replace old version number with new one
    if (preg_match('/\*\s+IanaVersion\s+\d+/', $line, $matches)) {
        $newFileContent[] = sprintf("     * IanaVersion %s\n", $ianaVersion);
        continue;
    }

    if ($insertDone === $insertFinish) {
        // Outside of $validTlds definition; keep line as-is
        $newFileContent[] = $line;
    }

    if ($insertFinish) {
        continue;
    }

    if ($insertDone) {
        // Detect where the $validTlds declaration ends
        if (preg_match('/^\s+\];\s*$/', $line)) {
            $newFileContent[] = $line;
            $insertFinish     = true;
        }

        continue;
    }

    // Detect where the $validTlds declaration begins
    if (preg_match('/^\s+protected\s+\$validTlds\s+=\s+\[\s*$/', $line)) {
        $newFileContent = array_merge($newFileContent, getNewValidTlds($response->getBody()));
        $insertDone     = true;
    }
}

if (! $insertDone) {
    printf('Error: cannot find line with "protected $validTlds"%s', PHP_EOL);
    exit(1);
}

if (!$insertFinish) {
    printf('Error: cannot find end of $validTlds declaration%s', PHP_EOL);
    exit(1);
}

if (false === @file_put_contents(LAMINAS_HOSTNAME_VALIDATOR_FILE, $newFileContent)) {
    printf('Error: cannot write info file "%s"%s', LAMINAS_HOSTNAME_VALIDATOR_FILE, PHP_EOL);
    exit(1);
}

printf('Validator TLD file updated.%s', PHP_EOL);
exit(0);

/**
 * Get Official TLDs
 *
 * @return \Laminas\Http\Response
 * @throws Exception
 */
function getOfficialTLDs()
{
    $client = new Client();
    $client->setOptions([
        'adapter' => 'Laminas\Http\Client\Adapter\Curl',
    ]);
    $client->setUri(IANA_URL);
    $client->setMethod('GET');

    $response = $client->send();
    if (! $response->isSuccess()) {
        throw new \Exception(sprintf("Error: cannot get '%s'%s", IANA_URL, PHP_EOL));
    }
    return $response;
}

/**
 * Extract the first match of a string like
 * "Version 2015072300" from the given string
 *
 * @param string $prefix
 * @param string $string
 * @return string
 * @throws Exception
 */
function getVersionFromString($prefix, $string)
{
    $matches = [];
    if (! preg_match(sprintf('/%s\s+((\d+)?)/', $prefix), $string, $matches)) {
        throw new Exception('Error: cannot get last update date');
    }

    return $matches[1];
}

/**
 * Extract new Valid TLDs from a string containing one per line.
 *
 * @param string $string
 * @return array
 */
function getNewValidTlds($string)
{
    $decodePunycode = getPunycodeDecoder();

    // Get new TLDs from the list previously fetched
    $newValidTlds = [];
    foreach (preg_grep('/^[^#]/', preg_split("#\r?\n#", $string)) as $line) {
        $newValidTlds []= sprintf(
            "%s'%s',\n",
            str_repeat(' ', 8),
            $decodePunycode(strtolower($line))
        );
    }

    return $newValidTlds;
}

/**
 * Retrieve and return a punycode decoder.
 *
 * TLDs are puny encoded.
 *
 * We need a decodePunycode function to translate TLDs to UTF-8:
 *
 * - use idn_to_utf8 if available
 * - otherwise, use Hostname::decodePunycode()
 *
 * @return callable
 */
function getPunycodeDecoder()
{
    if (function_exists('idn_to_utf8')) {
        return function ($domain) {
            return idn_to_utf8($domain, 0, INTL_IDNA_VARIANT_UTS46);
        };
    }

    $hostnameValidator = new Hostname();
    $reflection        = new ReflectionClass(get_class($hostnameValidator));
    $decodePunyCode    = $reflection->getMethod('decodePunycode');
    $decodePunyCode->setAccessible(true);

    return function ($encode) use ($hostnameValidator, $decodePunyCode) {
        if (strpos($encode, 'xn--') === 0) {
            return $decodePunyCode->invokeArgs($hostnameValidator, [substr($encode, 4)]);
        }
        return $encode;
    };
}
laminas-validator/src/StringLength.php000064400000013455147361032560014102 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-validator for the canonical source repository
 * @copyright https://github.com/laminas/laminas-validator/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-validator/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Validator;

use Laminas\Stdlib\StringUtils;
use Laminas\Stdlib\StringWrapper\StringWrapperInterface as StringWrapper;

class StringLength extends AbstractValidator
{
    const INVALID   = 'stringLengthInvalid';
    const TOO_SHORT = 'stringLengthTooShort';
    const TOO_LONG  = 'stringLengthTooLong';

    /**
     * @var array
     */
    protected $messageTemplates = [
        self::INVALID   => 'Invalid type given. String expected',
        self::TOO_SHORT => 'The input is less than %min% characters long',
        self::TOO_LONG  => 'The input is more than %max% characters long',
    ];

    /**
     * @var array
     */
    protected $messageVariables = [
        'min'    => ['options' => 'min'],
        'max'    => ['options' => 'max'],
        'length' => ['options' => 'length'],
    ];

    protected $options = [
        'min'      => 0,       // Minimum length
        'max'      => null,    // Maximum length, null if there is no length limitation
        'encoding' => 'UTF-8', // Encoding to use
        'length'   => 0,       // Actual length
    ];

    protected $stringWrapper;

    /**
     * Sets validator options
     *
     * @param  int|array|\Traversable $options
     */
    public function __construct($options = [])
    {
        if (! is_array($options)) {
            $options     = func_get_args();
            $temp['min'] = array_shift($options);
            if (! empty($options)) {
                $temp['max'] = array_shift($options);
            }

            if (! empty($options)) {
                $temp['encoding'] = array_shift($options);
            }

            $options = $temp;
        }

        parent::__construct($options);
    }

    /**
     * Returns the min option
     *
     * @return int
     */
    public function getMin()
    {
        return $this->options['min'];
    }

    /**
     * Sets the min option
     *
     * @param  int $min
     * @throws Exception\InvalidArgumentException
     * @return $this Provides a fluent interface
     */
    public function setMin($min)
    {
        if (null !== $this->getMax() && $min > $this->getMax()) {
            throw new Exception\InvalidArgumentException(
                "The minimum must be less than or equal to the maximum length, but {$min} > {$this->getMax()}"
            );
        }

        $this->options['min'] = max(0, (int) $min);
        return $this;
    }

    /**
     * Returns the max option
     *
     * @return int|null
     */
    public function getMax()
    {
        return $this->options['max'];
    }

    /**
     * Sets the max option
     *
     * @param  int|null $max
     * @throws Exception\InvalidArgumentException
     * @return $this Provides a fluent interface
     */
    public function setMax($max)
    {
        if (null === $max) {
            $this->options['max'] = null;
        } elseif ($max < $this->getMin()) {
            throw new Exception\InvalidArgumentException(
                "The maximum must be greater than or equal to the minimum length, but {$max} < {$this->getMin()}"
            );
        } else {
            $this->options['max'] = (int) $max;
        }

        return $this;
    }

    /**
     * Get the string wrapper to detect the string length
     *
     * @return StringWrapper
     */
    public function getStringWrapper()
    {
        if (! $this->stringWrapper) {
            $this->stringWrapper = StringUtils::getWrapper($this->getEncoding());
        }
        return $this->stringWrapper;
    }

    /**
     * Set the string wrapper to detect the string length
     *
     * @param StringWrapper $stringWrapper
     * @return StringLength
     */
    public function setStringWrapper(StringWrapper $stringWrapper)
    {
        $stringWrapper->setEncoding($this->getEncoding());
        $this->stringWrapper = $stringWrapper;
    }

    /**
     * Returns the actual encoding
     *
     * @return string
     */
    public function getEncoding()
    {
        return $this->options['encoding'];
    }

    /**
     * Sets a new encoding to use
     *
     * @param string $encoding
     * @return $this
     * @throws Exception\InvalidArgumentException
     */
    public function setEncoding($encoding)
    {
        $this->stringWrapper = StringUtils::getWrapper($encoding);
        $this->options['encoding'] = $encoding;
        return $this;
    }

    /**
     * Returns the length option
     *
     * @return int
     */
    private function getLength()
    {
        return $this->options['length'];
    }

    /**
     * Sets the length option
     *
     * @param  int $length
     * @return $this Provides a fluent interface
     */
    private function setLength($length)
    {
        $this->options['length'] = (int) $length;
        return $this;
    }

    /**
     * Returns true if and only if the string length of $value is at least the min option and
     * no greater than the max option (when the max option is not null).
     *
     * @param  string $value
     * @return bool
     */
    public function isValid($value)
    {
        if (! is_string($value)) {
            $this->error(self::INVALID);
            return false;
        }

        $this->setValue($value);

        $this->setLength($this->getStringWrapper()->strlen($value));
        if ($this->getLength() < $this->getMin()) {
            $this->error(self::TOO_SHORT);
        }

        if (null !== $this->getMax() && $this->getMax() < $this->getLength()) {
            $this->error(self::TOO_LONG);
        }

        if ($this->getMessages()) {
            return false;
        }

        return true;
    }
}
laminas-validator/src/Between.php000064400000013244147361032560013057 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-validator for the canonical source repository
 * @copyright https://github.com/laminas/laminas-validator/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-validator/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Validator;

use Laminas\Stdlib\ArrayUtils;
use Traversable;

class Between extends AbstractValidator
{
    const NOT_BETWEEN        = 'notBetween';
    const NOT_BETWEEN_STRICT = 'notBetweenStrict';
    const VALUE_NOT_NUMERIC  = 'valueNotNumeric';
    const VALUE_NOT_STRING   = 'valueNotString';

    /**
     * Retain if min and max are numeric values. Allow to not compare string and numeric types
     *
     * @var boolean
     */
    private $numeric;

    /**
     * Validation failure message template definitions
     *
     * @var array
     */
    protected $messageTemplates = [
        self::NOT_BETWEEN        => "The input is not between '%min%' and '%max%', inclusively",
        self::NOT_BETWEEN_STRICT => "The input is not strictly between '%min%' and '%max%'",
        self::VALUE_NOT_NUMERIC  => "The min ('%min%') and max ('%max%') values are numeric, but the input is not",
        self::VALUE_NOT_STRING   => "The min ('%min%') and max ('%max%') values are non-numeric strings, "
            . 'but the input is not a string',
    ];

    /**
     * Additional variables available for validation failure messages
     *
     * @var array
     */
    protected $messageVariables = [
        'min' => ['options' => 'min'],
        'max' => ['options' => 'max'],
    ];

    /**
     * Options for the between validator
     *
     * @var array
     */
    protected $options = [
        'inclusive' => true,  // Whether to do inclusive comparisons, allowing equivalence to min and/or max
        'min'       => 0,
        'max'       => PHP_INT_MAX,
    ];

    /**
     * Sets validator options
     * Accepts the following option keys:
     *   'min' => scalar, minimum border
     *   'max' => scalar, maximum border
     *   'inclusive' => boolean, inclusive border values
     *
     * @param  array|Traversable $options
     *
     * @throws Exception\InvalidArgumentException
     */
    public function __construct($options = null)
    {
        if ($options instanceof Traversable) {
            $options = ArrayUtils::iteratorToArray($options);
        }
        if (! is_array($options)) {
            $options = func_get_args();
            $temp['min'] = array_shift($options);
            if (! empty($options)) {
                $temp['max'] = array_shift($options);
            }

            if (! empty($options)) {
                $temp['inclusive'] = array_shift($options);
            }

            $options = $temp;
        }

        if (! array_key_exists('min', $options) || ! array_key_exists('max', $options)) {
            throw new Exception\InvalidArgumentException("Missing option: 'min' and 'max' have to be given");
        }

        if ((isset($options['min']) && is_numeric($options['min']))
            && (isset($options['max']) && is_numeric($options['max']))
        ) {
            $this->numeric = true;
        } elseif ((isset($options['min']) && is_string($options['min']))
            && (isset($options['max']) && is_string($options['max']))
        ) {
            $this->numeric = false;
        } else {
            throw new Exception\InvalidArgumentException(
                "Invalid options: 'min' and 'max' should be of the same scalar type"
            );
        }

        parent::__construct($options);
    }

    /**
     * Returns the min option
     *
     * @return mixed
     */
    public function getMin()
    {
        return $this->options['min'];
    }

    /**
     * Sets the min option
     *
     * @param  mixed $min
     * @return $this Provides a fluent interface
     */
    public function setMin($min)
    {
        $this->options['min'] = $min;
        return $this;
    }

    /**
     * Returns the max option
     *
     * @return mixed
     */
    public function getMax()
    {
        return $this->options['max'];
    }

    /**
     * Sets the max option
     *
     * @param  mixed $max
     * @return $this Provides a fluent interface
     */
    public function setMax($max)
    {
        $this->options['max'] = $max;
        return $this;
    }

    /**
     * Returns the inclusive option
     *
     * @return bool
     */
    public function getInclusive()
    {
        return $this->options['inclusive'];
    }

    /**
     * Sets the inclusive option
     *
     * @param  bool $inclusive
     * @return $this Provides a fluent interface
     */
    public function setInclusive($inclusive)
    {
        $this->options['inclusive'] = $inclusive;
        return $this;
    }

    /**
     * Returns true if and only if $value is between min and max options, inclusively
     * if inclusive option is true.
     *
     * @param  mixed $value
     * @return bool
     */
    public function isValid($value)
    {
        $this->setValue($value);

        if ($this->numeric && ! is_numeric($value)) {
            $this->error(self::VALUE_NOT_NUMERIC);
            return false;
        }
        if (! $this->numeric && ! is_string($value)) {
            $this->error(self::VALUE_NOT_STRING);
            return false;
        }

        if ($this->getInclusive()) {
            if ($this->getMin() > $value || $value > $this->getMax()) {
                $this->error(self::NOT_BETWEEN);
                return false;
            }
        } else {
            if ($this->getMin() >= $value || $value >= $this->getMax()) {
                $this->error(self::NOT_BETWEEN_STRICT);
                return false;
            }
        }

        return true;
    }
}
laminas-validator/src/Regex.php000064400000007110147361032560012533 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-validator for the canonical source repository
 * @copyright https://github.com/laminas/laminas-validator/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-validator/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Validator;

use Laminas\Stdlib\ArrayUtils;
use Laminas\Stdlib\ErrorHandler;
use Traversable;

class Regex extends AbstractValidator
{
    const INVALID   = 'regexInvalid';
    const NOT_MATCH = 'regexNotMatch';
    const ERROROUS  = 'regexErrorous';

    /**
     * @var array
     */
    protected $messageTemplates = [
        self::INVALID   => 'Invalid type given. String, integer or float expected',
        self::NOT_MATCH => "The input does not match against pattern '%pattern%'",
        self::ERROROUS  => "There was an internal error while using the pattern '%pattern%'",
    ];

    /**
     * @var array
     */
    protected $messageVariables = [
        'pattern' => 'pattern',
    ];

    /**
     * Regular expression pattern
     *
     * @var string
     */
    protected $pattern;

    /**
     * Sets validator options
     *
     * @param  string|array|Traversable $pattern
     * @throws Exception\InvalidArgumentException On missing 'pattern' parameter
     */
    public function __construct($pattern)
    {
        if (is_string($pattern)) {
            $this->setPattern($pattern);
            parent::__construct([]);
            return;
        }

        if ($pattern instanceof Traversable) {
            $pattern = ArrayUtils::iteratorToArray($pattern);
        }

        if (! is_array($pattern)) {
            throw new Exception\InvalidArgumentException('Invalid options provided to constructor');
        }

        if (! array_key_exists('pattern', $pattern)) {
            throw new Exception\InvalidArgumentException("Missing option 'pattern'");
        }

        $this->setPattern($pattern['pattern']);
        unset($pattern['pattern']);
        parent::__construct($pattern);
    }

    /**
     * Returns the pattern option
     *
     * @return string
     */
    public function getPattern()
    {
        return $this->pattern;
    }

    /**
     * Sets the pattern option
     *
     * @param  string $pattern
     * @throws Exception\InvalidArgumentException if there is a fatal error in pattern matching
     * @return $this Provides a fluent interface
     */
    public function setPattern($pattern)
    {
        ErrorHandler::start();
        $this->pattern = (string) $pattern;
        $status        = preg_match($this->pattern, 'Test');
        $error         = ErrorHandler::stop();

        if (false === $status) {
            throw new Exception\InvalidArgumentException(
                "Internal error parsing the pattern '{$this->pattern}'",
                0,
                $error
            );
        }

        return $this;
    }

    /**
     * Returns true if and only if $value matches against the pattern option
     *
     * @param  string $value
     * @return bool
     */
    public function isValid($value)
    {
        if (! is_string($value) && ! is_int($value) && ! is_float($value)) {
            $this->error(self::INVALID);
            return false;
        }

        $this->setValue($value);

        ErrorHandler::start();
        $status = preg_match($this->pattern, $value);
        ErrorHandler::stop();
        if (false === $status) {
            $this->error(self::ERROROUS);
            return false;
        }

        if (! $status) {
            $this->error(self::NOT_MATCH);
            return false;
        }

        return true;
    }
}
laminas-validator/src/Hex.php000064400000002307147361032560012210 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-validator for the canonical source repository
 * @copyright https://github.com/laminas/laminas-validator/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-validator/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Validator;

class Hex extends AbstractValidator
{
    const INVALID = 'hexInvalid';
    const NOT_HEX = 'notHex';

    /**
     * Validation failure message template definitions
     *
     * @var array
     */
    protected $messageTemplates = [
        self::INVALID => 'Invalid type given. String expected',
        self::NOT_HEX => 'The input contains non-hexadecimal characters',
    ];

    /**
     * Returns true if and only if $value contains only hexadecimal digit characters
     *
     * @param  string $value
     * @return bool
     */
    public function isValid($value)
    {
        if (! is_string($value) && ! is_int($value)) {
            $this->error(self::INVALID);
            return false;
        }

        $this->setValue($value);
        if (! ctype_xdigit((string) $value)) {
            $this->error(self::NOT_HEX);
            return false;
        }

        return true;
    }
}
laminas-validator/src/InArray.php000064400000015510147361032560013031 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-validator for the canonical source repository
 * @copyright https://github.com/laminas/laminas-validator/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-validator/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Validator;

use RecursiveArrayIterator;
use RecursiveIteratorIterator;

class InArray extends AbstractValidator
{
    const NOT_IN_ARRAY = 'notInArray';

    // Type of Strict check
    /**
     * standard in_array strict checking value and type
     */
    const COMPARE_STRICT = 1;

    /**
     * Non strict check but prevents "asdf" == 0 returning TRUE causing false/positive.
     * This is the most secure option for non-strict checks and replaces strict = false
     * This will only be effective when the input is a string
     */
    const COMPARE_NOT_STRICT_AND_PREVENT_STR_TO_INT_VULNERABILITY = 0;

    /**
     * Standard non-strict check where "asdf" == 0 returns TRUE
     * This will be wanted when comparing "0" against int 0
     */
    const COMPARE_NOT_STRICT = -1;

    /**
     * @var array
     */
    protected $messageTemplates = [
        self::NOT_IN_ARRAY => 'The input was not found in the haystack',
    ];

    /**
     * Haystack of possible values
     *
     * @var array
     */
    protected $haystack;

    /**
     * Type of strict check to be used. Due to "foo" == 0 === TRUE with in_array when strict = false,
     * an option has been added to prevent this. When $strict = 0/false, the most
     * secure non-strict check is implemented. if $strict = -1, the default in_array non-strict
     * behaviour is used
     *
     * @var int
     */
    protected $strict = self::COMPARE_NOT_STRICT_AND_PREVENT_STR_TO_INT_VULNERABILITY;

    /**
     * Whether a recursive search should be done
     *
     * @var bool
     */
    protected $recursive = false;

    /**
     * Returns the haystack option
     *
     * @return mixed
     * @throws Exception\RuntimeException if haystack option is not set
     */
    public function getHaystack()
    {
        if ($this->haystack === null) {
            throw new Exception\RuntimeException('haystack option is mandatory');
        }
        return $this->haystack;
    }

    /**
     * Sets the haystack option
     *
     * @param  mixed $haystack
     * @return $this Provides a fluent interface
     */
    public function setHaystack(array $haystack)
    {
        $this->haystack = $haystack;
        return $this;
    }

    /**
     * Returns the strict option
     *
     * @return bool|int
     */
    public function getStrict()
    {
        // To keep BC with new strict modes
        if ($this->strict == self::COMPARE_NOT_STRICT_AND_PREVENT_STR_TO_INT_VULNERABILITY
            || $this->strict == self::COMPARE_STRICT
        ) {
            return (bool) $this->strict;
        }
        return $this->strict;
    }

    /**
     * Sets the strict option mode
     * InArray::COMPARE_STRICT
     * InArray::COMPARE_NOT_STRICT_AND_PREVENT_STR_TO_INT_VULNERABILITY
     * InArray::COMPARE_NOT_STRICT
     *
     * @param  int $strict
     * @return $this Provides a fluent interface
     * @throws Exception\InvalidArgumentException
     */
    public function setStrict($strict)
    {
        $checkTypes = [
            self::COMPARE_NOT_STRICT_AND_PREVENT_STR_TO_INT_VULNERABILITY,    // 0
            self::COMPARE_STRICT,                                             // 1
            self::COMPARE_NOT_STRICT,                                         // -1
        ];

        // validate strict value
        if (! in_array($strict, $checkTypes)) {
            throw new Exception\InvalidArgumentException('Strict option must be one of the COMPARE_ constants');
        }

        $this->strict = $strict;
        return $this;
    }

    /**
     * Returns the recursive option
     *
     * @return bool
     */
    public function getRecursive()
    {
        return $this->recursive;
    }

    /**
     * Sets the recursive option
     *
     * @param  bool $recursive
     * @return $this Provides a fluent interface
     */
    public function setRecursive($recursive)
    {
        $this->recursive = (bool) $recursive;
        return $this;
    }

    /**
     * Returns true if and only if $value is contained in the haystack option. If the strict
     * option is true, then the type of $value is also checked.
     *
     * @param mixed $value
     * See {@link http://php.net/manual/function.in-array.php#104501}
     * @return bool
     */
    public function isValid($value)
    {
        // we create a copy of the haystack in case we need to modify it
        $haystack = $this->getHaystack();

        // if the input is a string or float, and vulnerability protection is on
        // we type cast the input to a string
        if (self::COMPARE_NOT_STRICT_AND_PREVENT_STR_TO_INT_VULNERABILITY == $this->strict
            && (is_int($value) || is_float($value))) {
            $value = (string) $value;
        }

        $this->setValue($value);

        if ($this->getRecursive()) {
            $iterator = new RecursiveIteratorIterator(new RecursiveArrayIterator($haystack));
            foreach ($iterator as $element) {
                if (self::COMPARE_STRICT == $this->strict) {
                    if ($element === $value) {
                        return true;
                    }
                } else {
                    // add protection to prevent string to int vuln's
                    $el = $element;
                    if (self::COMPARE_NOT_STRICT_AND_PREVENT_STR_TO_INT_VULNERABILITY == $this->strict
                        && is_string($value) && (is_int($el) || is_float($el))
                    ) {
                        $el = (string) $el;
                    }

                    if ($el == $value) {
                        return true;
                    }
                }
            }
        } else {
            /**
             * If the check is not strict, then, to prevent "asdf" being converted to 0
             * and returning a false positive if 0 is in haystack, we type cast
             * the haystack to strings. To prevent "56asdf" == 56 === TRUE we also
             * type cast values like 56 to strings as well.
             *
             * This occurs only if the input is a string and a haystack member is an int
             */
            if (self::COMPARE_NOT_STRICT_AND_PREVENT_STR_TO_INT_VULNERABILITY == $this->strict
                && is_string($value)
            ) {
                foreach ($haystack as &$h) {
                    if (is_int($h) || is_float($h)) {
                        $h = (string) $h;
                    }
                }
            }

            if (in_array($value, $haystack, self::COMPARE_STRICT == $this->strict)) {
                return true;
            }
        }

        $this->error(self::NOT_IN_ARRAY);
        return false;
    }
}
laminas-validator/src/Bitwise.php000064400000010316147361032560013071 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-validator for the canonical source repository
 * @copyright https://github.com/laminas/laminas-validator/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-validator/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Validator;

use Traversable;

class Bitwise extends AbstractValidator
{
    const OP_AND = 'and';
    const OP_XOR = 'xor';

    const NOT_AND        = 'notAnd';
    const NOT_AND_STRICT = 'notAndStrict';
    const NOT_XOR        = 'notXor';

    /**
     * @var integer
     */
    protected $control;

    /**
     * Validation failure message template definitions
     *
     * @var array
     */
    protected $messageTemplates = [
        self::NOT_AND        => "The input has no common bit set with '%control%'",
        self::NOT_AND_STRICT => "The input doesn't have the same bits set as '%control%'",
        self::NOT_XOR        => "The input has common bit set with '%control%'",
    ];

    /**
     * Additional variables available for validation failure messages
     *
     * @var array
     */
    protected $messageVariables = [
        'control' => 'control',
    ];

    /**
     * @var integer
     */
    protected $operator;

    /**
     * @var boolean
     */
    protected $strict = false;

    /**
     * Sets validator options
     * Accepts the following option keys:
     *   'control'  => integer
     *   'operator' =>
     *   'strict'   => boolean
     *
     * @param array|Traversable $options
     */
    public function __construct($options = null)
    {
        if ($options instanceof Traversable) {
            $options = iterator_to_array($options);
        }

        if (! is_array($options)) {
            $options = func_get_args();

            $temp['control'] = array_shift($options);

            if (! empty($options)) {
                $temp['operator'] = array_shift($options);
            }

            if (! empty($options)) {
                $temp['strict'] = array_shift($options);
            }

            $options = $temp;
        }

        parent::__construct($options);
    }

    /**
     * Returns the control parameter.
     *
     * @return integer
     */
    public function getControl()
    {
        return $this->control;
    }

    /**
     * Returns the operator parameter.
     *
     * @return string
     */
    public function getOperator()
    {
        return $this->operator;
    }

    /**
     * Returns the strict parameter.
     *
     * @return boolean
     */
    public function getStrict()
    {
        return $this->strict;
    }

    /**
     * Returns true if and only if $value is between min and max options, inclusively
     * if inclusive option is true.
     *
     * @param  mixed $value
     * @return bool
     */
    public function isValid($value)
    {
        $this->setValue($value);

        if (self::OP_AND === $this->operator) {
            if ($this->strict) {
                // All the bits set in value must be set in control
                $this->error(self::NOT_AND_STRICT);

                return (bool) (($this->control & $value) == $value);
            } else {
                // At least one of the bits must be common between value and control
                $this->error(self::NOT_AND);

                return (bool) ($this->control & $value);
            }
        } elseif (self::OP_XOR === $this->operator) {
            $this->error(self::NOT_XOR);

            return (bool) (($this->control ^ $value) === ($this->control | $value));
        }

        return false;
    }

    /**
     * Sets the control parameter.
     *
     * @param  integer $control
     * @return $this
     */
    public function setControl($control)
    {
        $this->control = (int) $control;

        return $this;
    }

    /**
     * Sets the operator parameter.
     *
     * @param  string  $operator
     * @return $this
     */
    public function setOperator($operator)
    {
        $this->operator = $operator;

        return $this;
    }

    /**
     * Sets the strict parameter.
     *
     * @param  boolean $strict
     * @return $this
     */
    public function setStrict($strict)
    {
        $this->strict = (bool) $strict;

        return $this;
    }
}
laminas-validator/src/File/UploadFile.php000064400000012531147361032560014367 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-validator for the canonical source repository
 * @copyright https://github.com/laminas/laminas-validator/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-validator/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Validator\File;

use Laminas\Validator\AbstractValidator;
use Laminas\Validator\Exception;
use Psr\Http\Message\UploadedFileInterface;

/**
 * Validator for the maximum size of a file up to a max of 2GB
 */
class UploadFile extends AbstractValidator
{
    /**
     * @const string Error constants
     */
    const INI_SIZE       = 'fileUploadFileErrorIniSize';
    const FORM_SIZE      = 'fileUploadFileErrorFormSize';
    const PARTIAL        = 'fileUploadFileErrorPartial';
    const NO_FILE        = 'fileUploadFileErrorNoFile';
    const NO_TMP_DIR     = 'fileUploadFileErrorNoTmpDir';
    const CANT_WRITE     = 'fileUploadFileErrorCantWrite';
    const EXTENSION      = 'fileUploadFileErrorExtension';
    const ATTACK         = 'fileUploadFileErrorAttack';
    const FILE_NOT_FOUND = 'fileUploadFileErrorFileNotFound';
    const UNKNOWN        = 'fileUploadFileErrorUnknown';

    /**
     * @var array Error message templates
     */
    protected $messageTemplates = [
        self::INI_SIZE       => 'The uploaded file exceeds the upload_max_filesize directive in php.ini',
        self::FORM_SIZE      => 'The uploaded file exceeds the MAX_FILE_SIZE directive that was '
            . 'specified in the HTML form',
        self::PARTIAL        => 'The uploaded file was only partially uploaded',
        self::NO_FILE        => 'No file was uploaded',
        self::NO_TMP_DIR     => 'Missing a temporary folder',
        self::CANT_WRITE     => 'Failed to write file to disk',
        self::EXTENSION      => 'A PHP extension stopped the file upload',
        self::ATTACK         => 'File was illegally uploaded. This could be a possible attack',
        self::FILE_NOT_FOUND => 'File was not found',
        self::UNKNOWN        => 'Unknown error while uploading file',
    ];

    /**
     * Returns true if and only if the file was uploaded without errors
     *
     * @param  string|array|UploadedFileInterface $value File to check for upload errors
     * @return bool
     * @throws Exception\InvalidArgumentException
     */
    public function isValid($value)
    {
        if (is_array($value)) {
            if (! isset($value['tmp_name']) || ! isset($value['name']) || ! isset($value['error'])) {
                throw new Exception\InvalidArgumentException(
                    'Value array must be in $_FILES format'
                );
            }

            return $this->validateUploadedFile(
                $value['error'],
                $value['name'],
                $value['tmp_name']
            );
        }

        if ($value instanceof UploadedFileInterface) {
            return $this->validatePsr7UploadedFile($value);
        }

        if (is_string($value)) {
            return $this->validateUploadedFile(0, basename($value), $value);
        }

        $this->error(self::UNKNOWN);
        return false;
    }

    /**
     * @param int $error UPLOAD_ERR_* constant value
     * @return bool
     */
    private function validateFileFromErrorCode($error)
    {
        switch ($error) {
            case UPLOAD_ERR_OK:
                return true;

            case UPLOAD_ERR_INI_SIZE:
                $this->error(self::INI_SIZE);
                return false;

            case UPLOAD_ERR_FORM_SIZE:
                $this->error(self::FORM_SIZE);
                return false;

            case UPLOAD_ERR_PARTIAL:
                $this->error(self::PARTIAL);
                return false;

            case UPLOAD_ERR_NO_FILE:
                $this->error(self::NO_FILE);
                return false;

            case UPLOAD_ERR_NO_TMP_DIR:
                $this->error(self::NO_TMP_DIR);
                return false;

            case UPLOAD_ERR_CANT_WRITE:
                $this->error(self::CANT_WRITE);
                return false;

            case UPLOAD_ERR_EXTENSION:
                $this->error(self::EXTENSION);
                return false;

            default:
                $this->error(self::UNKNOWN);
                return false;
        }
    }

    /**
     * @param  int $error UPLOAD_ERR_* constant
     * @param  string $filename
     * @param  string $uploadedFile Name of uploaded file (gen tmp_name)
     * @return bool
     */
    private function validateUploadedFile($error, $filename, $uploadedFile)
    {
        $this->setValue($filename);

        // Normal errors can be validated normally
        if ($error !== UPLOAD_ERR_OK) {
            return $this->validateFileFromErrorCode($error);
        }

        // Did we get no name? Is the file missing?
        if (empty($uploadedFile) || false === is_file($uploadedFile)) {
            $this->error(self::FILE_NOT_FOUND);
            return false;
        }

        // Do we have an invalid upload?
        if (! is_uploaded_file($uploadedFile)) {
            $this->error(self::ATTACK);
            return false;
        }

        return true;
    }

    /**
     * @return bool
     */
    private function validatePsr7UploadedFile(UploadedFileInterface $uploadedFile)
    {
        $this->setValue($uploadedFile);
        return $this->validateFileFromErrorCode($uploadedFile->getError());
    }
}
laminas-validator/src/File/ExcludeMimeType.php000064400000006076147361032560015415 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-validator for the canonical source repository
 * @copyright https://github.com/laminas/laminas-validator/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-validator/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Validator\File;

/**
 * Validator for the mime type of a file
 */
class ExcludeMimeType extends MimeType
{
    use FileInformationTrait;

    const FALSE_TYPE   = 'fileExcludeMimeTypeFalse';
    const NOT_DETECTED = 'fileExcludeMimeTypeNotDetected';
    const NOT_READABLE = 'fileExcludeMimeTypeNotReadable';

    /**
     * @var array Error message templates
     */
    protected $messageTemplates = [
        self::FALSE_TYPE   => "File has an incorrect mimetype of '%type%'",
        self::NOT_DETECTED => 'The mimetype could not be detected from the file',
        self::NOT_READABLE => 'File is not readable or does not exist',
    ];

    /**
     * Returns true if the mimetype of the file does not matche the given ones. Also parts
     * of mimetypes can be checked. If you give for example "image" all image
     * mime types will not be accepted like "image/gif", "image/jpeg" and so on.
     *
     * @param  string|array $value Real file to check for mimetype
     * @param  array        $file  File data from \Laminas\File\Transfer\Transfer (optional)
     * @return bool
     */
    public function isValid($value, $file = null)
    {
        $fileInfo = $this->getFileInfo($value, $file, true);

        $this->setValue($fileInfo['filename']);

        // Is file readable ?
        if (empty($fileInfo['file']) || false === is_readable($fileInfo['file'])) {
            $this->error(self::NOT_READABLE);
            return false;
        }

        $mimefile = $this->getMagicFile();
        if (class_exists('finfo', false)) {
            if (! $this->isMagicFileDisabled() && (! empty($mimefile) && empty($this->finfo))) {
                $this->finfo = finfo_open(FILEINFO_MIME_TYPE, $mimefile);
            }

            if (empty($this->finfo)) {
                $this->finfo = finfo_open(FILEINFO_MIME_TYPE);
            }

            $this->type = null;
            if (! empty($this->finfo)) {
                $this->type = finfo_file($this->finfo, $fileInfo['file']);
            }
        }

        if (empty($this->type) && $this->getHeaderCheck()) {
            $this->type = $fileInfo['filetype'];
        }

        if (empty($this->type)) {
            $this->error(self::NOT_DETECTED);
            return false;
        }

        $mimetype = $this->getMimeType(true);
        if (in_array($this->type, $mimetype)) {
            $this->error(self::FALSE_TYPE);
            return false;
        }

        $types = explode('/', $this->type);
        $types = array_merge($types, explode('-', $this->type));
        $types = array_merge($types, explode(';', $this->type));
        foreach ($mimetype as $mime) {
            if (in_array($mime, $types)) {
                $this->error(self::FALSE_TYPE);
                return false;
            }
        }

        return true;
    }
}
laminas-validator/src/File/MimeType.php000064400000027700147361032560014100 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-validator for the canonical source repository
 * @copyright https://github.com/laminas/laminas-validator/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-validator/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Validator\File;

use Laminas\Stdlib\ArrayUtils;
use Laminas\Stdlib\ErrorHandler;
use Laminas\Validator\AbstractValidator;
use Laminas\Validator\Exception;
use Traversable;

/**
 * Validator for the mime type of a file
 */
class MimeType extends AbstractValidator
{
    use FileInformationTrait;

    /**#@+
     * @const Error type constants
     */
    const FALSE_TYPE   = 'fileMimeTypeFalse';
    const NOT_DETECTED = 'fileMimeTypeNotDetected';
    const NOT_READABLE = 'fileMimeTypeNotReadable';
    /**#@-*/

    /**
     * @var array Error message templates
     */
    protected $messageTemplates = [
        self::FALSE_TYPE   => "File has an incorrect mimetype of '%type%'",
        self::NOT_DETECTED => 'The mimetype could not be detected from the file',
        self::NOT_READABLE => 'File is not readable or does not exist',
    ];

    /**
     * @var array
     */
    protected $messageVariables = [
        'type' => 'type',
    ];

    /**
     * @var string
     */
    protected $type;

    /**
     * Finfo object to use
     *
     * @var resource
     */
    protected $finfo;

    /**
     * If no environment variable 'MAGIC' is set, try and autodiscover it based on common locations
     * @var array
     */
    protected $magicFiles = [
        '/usr/share/misc/magic',
        '/usr/share/misc/magic.mime',
        '/usr/share/misc/magic.mgc',
        '/usr/share/mime/magic',
        '/usr/share/mime/magic.mime',
        '/usr/share/mime/magic.mgc',
        '/usr/share/file/magic',
        '/usr/share/file/magic.mime',
        '/usr/share/file/magic.mgc',
    ];

    /**
     * Options for this validator
     *
     * @var array
     */
    protected $options = [
        'enableHeaderCheck' => false,  // Allow header check
        'disableMagicFile'  => false,  // Disable usage of magicfile
        'magicFile'         => null,   // Magicfile to use
        'mimeType'          => null,   // Mimetype to allow
    ];

    /**
     * Sets validator options
     *
     * Mimetype to accept
     * - NULL means default PHP usage by using the environment variable 'magic'
     * - FALSE means disabling searching for mimetype, should be used for PHP 5.3
     * - A string is the mimetype file to use
     *
     * @param  string|array|Traversable $options
     */
    public function __construct($options = null)
    {
        if ($options instanceof Traversable) {
            $options = ArrayUtils::iteratorToArray($options);
        } elseif (is_string($options)) {
            $this->setMimeType($options);
            $options = [];
        } elseif (is_array($options)) {
            if (isset($options['magicFile'])) {
                $this->setMagicFile($options['magicFile']);
                unset($options['magicFile']);
            }

            if (isset($options['enableHeaderCheck'])) {
                $this->enableHeaderCheck($options['enableHeaderCheck']);
                unset($options['enableHeaderCheck']);
            }

            if (array_key_exists('mimeType', $options)) {
                $this->setMimeType($options['mimeType']);
                unset($options['mimeType']);
            }

            // Handle cases where mimetypes are interspersed with options, or
            // options are simply an array of mime types
            foreach (array_keys($options) as $key) {
                if (! is_int($key)) {
                    continue;
                }
                $this->addMimeType($options[$key]);
                unset($options[$key]);
            }
        }

        parent::__construct($options);
    }

    /**
     * Returns the actual set magicfile
     *
     * @return string
     */
    public function getMagicFile()
    {
        if (null === $this->options['magicFile']) {
            $magic = getenv('magic');
            if (! empty($magic)) {
                $this->setMagicFile($magic);
                if ($this->options['magicFile'] === null) {
                    $this->options['magicFile'] = false;
                }
                return $this->options['magicFile'];
            }

            foreach ($this->magicFiles as $file) {
                try {
                    $this->setMagicFile($file);
                } catch (Exception\ExceptionInterface $e) {
                    // suppressing errors which are thrown due to open_basedir restrictions
                    continue;
                }

                if ($this->options['magicFile'] !== null) {
                    return $this->options['magicFile'];
                }
            }

            if ($this->options['magicFile'] === null) {
                $this->options['magicFile'] = false;
            }
        }

        return $this->options['magicFile'];
    }

    /**
     * Sets the magicfile to use
     * if null, the MAGIC constant from php is used
     * if the MAGIC file is erroneous, no file will be set
     * if false, the default MAGIC file from PHP will be used
     *
     * @param  string $file
     * @throws Exception\RuntimeException When finfo can not read the magicfile
     * @throws Exception\InvalidArgumentException
     * @throws Exception\InvalidMagicMimeFileException
     * @return $this Provides fluid interface
     */
    public function setMagicFile($file)
    {
        if ($file === false) {
            $this->options['magicFile'] = false;
        } elseif (empty($file)) {
            $this->options['magicFile'] = null;
        } elseif (! class_exists('finfo', false)) {
            $this->options['magicFile'] = null;
            throw new Exception\RuntimeException('Magicfile can not be set; there is no finfo extension installed');
        } elseif (! is_file($file) || ! is_readable($file)) {
            throw new Exception\InvalidArgumentException(sprintf(
                'The given magicfile ("%s") could not be read',
                $file
            ));
        } else {
            ErrorHandler::start(E_NOTICE | E_WARNING);
            $this->finfo = finfo_open(FILEINFO_MIME_TYPE, $file);
            $error       = ErrorHandler::stop();
            if (empty($this->finfo)) {
                $this->finfo = null;
                throw new Exception\InvalidMagicMimeFileException(sprintf(
                    'The given magicfile ("%s") could not be used by ext/finfo',
                    $file
                ), 0, $error);
            }
            $this->options['magicFile'] = $file;
        }

        return $this;
    }

    /**
     * Disables usage of MagicFile
     *
     * @param $disable boolean False disables usage of magic file
     * @return $this Provides fluid interface
     */
    public function disableMagicFile($disable)
    {
        $this->options['disableMagicFile'] = (bool) $disable;
        return $this;
    }

    /**
     * Is usage of MagicFile disabled?
     *
     * @return bool
     */
    public function isMagicFileDisabled()
    {
        return $this->options['disableMagicFile'];
    }

    /**
     * Returns the Header Check option
     *
     * @return bool
     */
    public function getHeaderCheck()
    {
        return $this->options['enableHeaderCheck'];
    }

    /**
     * Defines if the http header should be used
     * Note that this is unsafe and therefor the default value is false
     *
     * @param  bool $headerCheck
     * @return $this Provides fluid interface
     */
    public function enableHeaderCheck($headerCheck = true)
    {
        $this->options['enableHeaderCheck'] = (bool) $headerCheck;
        return $this;
    }

    /**
     * Returns the set mimetypes
     *
     * @param  bool $asArray Returns the values as array, when false a concatenated string is returned
     * @return string|array
     */
    public function getMimeType($asArray = false)
    {
        $asArray  = (bool) $asArray;
        $mimetype = (string) $this->options['mimeType'];
        if ($asArray) {
            $mimetype = explode(',', $mimetype);
        }

        return $mimetype;
    }

    /**
     * Sets the mimetypes
     *
     * @param  string|array $mimetype The mimetypes to validate
     * @return $this Provides a fluent interface
     */
    public function setMimeType($mimetype)
    {
        $this->options['mimeType'] = null;
        $this->addMimeType($mimetype);
        return $this;
    }

    /**
     * Adds the mimetypes
     *
     * @param  string|array $mimetype The mimetypes to add for validation
     * @throws Exception\InvalidArgumentException
     * @return $this Provides a fluent interface
     */
    public function addMimeType($mimetype)
    {
        $mimetypes = $this->getMimeType(true);

        if (is_string($mimetype)) {
            $mimetype = explode(',', $mimetype);
        } elseif (! is_array($mimetype)) {
            throw new Exception\InvalidArgumentException('Invalid options to validator provided');
        }

        if (isset($mimetype['magicFile'])) {
            unset($mimetype['magicFile']);
        }

        foreach ($mimetype as $content) {
            if (empty($content) || ! is_string($content)) {
                continue;
            }
            $mimetypes[] = trim($content);
        }
        $mimetypes = array_unique($mimetypes);

        // Sanity check to ensure no empty values
        foreach ($mimetypes as $key => $mt) {
            if (empty($mt)) {
                unset($mimetypes[$key]);
            }
        }

        $this->options['mimeType'] = implode(',', $mimetypes);

        return $this;
    }

    /**
     * Defined by Laminas\Validator\ValidatorInterface
     *
     * Returns true if the mimetype of the file matches the given ones. Also parts
     * of mimetypes can be checked. If you give for example "image" all image
     * mime types will be accepted like "image/gif", "image/jpeg" and so on.
     *
     * @param  string|array $value Real file to check for mimetype
     * @param  array        $file  File data from \Laminas\File\Transfer\Transfer (optional)
     * @return bool
     */
    public function isValid($value, $file = null)
    {
        $fileInfo = $this->getFileInfo($value, $file, true);

        $this->setValue($fileInfo['filename']);

        // Is file readable ?
        if (empty($fileInfo['file']) || false === is_readable($fileInfo['file'])) {
            $this->error(static::NOT_READABLE);
            return false;
        }

        $mimefile = $this->getMagicFile();
        if (class_exists('finfo', false)) {
            if (! $this->isMagicFileDisabled() && (! empty($mimefile) && empty($this->finfo))) {
                ErrorHandler::start(E_NOTICE | E_WARNING);
                $this->finfo = finfo_open(FILEINFO_MIME_TYPE, $mimefile);
                ErrorHandler::stop();
            }

            if (empty($this->finfo)) {
                ErrorHandler::start(E_NOTICE | E_WARNING);
                $this->finfo = finfo_open(FILEINFO_MIME_TYPE);
                ErrorHandler::stop();
            }

            $this->type = null;
            if (! empty($this->finfo)) {
                $this->type = finfo_file($this->finfo, $fileInfo['file']);
                unset($this->finfo);
            }
        }

        if (empty($this->type) && $this->getHeaderCheck()) {
            $this->type = $fileInfo['filetype'];
        }

        if (empty($this->type)) {
            $this->error(static::NOT_DETECTED);
            return false;
        }

        $mimetype = $this->getMimeType(true);
        if (in_array($this->type, $mimetype)) {
            return true;
        }

        $types = explode('/', $this->type);
        $types = array_merge($types, explode('-', $this->type));
        $types = array_merge($types, explode(';', $this->type));
        foreach ($mimetype as $mime) {
            if (in_array($mime, $types)) {
                return true;
            }
        }

        $this->error(static::FALSE_TYPE);
        return false;
    }
}
laminas-validator/src/File/Extension.php000064400000013671147361032560014325 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-validator for the canonical source repository
 * @copyright https://github.com/laminas/laminas-validator/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-validator/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Validator\File;

use Laminas\Stdlib\ArrayUtils;
use Laminas\Validator\AbstractValidator;
use Traversable;

/**
 * Validator for the file extension of a file
 */
class Extension extends AbstractValidator
{
    use FileInformationTrait;

    /**
     * @const string Error constants
     */
    const FALSE_EXTENSION = 'fileExtensionFalse';
    const NOT_FOUND       = 'fileExtensionNotFound';

    /**
     * @var array Error message templates
     */
    protected $messageTemplates = [
        self::FALSE_EXTENSION => 'File has an incorrect extension',
        self::NOT_FOUND       => 'File is not readable or does not exist',
    ];

    /**
     * Options for this validator
     *
     * @var array
     */
    protected $options = [
        'case'      => false,   // Validate case sensitive
        'extension' => '',      // List of extensions
        'allowNonExistentFile' => false, // Allow validation even if file does not exist
    ];

    /**
     * @var array Error message template variables
     */
    protected $messageVariables = [
        'extension' => ['options' => 'extension'],
    ];

    /**
     * Sets validator options
     *
     * @param  string|array|Traversable $options
     */
    public function __construct($options = null)
    {
        if ($options instanceof Traversable) {
            $options = ArrayUtils::iteratorToArray($options);
        }

        $case = null;
        if (1 < func_num_args()) {
            $case = func_get_arg(1);
        }

        if (is_array($options)) {
            if (isset($options['case'])) {
                $case = $options['case'];
                unset($options['case']);
            }

            if (! array_key_exists('extension', $options)) {
                $options = ['extension' => $options];
            }
        } else {
            $options = ['extension' => $options];
        }

        if ($case !== null) {
            $options['case'] = $case;
        }

        parent::__construct($options);
    }

    /**
     * Returns the case option
     *
     * @return bool
     */
    public function getCase()
    {
        return $this->options['case'];
    }

    /**
     * Sets the case to use
     *
     * @param  bool $case
     * @return $this Provides a fluent interface
     */
    public function setCase($case)
    {
        $this->options['case'] = (bool) $case;
        return $this;
    }

    /**
     * Returns the set file extension
     *
     * @return array
     */
    public function getExtension()
    {
        $extension = explode(',', $this->options['extension']);

        return $extension;
    }

    /**
     * Sets the file extensions
     *
     * @param  string|array $extension The extensions to validate
     * @return $this Provides a fluent interface
     */
    public function setExtension($extension)
    {
        $this->options['extension'] = null;
        $this->addExtension($extension);
        return $this;
    }

    /**
     * Adds the file extensions
     *
     * @param  string|array $extension The extensions to add for validation
     * @return $this Provides a fluent interface
     */
    public function addExtension($extension)
    {
        $extensions = $this->getExtension();
        if (is_string($extension)) {
            $extension = explode(',', $extension);
        }

        foreach ($extension as $content) {
            if (empty($content) || ! is_string($content)) {
                continue;
            }

            $extensions[] = trim($content);
        }

        $extensions = array_unique($extensions);

        // Sanity check to ensure no empty values
        foreach ($extensions as $key => $ext) {
            if (empty($ext)) {
                unset($extensions[$key]);
            }
        }

        $this->options['extension'] = implode(',', $extensions);
        return $this;
    }

    /**
     * Returns whether or not to allow validation of non-existent files.
     *
     * @return bool
     */
    public function getAllowNonExistentFile()
    {
        return $this->options['allowNonExistentFile'];
    }

    /**
     * Sets the flag indicating whether or not to allow validation of non-existent files.
     *
     * @param  bool $flag Whether or not to allow validation of non-existent files.
     * @return $this Provides a fluent interface
     */
    public function setAllowNonExistentFile($flag)
    {
        $this->options['allowNonExistentFile'] = (bool) $flag;
        return $this;
    }

    /**
     * Returns true if and only if the file extension of $value is included in the
     * set extension list
     *
     * @param  string|array $value Real file to check for extension
     * @param  array        $file  File data from \Laminas\File\Transfer\Transfer (optional)
     * @return bool
     */
    public function isValid($value, $file = null)
    {
        $fileInfo = $this->getFileInfo($value, $file);

        // Is file readable ?
        if (! $this->getAllowNonExistentFile()
            && (empty($fileInfo['file']) || false === is_readable($fileInfo['file']))
        ) {
            $this->error(self::NOT_FOUND);
            return false;
        }

        $this->setValue($fileInfo['filename']);

        $extension  = substr($fileInfo['filename'], strrpos($fileInfo['filename'], '.') + 1);
        $extensions = $this->getExtension();

        if ($this->getCase() && (in_array($extension, $extensions))) {
            return true;
        } elseif (! $this->getCase()) {
            foreach ($extensions as $ext) {
                if (strtolower($ext) == strtolower($extension)) {
                    return true;
                }
            }
        }

        $this->error(self::FALSE_EXTENSION);
        return false;
    }
}
laminas-validator/src/File/Hash.php000064400000011025147361032560013223 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-validator for the canonical source repository
 * @copyright https://github.com/laminas/laminas-validator/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-validator/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Validator\File;

use Laminas\Validator\AbstractValidator;
use Laminas\Validator\Exception;

/**
 * Validator for the hash of given files
 */
class Hash extends AbstractValidator
{
    use FileInformationTrait;

    /**
     * @const string Error constants
     */
    const DOES_NOT_MATCH = 'fileHashDoesNotMatch';
    const NOT_DETECTED   = 'fileHashHashNotDetected';
    const NOT_FOUND      = 'fileHashNotFound';

    /**
     * @var array Error message templates
     */
    protected $messageTemplates = [
        self::DOES_NOT_MATCH => 'File does not match the given hashes',
        self::NOT_DETECTED   => 'A hash could not be evaluated for the given file',
        self::NOT_FOUND      => 'File is not readable or does not exist',
    ];

    /**
     * Options for this validator
     *
     * @var string
     */
    protected $options = [
        'algorithm' => 'crc32',
        'hash'      => null,
    ];

    /**
     * Sets validator options
     *
     * @param string|array $options
     */
    public function __construct($options = null)
    {
        if (is_scalar($options) ||
            (is_array($options) && ! array_key_exists('hash', $options))) {
            $options = ['hash' => $options];
        }

        if (1 < func_num_args()) {
            $options['algorithm'] = func_get_arg(1);
        }

        parent::__construct($options);
    }

    /**
     * Returns the set hash values as array, the hash as key and the algorithm the value
     *
     * @return array
     */
    public function getHash()
    {
        return $this->options['hash'];
    }

    /**
     * Sets the hash for one or multiple files
     *
     * @param  string|array $options
     * @return $this Provides a fluent interface
     */
    public function setHash($options)
    {
        $this->options['hash'] = null;
        $this->addHash($options);

        return $this;
    }

    /**
     * Adds the hash for one or multiple files
     *
     * @param  string|array $options
     * @throws Exception\InvalidArgumentException
     * @return $this Provides a fluent interface
     */
    public function addHash($options)
    {
        if (is_string($options)) {
            $options = [$options];
        } elseif (! is_array($options)) {
            throw new Exception\InvalidArgumentException('False parameter given');
        }

        $known = hash_algos();
        if (! isset($options['algorithm'])) {
            $algorithm = $this->options['algorithm'];
        } else {
            $algorithm = $options['algorithm'];
            unset($options['algorithm']);
        }

        if (! in_array($algorithm, $known)) {
            throw new Exception\InvalidArgumentException("Unknown algorithm '{$algorithm}'");
        }

        foreach ($options as $value) {
            if (! is_string($value)) {
                throw new Exception\InvalidArgumentException(sprintf(
                    'Hash must be a string, %s received',
                    is_object($value) ? get_class($value) : gettype($value)
                ));
            }
            $this->options['hash'][$value] = $algorithm;
        }

        return $this;
    }

    /**
     * Returns true if and only if the given file confirms the set hash
     *
     * @param  string|array $value File to check for hash
     * @param  array        $file  File data from \Laminas\File\Transfer\Transfer (optional)
     * @return bool
     */
    public function isValid($value, $file = null)
    {
        $fileInfo = $this->getFileInfo($value, $file);

        $this->setValue($fileInfo['filename']);

        // Is file readable ?
        if (empty($fileInfo['file']) || false === is_readable($fileInfo['file'])) {
            $this->error(self::NOT_FOUND);
            return false;
        }

        $algos = array_unique(array_values($this->getHash()));
        foreach ($algos as $algorithm) {
            $filehash = hash_file($algorithm, $fileInfo['file']);

            if ($filehash === false) {
                $this->error(self::NOT_DETECTED);
                return false;
            }

            if (isset($this->getHash()[$filehash]) && $this->getHash()[$filehash] === $algorithm) {
                return true;
            }
        }

        $this->error(self::DOES_NOT_MATCH);
        return false;
    }
}
laminas-validator/src/File/IsImage.php000064400000006421147361032560013662 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-validator for the canonical source repository
 * @copyright https://github.com/laminas/laminas-validator/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-validator/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Validator\File;

use Laminas\Stdlib\ArrayUtils;
use Traversable;

/**
 * Validator which checks if the file is an image
 */
class IsImage extends MimeType
{
    /**
     * @const string Error constants
     */
    const FALSE_TYPE   = 'fileIsImageFalseType';
    const NOT_DETECTED = 'fileIsImageNotDetected';
    const NOT_READABLE = 'fileIsImageNotReadable';

    /**
     * @var array Error message templates
     */
    protected $messageTemplates = [
        self::FALSE_TYPE   => "File is no image, '%type%' detected",
        self::NOT_DETECTED => 'The mimetype could not be detected from the file',
        self::NOT_READABLE => 'File is not readable or does not exist',
    ];

    /**
     * Sets validator options
     *
     * @param array|Traversable|string $options
     */
    public function __construct($options = [])
    {
        // http://www.iana.org/assignments/media-types/media-types.xhtml#image
        $default = [
            'application/cdf',
            'application/dicom',
            'application/fractals',
            'application/postscript',
            'application/vnd.hp-hpgl',
            'application/vnd.oasis.opendocument.graphics',
            'application/x-cdf',
            'application/x-cmu-raster',
            'application/x-ima',
            'application/x-inventor',
            'application/x-koan',
            'application/x-portable-anymap',
            'application/x-world-x-3dmf',
            'image/bmp',
            'image/c',
            'image/cgm',
            'image/fif',
            'image/gif',
            'image/jpeg',
            'image/jpm',
            'image/jpx',
            'image/jp2',
            'image/naplps',
            'image/pjpeg',
            'image/png',
            'image/svg',
            'image/svg+xml',
            'image/tiff',
            'image/vnd.adobe.photoshop',
            'image/vnd.djvu',
            'image/vnd.fpx',
            'image/vnd.net-fpx',
            'image/webp',
            'image/x-cmu-raster',
            'image/x-cmx',
            'image/x-coreldraw',
            'image/x-cpi',
            'image/x-emf',
            'image/x-ico',
            'image/x-icon',
            'image/x-jg',
            'image/x-ms-bmp',
            'image/x-niff',
            'image/x-pict',
            'image/x-pcx',
            'image/x-png',
            'image/x-portable-anymap',
            'image/x-portable-bitmap',
            'image/x-portable-greymap',
            'image/x-portable-pixmap',
            'image/x-quicktime',
            'image/x-rgb',
            'image/x-tiff',
            'image/x-unknown',
            'image/x-windows-bmp',
            'image/x-xpmi',
        ];

        if ($options instanceof Traversable) {
            $options = ArrayUtils::iteratorToArray($options);
        }

        if ($options === null) {
            $options = [];
        }

        parent::__construct($options);

        if (! $this->getMimeType()) {
            $this->setMimeType($default);
        }
    }
}
laminas-validator/src/File/Crc32.php000064400000005561147361032560013224 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-validator for the canonical source repository
 * @copyright https://github.com/laminas/laminas-validator/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-validator/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Validator\File;

/**
 * Validator for the crc32 hash of given files
 */
class Crc32 extends Hash
{
    use FileInformationTrait;

    /**
     * @const string Error constants
     */
    const DOES_NOT_MATCH = 'fileCrc32DoesNotMatch';
    const NOT_DETECTED   = 'fileCrc32NotDetected';
    const NOT_FOUND      = 'fileCrc32NotFound';

    /**
     * @var array Error message templates
     */
    protected $messageTemplates = [
        self::DOES_NOT_MATCH => 'File does not match the given crc32 hashes',
        self::NOT_DETECTED   => 'A crc32 hash could not be evaluated for the given file',
        self::NOT_FOUND      => 'File is not readable or does not exist',
    ];

    /**
     * Options for this validator
     *
     * @var string
     */
    protected $options = [
        'algorithm' => 'crc32',
        'hash'      => null,
    ];

    /**
     * Returns all set crc32 hashes
     *
     * @return array
     */
    public function getCrc32()
    {
        return $this->getHash();
    }

    /**
     * Sets the crc32 hash for one or multiple files
     *
     * @param  string|array $options
     * @return $this Provides a fluent interface
     */
    public function setCrc32($options)
    {
        $this->setHash($options);
        return $this;
    }

    /**
     * Adds the crc32 hash for one or multiple files
     *
     * @param  string|array $options
     * @return $this Provides a fluent interface
     */
    public function addCrc32($options)
    {
        $this->addHash($options);
        return $this;
    }

    /**
     * Returns true if and only if the given file confirms the set hash
     *
     * @param  string|array $value Filename to check for hash
     * @param  array        $file  File data from \Laminas\File\Transfer\Transfer (optional)
     * @return bool
     */
    public function isValid($value, $file = null)
    {
        $fileInfo = $this->getFileInfo($value, $file);

        $this->setValue($fileInfo['filename']);

        // Is file readable ?
        if (empty($fileInfo['file']) || false === is_readable($fileInfo['file'])) {
            $this->error(self::NOT_FOUND);
            return false;
        }

        $hashes   = array_unique(array_keys($this->getHash()));
        $filehash = hash_file('crc32', $fileInfo['file']);
        if ($filehash === false) {
            $this->error(self::NOT_DETECTED);
            return false;
        }

        foreach ($hashes as $hash) {
            if ($filehash === $hash) {
                return true;
            }
        }

        $this->error(self::DOES_NOT_MATCH);
        return false;
    }
}
laminas-validator/src/File/IsCompressed.php000064400000005324147361032560014745 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-validator for the canonical source repository
 * @copyright https://github.com/laminas/laminas-validator/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-validator/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Validator\File;

use Laminas\Stdlib\ArrayUtils;
use Traversable;

/**
 * Validator which checks if the file already exists in the directory
 */
class IsCompressed extends MimeType
{
    /**
     * @const string Error constants
     */
    const FALSE_TYPE   = 'fileIsCompressedFalseType';
    const NOT_DETECTED = 'fileIsCompressedNotDetected';
    const NOT_READABLE = 'fileIsCompressedNotReadable';

    /**
     * @var array Error message templates
     */
    protected $messageTemplates = [
        self::FALSE_TYPE   => "File is not compressed, '%type%' detected",
        self::NOT_DETECTED => 'The mimetype could not be detected from the file',
        self::NOT_READABLE => 'File is not readable or does not exist',
    ];

    /**
     * Sets validator options
     *
     * @param string|array|Traversable $options
     */
    public function __construct($options = [])
    {
        // http://hul.harvard.edu/ois/systems/wax/wax-public-help/mimetypes.htm
        $default = [
            'application/arj',
            'application/gnutar',
            'application/lha',
            'application/lzx',
            'application/vnd.ms-cab-compressed',
            'application/x-ace-compressed',
            'application/x-arc',
            'application/x-archive',
            'application/x-arj',
            'application/x-bzip',
            'application/x-bzip2',
            'application/x-cab-compressed',
            'application/x-compress',
            'application/x-compressed',
            'application/x-cpio',
            'application/x-debian-package',
            'application/x-eet',
            'application/x-gzip',
            'application/x-java-pack200',
            'application/x-lha',
            'application/x-lharc',
            'application/x-lzh',
            'application/x-lzma',
            'application/x-lzx',
            'application/x-rar',
            'application/x-sit',
            'application/x-stuffit',
            'application/x-tar',
            'application/zip',
            'application/x-zip',
            'application/zoo',
            'multipart/x-gzip',
        ];

        if ($options instanceof Traversable) {
            $options = ArrayUtils::iteratorToArray($options);
        }

        if ($options === null) {
            $options = [];
        }

        parent::__construct($options);

        if (! $this->getMimeType()) {
            $this->setMimeType($default);
        }
    }
}
laminas-validator/src/File/Md5.php000064400000005522147361032560012772 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-validator for the canonical source repository
 * @copyright https://github.com/laminas/laminas-validator/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-validator/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Validator\File;

/**
 * Validator for the md5 hash of given files
 */
class Md5 extends Hash
{
    use FileInformationTrait;

    /**
     * @const string Error constants
     */
    const DOES_NOT_MATCH = 'fileMd5DoesNotMatch';
    const NOT_DETECTED   = 'fileMd5NotDetected';
    const NOT_FOUND      = 'fileMd5NotFound';

    /**
     * @var array Error message templates
     */
    protected $messageTemplates = [
        self::DOES_NOT_MATCH => 'File does not match the given md5 hashes',
        self::NOT_DETECTED   => 'An md5 hash could not be evaluated for the given file',
        self::NOT_FOUND      => 'File is not readable or does not exist',
    ];

    /**
     * Options for this validator
     *
     * @var string
     */
    protected $options = [
        'algorithm' => 'md5',
        'hash'      => null,
    ];

    /**
     * Returns all set md5 hashes
     *
     * @return array
     */
    public function getMd5()
    {
        return $this->getHash();
    }

    /**
     * Sets the md5 hash for one or multiple files
     *
     * @param  string|array $options
     * @return Hash Provides a fluent interface
     */
    public function setMd5($options)
    {
        $this->setHash($options);
        return $this;
    }

    /**
     * Adds the md5 hash for one or multiple files
     *
     * @param  string|array $options
     * @return Hash Provides a fluent interface
     */
    public function addMd5($options)
    {
        $this->addHash($options);
        return $this;
    }

    /**
     * Returns true if and only if the given file confirms the set hash
     *
     * @param  string|array $value Filename to check for hash
     * @param  array        $file  File data from \Laminas\File\Transfer\Transfer (optional)
     * @return bool
     */
    public function isValid($value, $file = null)
    {
        $fileInfo = $this->getFileInfo($value, $file);

        $this->setValue($fileInfo['filename']);

        // Is file readable ?
        if (empty($fileInfo['file']) || false === is_readable($fileInfo['file'])) {
            $this->error(self::NOT_FOUND);
            return false;
        }

        $hashes   = array_unique(array_keys($this->getHash()));
        $filehash = hash_file('md5', $fileInfo['file']);
        if ($filehash === false) {
            $this->error(self::NOT_DETECTED);
            return false;
        }

        foreach ($hashes as $hash) {
            if ($filehash === $hash) {
                return true;
            }
        }

        $this->error(self::DOES_NOT_MATCH);
        return false;
    }
}
laminas-validator/src/File/Size.php000064400000023426147361032560013262 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-validator for the canonical source repository
 * @copyright https://github.com/laminas/laminas-validator/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-validator/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Validator\File;

use Laminas\Stdlib\ErrorHandler;
use Laminas\Validator\AbstractValidator;
use Laminas\Validator\Exception;

/**
 * Validator for the maximum size of a file up to a max of 2GB
 */
class Size extends AbstractValidator
{
    use FileInformationTrait;

    /**
     * @const string Error constants
     */
    const TOO_BIG   = 'fileSizeTooBig';
    const TOO_SMALL = 'fileSizeTooSmall';
    const NOT_FOUND = 'fileSizeNotFound';

    /**
     * @var array Error message templates
     */
    protected $messageTemplates = [
        self::TOO_BIG   => "Maximum allowed size for file is '%max%' but '%size%' detected",
        self::TOO_SMALL => "Minimum expected size for file is '%min%' but '%size%' detected",
        self::NOT_FOUND => 'File is not readable or does not exist',
    ];

    /**
     * @var array Error message template variables
     */
    protected $messageVariables = [
        'min'  => ['options' => 'min'],
        'max'  => ['options' => 'max'],
        'size' => 'size',
    ];

    /**
     * Detected size
     *
     * @var int
     */
    protected $size;

    /**
     * Options for this validator
     *
     * @var array
     */
    protected $options = [
        'min'           => null, // Minimum file size, if null there is no minimum
        'max'           => null, // Maximum file size, if null there is no maximum
        'useByteString' => true, // Use byte string?
    ];

    /**
     * Sets validator options
     *
     * If $options is an integer, it will be used as maximum file size
     * As Array is accepts the following keys:
     * 'min': Minimum file size
     * 'max': Maximum file size
     * 'useByteString': Use bytestring or real size for messages
     *
     * @param  int|array|\Traversable $options Options for the adapter
     */
    public function __construct($options = null)
    {
        if (is_string($options) || is_numeric($options)) {
            $options = ['max' => $options];
        }

        if (1 < func_num_args()) {
            $argv = func_get_args();
            array_shift($argv);
            $options['max'] = array_shift($argv);
            if (! empty($argv)) {
                $options['useByteString'] = array_shift($argv);
            }
        }

        parent::__construct($options);
    }

    /**
     * Should messages return bytes as integer or as string in SI notation
     *
     * @param  bool $byteString Use bytestring ?
     * @return int
     */
    public function useByteString($byteString = true)
    {
        $this->options['useByteString'] = (bool) $byteString;
        return $this;
    }

    /**
     * Will bytestring be used?
     *
     * @return bool
     */
    public function getByteString()
    {
        return $this->options['useByteString'];
    }

    /**
     * Returns the minimum file size
     *
     * @param  bool $raw Whether or not to force return of the raw value (defaults off)
     * @return int|string
     */
    public function getMin($raw = false)
    {
        $min = $this->options['min'];
        if (! $raw && $this->getByteString()) {
            $min = $this->toByteString($min);
        }

        return $min;
    }

    /**
     * Sets the minimum file size
     *
     * File size can be an integer or a byte string
     * This includes 'B', 'kB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'
     * For example: 2000, 2MB, 0.2GB
     *
     * @param  int|string $min The minimum file size
     * @throws Exception\InvalidArgumentException When min is greater than max
     * @return $this Provides a fluent interface
     */
    public function setMin($min)
    {
        if (! is_string($min) && ! is_numeric($min)) {
            throw new Exception\InvalidArgumentException('Invalid options to validator provided');
        }

        $min = (int) $this->fromByteString($min);
        $max = $this->getMax(true);
        if (($max !== null) && ($min > $max)) {
            throw new Exception\InvalidArgumentException(
                "The minimum must be less than or equal to the maximum file size, but $min > $max"
            );
        }

        $this->options['min'] = $min;
        return $this;
    }

    /**
     * Returns the maximum file size
     *
     * @param  bool $raw Whether or not to force return of the raw value (defaults off)
     * @return int|string
     */
    public function getMax($raw = false)
    {
        $max = $this->options['max'];
        if (! $raw && $this->getByteString()) {
            $max = $this->toByteString($max);
        }

        return $max;
    }

    /**
     * Sets the maximum file size
     *
     * File size can be an integer or a byte string
     * This includes 'B', 'kB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'
     * For example: 2000, 2MB, 0.2GB
     *
     * @param  int|string $max The maximum file size
     * @throws Exception\InvalidArgumentException When max is smaller than min
     * @return $this Provides a fluent interface
     */
    public function setMax($max)
    {
        if (! is_string($max) && ! is_numeric($max)) {
            throw new Exception\InvalidArgumentException('Invalid options to validator provided');
        }

        $max = (int) $this->fromByteString($max);
        $min = $this->getMin(true);
        if (($min !== null) && ($max < $min)) {
            throw new Exception\InvalidArgumentException(
                "The maximum must be greater than or equal to the minimum file size, but $max < $min"
            );
        }

        $this->options['max'] = $max;
        return $this;
    }

    /**
     * Retrieve current detected file size
     *
     * @return int
     */
    protected function getSize()
    {
        return $this->size;
    }

    /**
     * Set current size
     *
     * @param  int $size
     * @return $this
     */
    protected function setSize($size)
    {
        $this->size = $size;
        return $this;
    }

    /**
     * Returns true if and only if the file size of $value is at least min and
     * not bigger than max (when max is not null).
     *
     * @param  string|array $value File to check for size
     * @param  array        $file  File data from \Laminas\File\Transfer\Transfer (optional)
     * @return bool
     */
    public function isValid($value, $file = null)
    {
        $fileInfo = $this->getFileInfo($value, $file);

        $this->setValue($fileInfo['filename']);

        // Is file readable ?
        if (empty($fileInfo['file']) || false === is_readable($fileInfo['file'])) {
            $this->error(self::NOT_FOUND);
            return false;
        }

        // limited to 4GB files
        ErrorHandler::start();
        $size = sprintf('%u', filesize($fileInfo['file']));
        ErrorHandler::stop();
        $this->size = $size;

        // Check to see if it's smaller than min size
        $min = $this->getMin(true);
        $max = $this->getMax(true);
        if (($min !== null) && ($size < $min)) {
            if ($this->getByteString()) {
                $this->options['min'] = $this->toByteString($min);
                $this->size           = $this->toByteString($size);
                $this->error(self::TOO_SMALL);
                $this->options['min'] = $min;
                $this->size           = $size;
            } else {
                $this->error(self::TOO_SMALL);
            }
        }

        // Check to see if it's larger than max size
        if (($max !== null) && ($max < $size)) {
            if ($this->getByteString()) {
                $this->options['max'] = $this->toByteString($max);
                $this->size           = $this->toByteString($size);
                $this->error(self::TOO_BIG);
                $this->options['max'] = $max;
                $this->size           = $size;
            } else {
                $this->error(self::TOO_BIG);
            }
        }

        if ($this->getMessages()) {
            return false;
        }

        return true;
    }

    /**
     * Returns the formatted size
     *
     * @param  int $size
     * @return string
     */
    protected function toByteString($size)
    {
        $sizes = ['B', 'kB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
        for ($i = 0; $size >= 1024 && $i < 9; $i++) {
            $size /= 1024;
        }

        return round($size, 2) . $sizes[$i];
    }

    /**
     * Returns the unformatted size
     *
     * @param  string $size
     * @return int
     */
    protected function fromByteString($size)
    {
        if (is_numeric($size)) {
            return (int) $size;
        }

        $type  = trim(substr($size, -2, 1));

        $value = substr($size, 0, -1);
        if (! is_numeric($value)) {
            $value = trim(substr($value, 0, -1));
        }

        switch (strtoupper($type)) {
            case 'Y':
                $value *= 1024 * 1024 * 1024 * 1024 * 1024 * 1024 * 1024 * 1024;
                break;
            case 'Z':
                $value *= 1024 * 1024 * 1024 * 1024 * 1024 * 1024 * 1024;
                break;
            case 'E':
                $value *= 1024 * 1024 * 1024 * 1024 * 1024 * 1024;
                break;
            case 'P':
                $value *= 1024 * 1024 * 1024 * 1024 * 1024;
                break;
            case 'T':
                $value *= 1024 * 1024 * 1024 * 1024;
                break;
            case 'G':
                $value *= 1024 * 1024 * 1024;
                break;
            case 'M':
                $value *= 1024 * 1024;
                break;
            case 'K':
                $value *= 1024;
                break;
            default:
                break;
        }

        return $value;
    }
}
laminas-validator/src/File/ExcludeExtension.php000064400000004545147361032560015637 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-validator for the canonical source repository
 * @copyright https://github.com/laminas/laminas-validator/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-validator/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Validator\File;

/**
 * Validator for the excluding file extensions
 */
class ExcludeExtension extends Extension
{
    use FileInformationTrait;

    /**
     * @const string Error constants
     */
    const FALSE_EXTENSION = 'fileExcludeExtensionFalse';
    const NOT_FOUND       = 'fileExcludeExtensionNotFound';

    /**
     * @var array Error message templates
     */
    protected $messageTemplates = [
        self::FALSE_EXTENSION => 'File has an incorrect extension',
        self::NOT_FOUND       => 'File is not readable or does not exist',
    ];

    /**
     * Returns true if and only if the file extension of $value is not included in the
     * set extension list
     *
     * @param  string|array $value Real file to check for extension
     * @param  array        $file  File data from \Laminas\File\Transfer\Transfer (optional)
     * @return bool
     */
    public function isValid($value, $file = null)
    {
        $fileInfo = $this->getFileInfo($value, $file);

        // Is file readable ?
        if (! $this->getAllowNonExistentFile()
            && (empty($fileInfo['file']) || false === is_readable($fileInfo['file']))
        ) {
            if (preg_match('/nofile\.mo$/', $fileInfo['file'])) {
            }
            $this->error(self::NOT_FOUND);
            return false;
        }

        $this->setValue($fileInfo['filename']);

        $extension  = substr($fileInfo['filename'], strrpos($fileInfo['filename'], '.') + 1);
        $extensions = $this->getExtension();

        if ($this->getCase() && (! in_array($extension, $extensions))) {
            return true;
        } elseif (! $this->getCase()) {
            foreach ($extensions as $ext) {
                if (strtolower($ext) == strtolower($extension)) {
                    if (preg_match('/nofile\.mo$/', $fileInfo['file'])) {
                    }
                    $this->error(self::FALSE_EXTENSION);
                    return false;
                }
            }

            return true;
        }

        $this->error(self::FALSE_EXTENSION);
        return false;
    }
}
laminas-validator/src/File/FilesSize.php000064400000013261147361032560014241 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-validator for the canonical source repository
 * @copyright https://github.com/laminas/laminas-validator/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-validator/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Validator\File;

use Laminas\Stdlib\ArrayUtils;
use Laminas\Stdlib\ErrorHandler;
use Laminas\Validator\Exception;
use Traversable;

/**
 * Validator for the size of all files which will be validated in sum
 *
 */
class FilesSize extends Size
{
    /**
     * @const string Error constants
     */
    const TOO_BIG      = 'fileFilesSizeTooBig';
    const TOO_SMALL    = 'fileFilesSizeTooSmall';
    const NOT_READABLE = 'fileFilesSizeNotReadable';

    /**
     * @var array Error message templates
     */
    protected $messageTemplates = [
        self::TOO_BIG      => "All files in sum should have a maximum size of '%max%' but '%size%' were detected",
        self::TOO_SMALL    => "All files in sum should have a minimum size of '%min%' but '%size%' were detected",
        self::NOT_READABLE => 'One or more files can not be read',
    ];

    /**
     * Internal file array
     *
     * @var array
     */
    protected $files;

    /**
     * Sets validator options
     *
     * Min limits the used disk space for all files, when used with max=null it is the maximum file size
     * It also accepts an array with the keys 'min' and 'max'
     *
     * @param  int|array|Traversable $options Options for this validator
     * @throws \Laminas\Validator\Exception\InvalidArgumentException
     */
    public function __construct($options = null)
    {
        $this->files = [];
        $this->setSize(0);

        if ($options instanceof Traversable) {
            $options = ArrayUtils::iteratorToArray($options);
        } elseif (is_scalar($options)) {
            $options = ['max' => $options];
        } elseif (! is_array($options)) {
            throw new Exception\InvalidArgumentException('Invalid options to validator provided');
        }

        if (1 < func_num_args()) {
            $argv = func_get_args();
            array_shift($argv);
            $options['max'] = array_shift($argv);
            if (! empty($argv)) {
                $options['useByteString'] = array_shift($argv);
            }
        }

        parent::__construct($options);
    }

    /**
     * Returns true if and only if the disk usage of all files is at least min and
     * not bigger than max (when max is not null).
     *
     * @param  string|array $value Real file to check for size
     * @param  array        $file  File data from \Laminas\File\Transfer\Transfer
     * @return bool
     */
    public function isValid($value, $file = null)
    {
        if (is_string($value)) {
            $value = [$value];
        } elseif (is_array($value) && isset($value['tmp_name'])) {
            $value = [$value];
        }

        $min  = $this->getMin(true);
        $max  = $this->getMax(true);
        $size = $this->getSize();
        foreach ($value as $files) {
            if (is_array($files)) {
                if (! isset($files['tmp_name']) || ! isset($files['name'])) {
                    throw new Exception\InvalidArgumentException(
                        'Value array must be in $_FILES format'
                    );
                }
                $file  = $files;
                $files = $files['tmp_name'];
            }

            // Is file readable ?
            if (empty($files) || false === is_readable($files)) {
                $this->throwError($file, self::NOT_READABLE);
                continue;
            }

            if (! isset($this->files[$files])) {
                $this->files[$files] = $files;
            } else {
                // file already counted... do not count twice
                continue;
            }

            // limited to 2GB files
            ErrorHandler::start();
            $size += filesize($files);
            ErrorHandler::stop();
            $this->size = $size;
            if (($max !== null) && ($max < $size)) {
                if ($this->getByteString()) {
                    $this->options['max'] = $this->toByteString($max);
                    $this->size           = $this->toByteString($size);
                    $this->throwError($file, self::TOO_BIG);
                    $this->options['max'] = $max;
                    $this->size           = $size;
                } else {
                    $this->throwError($file, self::TOO_BIG);
                }
            }
        }

        // Check that aggregate files are >= minimum size
        if (($min !== null) && ($size < $min)) {
            if ($this->getByteString()) {
                $this->options['min'] = $this->toByteString($min);
                $this->size           = $this->toByteString($size);
                $this->throwError($file, self::TOO_SMALL);
                $this->options['min'] = $min;
                $this->size           = $size;
            } else {
                $this->throwError($file, self::TOO_SMALL);
            }
        }

        if ($this->getMessages()) {
            return false;
        }

        return true;
    }

    /**
     * Throws an error of the given type
     *
     * @param  string $file
     * @param  string $errorType
     * @return false
     */
    protected function throwError($file, $errorType)
    {
        if ($file !== null) {
            if (is_array($file)) {
                if (array_key_exists('name', $file)) {
                    $this->value = $file['name'];
                }
            } elseif (is_string($file)) {
                $this->value = $file;
            }
        }

        $this->error($errorType);
        return false;
    }
}
laminas-validator/src/File/FileInformationTrait.php000064400000011320147361032560016427 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-validator for the canonical source repository
 * @copyright https://github.com/laminas/laminas-validator/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-validator/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Validator\File;

use Laminas\Validator\Exception;
use Psr\Http\Message\UploadedFileInterface;

trait FileInformationTrait
{
    /**
     * Returns array if the procedure is identified
     *
     * @param  string|array|object $value    Filename to check
     * @param  null|array          $file     File data (when using legacy Laminas_File_Transfer API)
     * @param  bool                $hasType  Return with filetype (optional)
     * @param  bool                $basename Return with basename - is calculated from location path (optional)
     * @return array
     */
    protected function getFileInfo(
        $value,
        array $file = null,
        $hasType = false,
        $hasBasename = false
    ) {
        if (is_string($value) && is_array($file)) {
            return $this->getLegacyFileInfo($file, $hasType, $hasBasename);
        }

        if (is_array($value)) {
            return $this->getSapiFileInfo($value, $hasType, $hasBasename);
        }

        if ($value instanceof UploadedFileInterface) {
            return $this->getPsr7FileInfo($value, $hasType, $hasBasename);
        }

        return $this->getFileBasedFileInfo($value, $hasType, $hasBasename);
    }

    /**
     * Generate file information array with legacy Laminas_File_Transfer API
     *
     * @param array  $file        File data
     * @param bool   $hasType     Return with filetype
     * @param bool   $hasBasename Basename is calculated from location path
     * @return array
     */
    private function getLegacyFileInfo(
        array $file,
        $hasType = false,
        $hasBasename = false
    ) {
        $fileInfo = [];

        $fileInfo['filename'] = $file['name'];
        $fileInfo['file']     = $file['tmp_name'];

        if ($hasBasename) {
            $fileInfo['basename'] = basename($fileInfo['file']);
        }

        if ($hasType) {
            $fileInfo['filetype'] = $file['type'];
        }

        return $fileInfo;
    }

    /**
     * Generate file information array with SAPI
     *
     * @param array $file        File data from SAPI
     * @param bool  $hasType     Return with filetype
     * @param bool  $hasBasename Filename is calculated from location path
     * @return array
     */
    private function getSapiFileInfo(
        array $file,
        $hasType = false,
        $hasBasename = false
    ) {
        if (! isset($file['tmp_name']) || ! isset($file['name'])) {
            throw new Exception\InvalidArgumentException(
                'Value array must be in $_FILES format'
            );
        }

        $fileInfo = [];

        $fileInfo['file']     = $file['tmp_name'];
        $fileInfo['filename'] = $file['name'];

        if ($hasBasename) {
            $fileInfo['basename'] = basename($fileInfo['file']);
        }

        if ($hasType) {
            $fileInfo['filetype'] = $file['type'];
        }

        return $fileInfo;
    }

    /**
     * Generate file information array with PSR-7 UploadedFileInterface
     *
     * @param UploadedFileInterface $file
     * @param bool                  $hasType     Return with filetype
     * @param bool                  $hasBasename Filename is calculated from location path
     * @return array
     */
    private function getPsr7FileInfo(
        UploadedFileInterface $file,
        $hasType = false,
        $hasBasename = false
    ) {
        $fileInfo = [];

        $fileInfo['file']     = $file->getStream()->getMetadata('uri');
        $fileInfo['filename'] = $file->getClientFilename();

        if ($hasBasename) {
            $fileInfo['basename'] = basename($fileInfo['file']);
        }

        if ($hasType) {
            $fileInfo['filetype'] = $file->getClientMediaType();
        }

        return $fileInfo;
    }

    /**
     * Generate file information array with base method
     *
     * @param string $file        File path
     * @param bool   $hasType     Return with filetype
     * @param bool   $hasBasename Filename is calculated from location path
     * @return array
     */
    private function getFileBasedFileInfo(
        $file,
        $hasType = false,
        $hasBasename = false
    ) {
        $fileInfo = [];

        $fileInfo['file']     = $file;
        $fileInfo['filename'] = basename($fileInfo['file']);

        if ($hasBasename) {
            $fileInfo['basename'] = basename($fileInfo['file']);
        }

        if ($hasType) {
            $fileInfo['filetype'] = null;
        }

        return $fileInfo;
    }
}
laminas-validator/src/File/NotExists.php000064400000003746147361032560014313 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-validator for the canonical source repository
 * @copyright https://github.com/laminas/laminas-validator/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-validator/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Validator\File;

/**
 * Validator which checks if the destination file does not exist
 */
class NotExists extends Exists
{
    use FileInformationTrait;

    /**
     * @const string Error constants
     */
    const DOES_EXIST = 'fileNotExistsDoesExist';

    /**
     * @var array Error message templates
     */
    protected $messageTemplates = [
        self::DOES_EXIST => 'File exists',
    ];

    /**
     * Returns true if and only if the file does not exist in the set destinations
     *
     * @param  string|array $value Real file to check for existence
     * @param  array        $file  File data from \Laminas\File\Transfer\Transfer (optional)
     * @return bool
     */
    public function isValid($value, $file = null)
    {
        $fileInfo = $this->getFileInfo($value, $file, false, true);

        $this->setValue($fileInfo['filename']);

        $check = false;
        $directories = $this->getDirectory(true);
        if (! isset($directories)) {
            $check = true;
            if (file_exists($fileInfo['file'])) {
                $this->error(self::DOES_EXIST);
                return false;
            }
        } else {
            foreach ($directories as $directory) {
                if (! isset($directory) || '' === $directory) {
                    continue;
                }

                $check = true;
                if (file_exists($directory . DIRECTORY_SEPARATOR . $fileInfo['basename'])) {
                    $this->error(self::DOES_EXIST);
                    return false;
                }
            }
        }

        if (! $check) {
            $this->error(self::DOES_EXIST);
            return false;
        }

        return true;
    }
}
laminas-validator/src/File/ImageSize.php000064400000024673147361032560014232 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-validator for the canonical source repository
 * @copyright https://github.com/laminas/laminas-validator/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-validator/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Validator\File;

use Laminas\Stdlib\ErrorHandler;
use Laminas\Validator\AbstractValidator;
use Laminas\Validator\Exception;

/**
 * Validator for the image size of an image file
 */
class ImageSize extends AbstractValidator
{
    use FileInformationTrait;

    /**
     * @const string Error constants
     */
    const WIDTH_TOO_BIG    = 'fileImageSizeWidthTooBig';
    const WIDTH_TOO_SMALL  = 'fileImageSizeWidthTooSmall';
    const HEIGHT_TOO_BIG   = 'fileImageSizeHeightTooBig';
    const HEIGHT_TOO_SMALL = 'fileImageSizeHeightTooSmall';
    const NOT_DETECTED     = 'fileImageSizeNotDetected';
    const NOT_READABLE     = 'fileImageSizeNotReadable';

    /**
     * @var array Error message template
     */
    protected $messageTemplates = [
        self::WIDTH_TOO_BIG    => "Maximum allowed width for image should be '%maxwidth%' but '%width%' detected",
        self::WIDTH_TOO_SMALL  => "Minimum expected width for image should be '%minwidth%' but '%width%' detected",
        self::HEIGHT_TOO_BIG   => "Maximum allowed height for image should be '%maxheight%' but '%height%' detected",
        self::HEIGHT_TOO_SMALL => "Minimum expected height for image should be '%minheight%' but '%height%' detected",
        self::NOT_DETECTED     => 'The size of image could not be detected',
        self::NOT_READABLE     => 'File is not readable or does not exist',
    ];

    /**
     * @var array Error message template variables
     */
    protected $messageVariables = [
        'minwidth'  => ['options' => 'minWidth'],
        'maxwidth'  => ['options' => 'maxWidth'],
        'minheight' => ['options' => 'minHeight'],
        'maxheight' => ['options' => 'maxHeight'],
        'width'     => 'width',
        'height'    => 'height',
    ];

    /**
     * Detected width
     *
     * @var int
     */
    protected $width;

    /**
     * Detected height
     *
     * @var int
     */
    protected $height;

    /**
     * Options for this validator
     *
     * @var array
     */
    protected $options = [
        'minWidth'  => null,  // Minimum image width
        'maxWidth'  => null,  // Maximum image width
        'minHeight' => null,  // Minimum image height
        'maxHeight' => null,  // Maximum image height
    ];

    /**
     * Sets validator options
     *
     * Accepts the following option keys:
     * - minheight
     * - minwidth
     * - maxheight
     * - maxwidth
     *
     * @param  array|\Traversable $options
     */
    public function __construct($options = null)
    {
        if (1 < func_num_args()) {
            if (! is_array($options)) {
                $options = ['minWidth' => $options];
            }

            $argv = func_get_args();
            array_shift($argv);
            $options['minHeight'] = array_shift($argv);
            if (! empty($argv)) {
                $options['maxWidth'] = array_shift($argv);
                if (! empty($argv)) {
                    $options['maxHeight'] = array_shift($argv);
                }
            }
        }

        parent::__construct($options);
    }

    /**
     * Returns the minimum allowed width
     *
     * @return int
     */
    public function getMinWidth()
    {
        return $this->options['minWidth'];
    }

    /**
     * Sets the minimum allowed width
     *
     * @param  int $minWidth
     * @throws Exception\InvalidArgumentException When minwidth is greater than maxwidth
     * @return $this Provides a fluid interface
     */
    public function setMinWidth($minWidth)
    {
        if (($this->getMaxWidth() !== null) && ($minWidth > $this->getMaxWidth())) {
            throw new Exception\InvalidArgumentException(
                'The minimum image width must be less than or equal to the '
                . " maximum image width, but {$minWidth} > {$this->getMaxWidth()}"
            );
        }

        $this->options['minWidth']  = (int) $minWidth;
        return $this;
    }

    /**
     * Returns the maximum allowed width
     *
     * @return int
     */
    public function getMaxWidth()
    {
        return $this->options['maxWidth'];
    }

    /**
     * Sets the maximum allowed width
     *
     * @param  int $maxWidth
     * @throws Exception\InvalidArgumentException When maxwidth is less than minwidth
     * @return $this Provides a fluid interface
     */
    public function setMaxWidth($maxWidth)
    {
        if (($this->getMinWidth() !== null) && ($maxWidth < $this->getMinWidth())) {
            throw new Exception\InvalidArgumentException(
                'The maximum image width must be greater than or equal to the '
                . "minimum image width, but {$maxWidth} < {$this->getMinWidth()}"
            );
        }

        $this->options['maxWidth']  = (int) $maxWidth;
        return $this;
    }

    /**
     * Returns the minimum allowed height
     *
     * @return int
     */
    public function getMinHeight()
    {
        return $this->options['minHeight'];
    }

    /**
     * Sets the minimum allowed height
     *
     * @param  int $minHeight
     * @throws Exception\InvalidArgumentException When minheight is greater than maxheight
     * @return $this Provides a fluid interface
     */
    public function setMinHeight($minHeight)
    {
        if (($this->getMaxHeight() !== null) && ($minHeight > $this->getMaxHeight())) {
            throw new Exception\InvalidArgumentException(
                'The minimum image height must be less than or equal to the '
                . " maximum image height, but {$minHeight} > {$this->getMaxHeight()}"
            );
        }

        $this->options['minHeight']  = (int) $minHeight;
        return $this;
    }

    /**
     * Returns the maximum allowed height
     *
     * @return int
     */
    public function getMaxHeight()
    {
        return $this->options['maxHeight'];
    }

    /**
     * Sets the maximum allowed height
     *
     * @param  int $maxHeight
     * @throws Exception\InvalidArgumentException When maxheight is less than minheight
     * @return $this Provides a fluid interface
     */
    public function setMaxHeight($maxHeight)
    {
        if (($this->getMinHeight() !== null) && ($maxHeight < $this->getMinHeight())) {
            throw new Exception\InvalidArgumentException(
                'The maximum image height must be greater than or equal to the '
                . "minimum image height, but {$maxHeight} < {$this->getMinHeight()}"
            );
        }

        $this->options['maxHeight']  = (int) $maxHeight;
        return $this;
    }

    /**
     * Returns the set minimum image sizes
     *
     * @return array
     */
    public function getImageMin()
    {
        return ['minWidth' => $this->getMinWidth(), 'minHeight' => $this->getMinHeight()];
    }

    /**
     * Returns the set maximum image sizes
     *
     * @return array
     */
    public function getImageMax()
    {
        return ['maxWidth' => $this->getMaxWidth(), 'maxHeight' => $this->getMaxHeight()];
    }

    /**
     * Returns the set image width sizes
     *
     * @return array
     */
    public function getImageWidth()
    {
        return ['minWidth' => $this->getMinWidth(), 'maxWidth' => $this->getMaxWidth()];
    }

    /**
     * Returns the set image height sizes
     *
     * @return array
     */
    public function getImageHeight()
    {
        return ['minHeight' => $this->getMinHeight(), 'maxHeight' => $this->getMaxHeight()];
    }

    /**
     * Sets the minimum image size
     *
     * @param  array $options                 The minimum image dimensions
     * @return $this Provides a fluent interface
     */
    public function setImageMin($options)
    {
        $this->setOptions($options);
        return $this;
    }

    /**
     * Sets the maximum image size
     *
     * @param  array|\Traversable $options The maximum image dimensions
     * @return $this Provides a fluent interface
     */
    public function setImageMax($options)
    {
        $this->setOptions($options);
        return $this;
    }

    /**
     * Sets the minimum and maximum image width
     *
     * @param  array $options               The image width dimensions
     * @return $this Provides a fluent interface
     */
    public function setImageWidth($options)
    {
        $this->setImageMin($options);
        $this->setImageMax($options);

        return $this;
    }

    /**
     * Sets the minimum and maximum image height
     *
     * @param  array $options               The image height dimensions
     * @return $this Provides a fluent interface
     */
    public function setImageHeight($options)
    {
        $this->setImageMin($options);
        $this->setImageMax($options);

        return $this;
    }

    /**
     * Returns true if and only if the image size of $value is at least min and
     * not bigger than max
     *
     * @param  string|array $value Real file to check for image size
     * @param  array        $file  File data from \Laminas\File\Transfer\Transfer (optional)
     * @return bool
     */
    public function isValid($value, $file = null)
    {
        $fileInfo = $this->getFileInfo($value, $file);

        $this->setValue($fileInfo['filename']);

        // Is file readable ?
        if (empty($fileInfo['file']) || false === is_readable($fileInfo['file'])) {
            $this->error(self::NOT_READABLE);
            return false;
        }

        ErrorHandler::start();
        $size = getimagesize($fileInfo['file']);
        ErrorHandler::stop();

        if (empty($size) || ($size[0] === 0) || ($size[1] === 0)) {
            $this->error(self::NOT_DETECTED);
            return false;
        }

        $this->width  = $size[0];
        $this->height = $size[1];
        if ($this->width < $this->getMinWidth()) {
            $this->error(self::WIDTH_TOO_SMALL);
        }

        if (($this->getMaxWidth() !== null) && ($this->getMaxWidth() < $this->width)) {
            $this->error(self::WIDTH_TOO_BIG);
        }

        if ($this->height < $this->getMinHeight()) {
            $this->error(self::HEIGHT_TOO_SMALL);
        }

        if (($this->getMaxHeight() !== null) && ($this->getMaxHeight() < $this->height)) {
            $this->error(self::HEIGHT_TOO_BIG);
        }

        if ($this->getMessages()) {
            return false;
        }

        return true;
    }
}
laminas-validator/src/File/Exists.php000064400000011662147361032560013626 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-validator for the canonical source repository
 * @copyright https://github.com/laminas/laminas-validator/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-validator/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Validator\File;

use Laminas\Validator\AbstractValidator;
use Laminas\Validator\Exception;

/**
 * Validator which checks if the file already exists in the directory
 */
class Exists extends AbstractValidator
{
    use FileInformationTrait;

    /**
     * @const string Error constants
     */
    const DOES_NOT_EXIST = 'fileExistsDoesNotExist';

    /**
     * @var array Error message templates
     */
    protected $messageTemplates = [
        self::DOES_NOT_EXIST => 'File does not exist',
    ];

    /**
     * Options for this validator
     *
     * @var array
     */
    protected $options = [
        'directory' => null,  // internal list of directories
    ];

    /**
     * @var array Error message template variables
     */
    protected $messageVariables = [
        'directory' => ['options' => 'directory'],
    ];

    /**
     * Sets validator options
     *
     * @param  string|array|\Traversable $options
     */
    public function __construct($options = null)
    {
        if (is_string($options)) {
            $options = explode(',', $options);
        }

        if (is_array($options) && ! array_key_exists('directory', $options)) {
            $options = ['directory' => $options];
        }

        parent::__construct($options);
    }

    /**
     * Returns the set file directories which are checked
     *
     * @param  bool $asArray Returns the values as array; when false, a concatenated string is returned
     * @return string|null
     */
    public function getDirectory($asArray = false)
    {
        $asArray   = (bool) $asArray;
        $directory = $this->options['directory'];
        if ($asArray && isset($directory)) {
            $directory = explode(',', (string) $directory);
        }

        return $directory;
    }

    /**
     * Sets the file directory which will be checked
     *
     * @param  string|array $directory The directories to validate
     * @return Extension Provides a fluent interface
     */
    public function setDirectory($directory)
    {
        $this->options['directory'] = null;
        $this->addDirectory($directory);
        return $this;
    }

    /**
     * Adds the file directory which will be checked
     *
     * @param  string|array $directory The directory to add for validation
     * @return Extension Provides a fluent interface
     * @throws Exception\InvalidArgumentException
     */
    public function addDirectory($directory)
    {
        $directories = $this->getDirectory(true);
        if (! isset($directories)) {
            $directories = [];
        }

        if (is_string($directory)) {
            $directory = explode(',', $directory);
        } elseif (! is_array($directory)) {
            throw new Exception\InvalidArgumentException('Invalid options to validator provided');
        }

        foreach ($directory as $content) {
            if (empty($content) || ! is_string($content)) {
                continue;
            }

            $directories[] = trim($content);
        }
        $directories = array_unique($directories);

        // Sanity check to ensure no empty values
        foreach ($directories as $key => $dir) {
            if (empty($dir)) {
                unset($directories[$key]);
            }
        }

        $this->options['directory'] = ! empty($directory)
            ? implode(',', $directories) : null;

        return $this;
    }

    /**
     * Returns true if and only if the file already exists in the set directories
     *
     * @param  string|array $value Real file to check for existence
     * @param  array        $file  File data from \Laminas\File\Transfer\Transfer (optional)
     * @return bool
     */
    public function isValid($value, $file = null)
    {
        $fileInfo = $this->getFileInfo($value, $file, false, true);

        $this->setValue($fileInfo['filename']);

        $check = false;
        $directories = $this->getDirectory(true);
        if (! isset($directories)) {
            $check = true;
            if (! file_exists($fileInfo['file'])) {
                $this->error(self::DOES_NOT_EXIST);
                return false;
            }
        } else {
            foreach ($directories as $directory) {
                if (! isset($directory) || '' === $directory) {
                    continue;
                }

                $check = true;
                if (! file_exists($directory . DIRECTORY_SEPARATOR . $fileInfo['basename'])) {
                    $this->error(self::DOES_NOT_EXIST);
                    return false;
                }
            }
        }

        if (! $check) {
            $this->error(self::DOES_NOT_EXIST);
            return false;
        }

        return true;
    }
}
laminas-validator/src/File/Upload.php000064400000021417147361032560013572 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-validator for the canonical source repository
 * @copyright https://github.com/laminas/laminas-validator/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-validator/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Validator\File;

use Countable;
use Laminas\Validator\AbstractValidator;
use Laminas\Validator\Exception;
use Psr\Http\Message\UploadedFileInterface;

/**
 * Validator for the maximum size of a file up to a max of 2GB
 *
 */
class Upload extends AbstractValidator
{
    /**
     * @const string Error constants
     */
    const INI_SIZE       = 'fileUploadErrorIniSize';
    const FORM_SIZE      = 'fileUploadErrorFormSize';
    const PARTIAL        = 'fileUploadErrorPartial';
    const NO_FILE        = 'fileUploadErrorNoFile';
    const NO_TMP_DIR     = 'fileUploadErrorNoTmpDir';
    const CANT_WRITE     = 'fileUploadErrorCantWrite';
    const EXTENSION      = 'fileUploadErrorExtension';
    const ATTACK         = 'fileUploadErrorAttack';
    const FILE_NOT_FOUND = 'fileUploadErrorFileNotFound';
    const UNKNOWN        = 'fileUploadErrorUnknown';

    /**
     * @var array Error message templates
     */
    protected $messageTemplates = [
        self::INI_SIZE       => "File '%value%' exceeds upload_max_filesize directive in php.ini",
        self::FORM_SIZE      => "File '%value%' exceeds the MAX_FILE_SIZE directive that was "
            . 'specified in the HTML form',
        self::PARTIAL        => "File '%value%' was only partially uploaded",
        self::NO_FILE        => "File '%value%' was not uploaded",
        self::NO_TMP_DIR     => "Missing a temporary folder to store '%value%'",
        self::CANT_WRITE     => "Failed to write file '%value%' to disk",
        self::EXTENSION      => "A PHP extension stopped uploading the file '%value%'",
        self::ATTACK         => "File '%value%' was illegally uploaded. This could be a possible attack",
        self::FILE_NOT_FOUND => "File '%value%' was not found",
        self::UNKNOWN        => "Unknown error while uploading file '%value%'",
    ];

    protected $options = [
        'files' => [],
    ];

    /**
     * Sets validator options
     *
     * The array $files must be given in syntax of Laminas\File\Transfer\Transfer to be checked
     * If no files are given the $_FILES array will be used automatically.
     * NOTE: This validator will only work with HTTP POST uploads!
     *
     * @param  array|\Traversable $options Array of files in syntax of \Laminas\File\Transfer\Transfer
     */
    public function __construct($options = [])
    {
        if (is_array($options) && ! array_key_exists('files', $options)) {
            $options = ['files' => $options];
        }

        parent::__construct($options);
    }

    /**
     * Returns the array of set files
     *
     * @param  string $file (Optional) The file to return in detail
     * @return array
     * @throws Exception\InvalidArgumentException If file is not found
     */
    public function getFiles($file = null)
    {
        if ($file !== null) {
            $return = [];
            foreach ($this->options['files'] as $name => $content) {
                if ($name === $file) {
                    $return[$file] = $this->options['files'][$name];
                }

                if ($content instanceof UploadedFileInterface) {
                    if ($content->getClientFilename() === $file) {
                        $return[$name] = $this->options['files'][$name];
                    }
                } elseif ($content['name'] === $file) {
                    $return[$name] = $this->options['files'][$name];
                }
            }

            if (! $return) {
                throw new Exception\InvalidArgumentException("The file '$file' was not found");
            }

            return $return;
        }

        return $this->options['files'];
    }

    /**
     * Sets the files to be checked
     *
     * @param  array $files The files to check in syntax of \Laminas\File\Transfer\Transfer
     * @return $this Provides a fluent interface
     */
    public function setFiles($files = [])
    {
        if (null === $files
            || ((is_array($files) || $files instanceof Countable)
                && count($files) === 0)
        ) {
            $this->options['files'] = $_FILES;
        } else {
            $this->options['files'] = $files;
        }

        if ($this->options['files'] === null) {
            $this->options['files'] = [];
        }

        foreach ($this->options['files'] as $file => $content) {
            if (! $content instanceof UploadedFileInterface
                && ! isset($content['error'])
            ) {
                unset($this->options['files'][$file]);
            }
        }

        return $this;
    }

    /**
     * Returns true if and only if the file was uploaded without errors
     *
     * @param  string $value Single file to check for upload errors, when giving null the $_FILES array
     *                       from initialization will be used
     * @param  mixed  $file
     * @return bool
     */
    public function isValid($value, $file = null)
    {
        $files = [];
        $this->setValue($value);
        if (array_key_exists($value, $this->getFiles())) {
            $files = array_merge($files, $this->getFiles($value));
        } else {
            foreach ($this->getFiles() as $file => $content) {
                if ($content instanceof UploadedFileInterface) {
                    if ($content->getClientFilename() === $value) {
                        $files = array_merge($files, $this->getFiles($file));
                    }

                    // PSR cannot search by tmp_name because it does not have
                    // a public interface to get it, only user defined name
                    // from form field.
                    continue;
                }

                if (isset($content['name']) && ($content['name'] === $value)) {
                    $files = array_merge($files, $this->getFiles($file));
                }

                if (isset($content['tmp_name']) && ($content['tmp_name'] === $value)) {
                    $files = array_merge($files, $this->getFiles($file));
                }
            }
        }

        if (empty($files)) {
            return $this->throwError($file, self::FILE_NOT_FOUND);
        }

        foreach ($files as $file => $content) {
            $this->value = $file;
            $error = $content instanceof UploadedFileInterface
                ? $content->getError()
                : $content['error'];

            switch ($error) {
                case 0:
                    if ($content instanceof UploadedFileInterface) {
                        // done!
                        break;
                    }

                    // For standard SAPI environments, check that the upload
                    // was valid
                    if (! is_uploaded_file($content['tmp_name'])) {
                        $this->throwError($content, self::ATTACK);
                    }
                    break;

                case 1:
                    $this->throwError($content, self::INI_SIZE);
                    break;

                case 2:
                    $this->throwError($content, self::FORM_SIZE);
                    break;

                case 3:
                    $this->throwError($content, self::PARTIAL);
                    break;

                case 4:
                    $this->throwError($content, self::NO_FILE);
                    break;

                case 6:
                    $this->throwError($content, self::NO_TMP_DIR);
                    break;

                case 7:
                    $this->throwError($content, self::CANT_WRITE);
                    break;

                case 8:
                    $this->throwError($content, self::EXTENSION);
                    break;

                default:
                    $this->throwError($content, self::UNKNOWN);
                    break;
            }
        }

        if ($this->getMessages()) {
            return false;
        }

        return true;
    }

    /**
     * Throws an error of the given type
     *
     * @param  array|string|UploadedFileInterface $file
     * @param  string $errorType
     * @return false
     */
    protected function throwError($file, $errorType)
    {
        if ($file !== null) {
            if (is_array($file)) {
                if (array_key_exists('name', $file)) {
                    $this->value = $file['name'];
                }
            } elseif (is_string($file)) {
                $this->value = $file;
            } elseif ($file instanceof UploadedFileInterface) {
                $this->value = $file->getClientFilename();
            }
        }

        $this->error($errorType);
        return false;
    }
}
laminas-validator/src/File/Count.php000064400000015427147361032560013442 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-validator for the canonical source repository
 * @copyright https://github.com/laminas/laminas-validator/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-validator/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Validator\File;

use Laminas\Validator\AbstractValidator;
use Laminas\Validator\Exception;

/**
 * Validator for counting all given files
 *
 */
class Count extends AbstractValidator
{
    /**#@+
     * @const string Error constants
     */
    const TOO_MANY = 'fileCountTooMany';
    const TOO_FEW  = 'fileCountTooFew';
    /**#@-*/

    /**
     * @var array Error message templates
     */
    protected $messageTemplates = [
        self::TOO_MANY => "Too many files, maximum '%max%' are allowed but '%count%' are given",
        self::TOO_FEW  => "Too few files, minimum '%min%' are expected but '%count%' are given",
    ];

    /**
     * @var array Error message template variables
     */
    protected $messageVariables = [
        'min'   => ['options' => 'min'],
        'max'   => ['options' => 'max'],
        'count' => 'count',
    ];

    /**
     * Actual filecount
     *
     * @var int
     */
    protected $count;

    /**
     * Internal file array
     * @var array
     */
    protected $files;

    /**
     * Options for this validator
     *
     * @var array
     */
    protected $options = [
        'min' => null,  // Minimum file count, if null there is no minimum file count
        'max' => null,  // Maximum file count, if null there is no maximum file count
    ];

    /**
     * Sets validator options
     *
     * Min limits the file count, when used with max=null it is the maximum file count
     * It also accepts an array with the keys 'min' and 'max'
     *
     * If $options is an integer, it will be used as maximum file count
     * As Array is accepts the following keys:
     * 'min': Minimum filecount
     * 'max': Maximum filecount
     *
     * @param  int|array|\Traversable $options Options for the adapter
     */
    public function __construct($options = null)
    {
        if (1 < func_num_args()) {
            $args = func_get_args();
            $options = [
                'min' => array_shift($args),
                'max' => array_shift($args),
            ];
        }

        if (is_string($options) || is_numeric($options)) {
            $options = ['max' => $options];
        }

        parent::__construct($options);
    }

    /**
     * Returns the minimum file count
     *
     * @return int
     */
    public function getMin()
    {
        return $this->options['min'];
    }

    /**
     * Sets the minimum file count
     *
     * @param  int|array $min The minimum file count
     * @return $this Provides a fluent interface
     * @throws Exception\InvalidArgumentException When min is greater than max
     */
    public function setMin($min)
    {
        if (is_array($min) && isset($min['min'])) {
            $min = $min['min'];
        }

        if (! is_numeric($min)) {
            throw new Exception\InvalidArgumentException('Invalid options to validator provided');
        }

        $min = (int) $min;
        if (($this->getMax() !== null) && ($min > $this->getMax())) {
            throw new Exception\InvalidArgumentException(
                "The minimum must be less than or equal to the maximum file count, but {$min} > {$this->getMax()}"
            );
        }

        $this->options['min'] = $min;
        return $this;
    }

    /**
     * Returns the maximum file count
     *
     * @return int
     */
    public function getMax()
    {
        return $this->options['max'];
    }

    /**
     * Sets the maximum file count
     *
     * @param  int|array $max The maximum file count
     * @return $this Provides a fluent interface
     * @throws Exception\InvalidArgumentException When max is smaller than min
     */
    public function setMax($max)
    {
        if (is_array($max) && isset($max['max'])) {
            $max = $max['max'];
        }

        if (! is_numeric($max)) {
            throw new Exception\InvalidArgumentException('Invalid options to validator provided');
        }

        $max = (int) $max;
        if (($this->getMin() !== null) && ($max < $this->getMin())) {
            throw new Exception\InvalidArgumentException(
                "The maximum must be greater than or equal to the minimum file count, but {$max} < {$this->getMin()}"
            );
        }

        $this->options['max'] = $max;
        return $this;
    }

    /**
     * Adds a file for validation
     *
     * @param string|array $file
     * @return $this
     */
    public function addFile($file)
    {
        if (is_string($file)) {
            $file = [$file];
        }

        if (is_array($file)) {
            foreach ($file as $name) {
                if (! isset($this->files[$name]) && ! empty($name)) {
                    $this->files[$name] = $name;
                }
            }
        }

        return $this;
    }

    /**
     * Returns true if and only if the file count of all checked files is at least min and
     * not bigger than max (when max is not null). Attention: When checking with set min you
     * must give all files with the first call, otherwise you will get a false.
     *
     * @param  string|array $value Filenames to check for count
     * @param  array        $file  File data from \Laminas\File\Transfer\Transfer
     * @return bool
     */
    public function isValid($value, $file = null)
    {
        if (($file !== null) && ! array_key_exists('destination', $file)) {
            $file['destination'] = dirname($value);
        }

        if (($file !== null) && array_key_exists('tmp_name', $file)) {
            $value = $file['destination'] . DIRECTORY_SEPARATOR . $file['name'];
        }

        if (($file === null) || ! empty($file['tmp_name'])) {
            $this->addFile($value);
        }

        $this->count = count($this->files);
        if (($this->getMax() !== null) && ($this->count > $this->getMax())) {
            return $this->throwError($file, self::TOO_MANY);
        }

        if (($this->getMin() !== null) && ($this->count < $this->getMin())) {
            return $this->throwError($file, self::TOO_FEW);
        }

        return true;
    }

    /**
     * Throws an error of the given type
     *
     * @param  string $file
     * @param  string $errorType
     * @return false
     */
    protected function throwError($file, $errorType)
    {
        if ($file !== null) {
            if (is_array($file)) {
                if (array_key_exists('name', $file)) {
                    $this->value = $file['name'];
                }
            } elseif (is_string($file)) {
                $this->value = $file;
            }
        }

        $this->error($errorType);
        return false;
    }
}
laminas-validator/src/File/Sha1.php000064400000005540147361032560013141 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-validator for the canonical source repository
 * @copyright https://github.com/laminas/laminas-validator/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-validator/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Validator\File;

/**
 * Validator for the sha1 hash of given files
 */
class Sha1 extends Hash
{
    use FileInformationTrait;

    /**
     * @const string Error constants
     */
    const DOES_NOT_MATCH = 'fileSha1DoesNotMatch';
    const NOT_DETECTED   = 'fileSha1NotDetected';
    const NOT_FOUND      = 'fileSha1NotFound';

    /**
     * @var array Error message templates
     */
    protected $messageTemplates = [
        self::DOES_NOT_MATCH => 'File does not match the given sha1 hashes',
        self::NOT_DETECTED   => 'A sha1 hash could not be evaluated for the given file',
        self::NOT_FOUND      => 'File is not readable or does not exist',
    ];

    /**
     * Options for this validator
     *
     * @var string
     */
    protected $options = [
        'algorithm' => 'sha1',
        'hash'      => null,
    ];

    /**
     * Returns all set sha1 hashes
     *
     * @return array
     */
    public function getSha1()
    {
        return $this->getHash();
    }

    /**
     * Sets the sha1 hash for one or multiple files
     *
     * @param  string|array $options
     * @return Hash Provides a fluent interface
     */
    public function setSha1($options)
    {
        $this->setHash($options);
        return $this;
    }

    /**
     * Adds the sha1 hash for one or multiple files
     *
     * @param  string|array $options
     * @return Hash Provides a fluent interface
     */
    public function addSha1($options)
    {
        $this->addHash($options);
        return $this;
    }

    /**
     * Returns true if and only if the given file confirms the set hash
     *
     * @param  string $value|array Filename to check for hash
     * @param  array        $file  File data from \Laminas\File\Transfer\Transfer (optional)
     * @return bool
     */
    public function isValid($value, $file = null)
    {
        $fileInfo = $this->getFileInfo($value, $file);

        $this->setValue($fileInfo['filename']);

        // Is file readable ?
        if (empty($fileInfo['file']) || false === is_readable($fileInfo['file'])) {
            $this->error(self::NOT_FOUND);
            return false;
        }

        $hashes   = array_unique(array_keys($this->getHash()));
        $filehash = hash_file('sha1', $fileInfo['file']);
        if ($filehash === false) {
            $this->error(self::NOT_DETECTED);
            return false;
        }

        foreach ($hashes as $hash) {
            if ($filehash === $hash) {
                return true;
            }
        }

        $this->error(self::DOES_NOT_MATCH);
        return false;
    }
}
laminas-validator/src/File/WordCount.php000064400000013252147361032560014270 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-validator for the canonical source repository
 * @copyright https://github.com/laminas/laminas-validator/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-validator/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Validator\File;

use Laminas\Validator\AbstractValidator;
use Laminas\Validator\Exception;

/**
 * Validator for counting all words in a file
 */
class WordCount extends AbstractValidator
{
    use FileInformationTrait;

    /**
     * @const string Error constants
     */
    const TOO_MUCH  = 'fileWordCountTooMuch';
    const TOO_LESS  = 'fileWordCountTooLess';
    const NOT_FOUND = 'fileWordCountNotFound';

    /**
     * @var array Error message templates
     */
    protected $messageTemplates = [
        self::TOO_MUCH  => "Too many words, maximum '%max%' are allowed but '%count%' were counted",
        self::TOO_LESS  => "Too few words, minimum '%min%' are expected but '%count%' were counted",
        self::NOT_FOUND => 'File is not readable or does not exist',
    ];

    /**
     * @var array Error message template variables
     */
    protected $messageVariables = [
        'min'   => ['options' => 'min'],
        'max'   => ['options' => 'max'],
        'count' => 'count',
    ];

    /**
     * Word count
     *
     * @var int
     */
    protected $count;

    /**
     * Options for this validator
     *
     * @var array
     */
    protected $options = [
        'min' => null,  // Minimum word count, if null there is no minimum word count
        'max' => null,  // Maximum word count, if null there is no maximum word count
    ];

    /**
     * Sets validator options
     *
     * Min limits the word count, when used with max=null it is the maximum word count
     * It also accepts an array with the keys 'min' and 'max'
     *
     * If $options is an integer, it will be used as maximum word count
     * As Array is accepts the following keys:
     * 'min': Minimum word count
     * 'max': Maximum word count
     *
     * @param  int|array|\Traversable $options Options for the adapter
     */
    public function __construct($options = null)
    {
        if (1 < func_num_args()) {
            $args    = func_get_args();
            $options = [
                'min' => array_shift($args),
                'max' => array_shift($args),
            ];
        }

        if (is_string($options) || is_numeric($options)) {
            $options = ['max' => $options];
        }

        parent::__construct($options);
    }

    /**
     * Returns the minimum word count
     *
     * @return int
     */
    public function getMin()
    {
        return $this->options['min'];
    }

    /**
     * Sets the minimum word count
     *
     * @param  int|array $min The minimum word count
     * @throws Exception\InvalidArgumentException When min is greater than max
     * @return $this Provides a fluent interface
     */
    public function setMin($min)
    {
        if (is_array($min) and isset($min['min'])) {
            $min = $min['min'];
        }

        if (! is_numeric($min)) {
            throw new Exception\InvalidArgumentException('Invalid options to validator provided');
        }

        $min = (int) $min;
        if (($this->getMax() !== null) && ($min > $this->getMax())) {
            throw new Exception\InvalidArgumentException(
                "The minimum must be less than or equal to the maximum word count, but $min > {$this->getMax()}"
            );
        }

        $this->options['min'] = $min;
        return $this;
    }

    /**
     * Returns the maximum word count
     *
     * @return int
     */
    public function getMax()
    {
        return $this->options['max'];
    }

    /**
     * Sets the maximum file count
     *
     * @param  int|array $max The maximum word count
     * @throws Exception\InvalidArgumentException When max is smaller than min
     * @return $this Provides a fluent interface
     */
    public function setMax($max)
    {
        if (is_array($max) and isset($max['max'])) {
            $max = $max['max'];
        }

        if (! is_numeric($max)) {
            throw new Exception\InvalidArgumentException('Invalid options to validator provided');
        }

        $max = (int) $max;
        if (($this->getMin() !== null) && ($max < $this->getMin())) {
            throw new Exception\InvalidArgumentException(
                "The maximum must be greater than or equal to the minimum word count, but $max < {$this->getMin()}"
            );
        }

        $this->options['max'] = $max;
        return $this;
    }

    /**
     * Returns true if and only if the counted words are at least min and
     * not bigger than max (when max is not null).
     *
     * @param  string|array $value Filename to check for word count
     * @param  array        $file  File data from \Laminas\File\Transfer\Transfer (optional)
     * @return bool
     */
    public function isValid($value, $file = null)
    {
        $fileInfo = $this->getFileInfo($value, $file);

        $this->setValue($fileInfo['filename']);

        // Is file readable ?
        if (empty($fileInfo['file']) || false === is_readable($fileInfo['file'])) {
            $this->error(self::NOT_FOUND);
            return false;
        }

        $content     = file_get_contents($fileInfo['file']);
        $this->count = str_word_count($content);
        if (($this->getMax() !== null) && ($this->count > $this->getMax())) {
            $this->error(self::TOO_MUCH);
            return false;
        }

        if (($this->getMin() !== null) && ($this->count < $this->getMin())) {
            $this->error(self::TOO_LESS);
            return false;
        }

        return true;
    }
}
laminas-validator/src/Isbn.php000064400000011617147361032560012363 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-validator for the canonical source repository
 * @copyright https://github.com/laminas/laminas-validator/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-validator/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Validator;

class Isbn extends AbstractValidator
{
    const AUTO    = 'auto';
    const ISBN10  = '10';
    const ISBN13  = '13';
    const INVALID = 'isbnInvalid';
    const NO_ISBN = 'isbnNoIsbn';

    /**
     * Validation failure message template definitions.
     *
     * @var array
     */
    protected $messageTemplates = [
        self::INVALID => 'Invalid type given. String or integer expected',
        self::NO_ISBN => 'The input is not a valid ISBN number',
    ];

    protected $options = [
        'type'      => self::AUTO, // Allowed type
        'separator' => '',         // Separator character
    ];

    /**
     * Detect input format.
     *
     * @return string
     */
    protected function detectFormat()
    {
        // prepare separator and pattern list
        $sep      = quotemeta($this->getSeparator());
        $patterns = [];
        $lengths  = [];
        $type     = $this->getType();

        // check for ISBN-10
        if ($type == self::ISBN10 || $type == self::AUTO) {
            if (empty($sep)) {
                $pattern = '/^[0-9]{9}[0-9X]{1}$/';
                $length  = 10;
            } else {
                $pattern = "/^[0-9]{1,7}[{$sep}]{1}[0-9]{1,7}[{$sep}]{1}[0-9]{1,7}[{$sep}]{1}[0-9X]{1}$/";
                $length  = 13;
            }

            $patterns[$pattern] = self::ISBN10;
            $lengths[$pattern]  = $length;
        }

        // check for ISBN-13
        if ($type == self::ISBN13 || $type == self::AUTO) {
            if (empty($sep)) {
                $pattern = '/^[0-9]{13}$/';
                $length  = 13;
            } else {
                // @codingStandardsIgnoreStart
                $pattern = "/^[0-9]{1,9}[{$sep}]{1}[0-9]{1,5}[{$sep}]{1}[0-9]{1,9}[{$sep}]{1}[0-9]{1,9}[{$sep}]{1}[0-9]{1}$/";
                // @codingStandardsIgnoreEnd
                $length  = 17;
            }

            $patterns[$pattern] = self::ISBN13;
            $lengths[$pattern]  = $length;
        }

        // check pattern list
        foreach ($patterns as $pattern => $type) {
            if ((strlen($this->getValue()) == $lengths[$pattern]) && preg_match($pattern, $this->getValue())) {
                return $type;
            }
        }

        return;
    }

    /**
     * Returns true if and only if $value is a valid ISBN.
     *
     * @param  string $value
     * @return bool
     */
    public function isValid($value)
    {
        if (! is_string($value) && ! is_int($value)) {
            $this->error(self::INVALID);
            return false;
        }

        $value = (string) $value;
        $this->setValue($value);

        switch ($this->detectFormat()) {
            case self::ISBN10:
                $isbn = new Isbn\Isbn10();
                break;

            case self::ISBN13:
                $isbn = new Isbn\Isbn13();
                break;

            default:
                $this->error(self::NO_ISBN);
                return false;
        }

        $value = str_replace($this->getSeparator(), '', $value);
        $checksum = $isbn->getChecksum($value);

        // validate
        if (substr($this->getValue(), -1) != $checksum) {
            $this->error(self::NO_ISBN);
            return false;
        }
        return true;
    }

    /**
     * Set separator characters.
     *
     * It is allowed only empty string, hyphen and space.
     *
     * @param  string $separator
     * @throws Exception\InvalidArgumentException When $separator is not valid
     * @return $this Provides a fluent interface
     */
    public function setSeparator($separator)
    {
        // check separator
        if (! in_array($separator, ['-', ' ', ''])) {
            throw new Exception\InvalidArgumentException('Invalid ISBN separator.');
        }

        $this->options['separator'] = $separator;
        return $this;
    }

    /**
     * Get separator characters.
     *
     * @return string
     */
    public function getSeparator()
    {
        return $this->options['separator'];
    }

    /**
     * Set allowed ISBN type.
     *
     * @param  string $type
     * @throws Exception\InvalidArgumentException When $type is not valid
     * @return $this Provides a fluent interface
     */
    public function setType($type)
    {
        // check type
        if (! in_array($type, [self::AUTO, self::ISBN10, self::ISBN13])) {
            throw new Exception\InvalidArgumentException('Invalid ISBN type');
        }

        $this->options['type'] = $type;
        return $this;
    }

    /**
     * Get allowed ISBN type.
     *
     * @return string
     */
    public function getType()
    {
        return $this->options['type'];
    }
}
laminas-validator/src/Explode.php000064400000012376147361032560013073 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-validator for the canonical source repository
 * @copyright https://github.com/laminas/laminas-validator/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-validator/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Validator;

use Laminas\ServiceManager\ServiceManager;
use Laminas\Stdlib\ArrayUtils;
use Traversable;

class Explode extends AbstractValidator implements ValidatorPluginManagerAwareInterface
{
    const INVALID = 'explodeInvalid';

    protected $pluginManager;

    /**
     * @var array
     */
    protected $messageTemplates = [
        self::INVALID => 'Invalid type given',
    ];

    /**
     * @var array
     */
    protected $messageVariables = [];

    /**
     * @var string
     */
    protected $valueDelimiter = ',';

    /**
     * @var ValidatorInterface
     */
    protected $validator;

    /**
     * @var bool
     */
    protected $breakOnFirstFailure = false;

    /**
     * Sets the delimiter string that the values will be split upon
     *
     * @param string $delimiter
     * @return $this
     */
    public function setValueDelimiter($delimiter)
    {
        $this->valueDelimiter = $delimiter;
        return $this;
    }

    /**
     * Returns the delimiter string that the values will be split upon
     *
     * @return string
     */
    public function getValueDelimiter()
    {
        return $this->valueDelimiter;
    }

    /**
     * Set validator plugin manager
     *
     * @param ValidatorPluginManager $pluginManager
     */
    public function setValidatorPluginManager(ValidatorPluginManager $pluginManager)
    {
        $this->pluginManager = $pluginManager;
    }

    /**
     * Get validator plugin manager
     *
     * @return ValidatorPluginManager
     */
    public function getValidatorPluginManager()
    {
        if (! $this->pluginManager) {
            $this->setValidatorPluginManager(new ValidatorPluginManager(new ServiceManager));
        }

        return $this->pluginManager;
    }

    /**
     * Sets the Validator for validating each value
     *
     * @param ValidatorInterface|array $validator
     * @throws Exception\RuntimeException
     * @return $this
     */
    public function setValidator($validator)
    {
        if (is_array($validator)) {
            if (! isset($validator['name'])) {
                throw new Exception\RuntimeException(
                    'Invalid validator specification provided; does not include "name" key'
                );
            }
            $name = $validator['name'];
            $options = isset($validator['options']) ? $validator['options'] : [];
            $validator = $this->getValidatorPluginManager()->get($name, $options);
        }

        if (! $validator instanceof ValidatorInterface) {
            throw new Exception\RuntimeException(
                'Invalid validator given'
            );
        }

        $this->validator = $validator;
        return $this;
    }

    /**
     * Gets the Validator for validating each value
     *
     * @return ValidatorInterface
     */
    public function getValidator()
    {
        return $this->validator;
    }

    /**
     * Set break on first failure setting
     *
     * @param  bool $break
     * @return $this
     */
    public function setBreakOnFirstFailure($break)
    {
        $this->breakOnFirstFailure = (bool) $break;
        return $this;
    }

    /**
     * Get break on first failure setting
     *
     * @return bool
     */
    public function isBreakOnFirstFailure()
    {
        return $this->breakOnFirstFailure;
    }

    /**
     * Defined by Laminas\Validator\ValidatorInterface
     *
     * Returns true if all values validate true
     *
     * @param  mixed $value
     * @param  mixed $context Extra "context" to provide the composed validator
     * @return bool
     * @throws Exception\RuntimeException
     */
    public function isValid($value, $context = null)
    {
        $this->setValue($value);

        if ($value instanceof Traversable) {
            $value = ArrayUtils::iteratorToArray($value);
        }

        if (is_array($value)) {
            $values = $value;
        } elseif (is_string($value)) {
            $delimiter = $this->getValueDelimiter();
            // Skip explode if delimiter is null,
            // used when value is expected to be either an
            // array when multiple values and a string for
            // single values (ie. MultiCheckbox form behavior)
            $values = null !== $delimiter
                      ? explode($this->valueDelimiter, $value)
                      : [$value];
        } else {
            $values = [$value];
        }

        $validator = $this->getValidator();

        if (! $validator) {
            throw new Exception\RuntimeException(sprintf(
                '%s expects a validator to be set; none given',
                __METHOD__
            ));
        }

        foreach ($values as $value) {
            if (! $validator->isValid($value, $context)) {
                $this->abstractOptions['messages'][] = $validator->getMessages();

                if ($this->isBreakOnFirstFailure()) {
                    return false;
                }
            }
        }

        return ! $this->abstractOptions['messages'];
    }
}
laminas-validator/src/GpsPoint.php000064400000006644147361032560013237 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-validator for the canonical source repository
 * @copyright https://github.com/laminas/laminas-validator/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-validator/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Validator;

final class GpsPoint extends AbstractValidator
{

    const OUT_OF_BOUNDS = 'gpsPointOutOfBounds';
    const CONVERT_ERROR = 'gpsPointConvertError';
    const INCOMPLETE_COORDINATE = 'gpsPointIncompleteCoordinate';

    /**
     * @var array
     */
    protected $messageTemplates = [
        'gpsPointOutOfBounds' => '%value% is out of Bounds.',
        'gpsPointConvertError' => '%value% can not converted into a Decimal Degree Value.',
        'gpsPointIncompleteCoordinate' => '%value% did not provided a complete Coordinate',
    ];

    /**
     * Returns true if and only if $value meets the validation requirements
     *
     * If $value fails validation, then this method returns false, and
     * getMessages() will return an array of messages that explain why the
     * validation failed.
     *
     * @param  mixed $value
     * @return bool
     * @throws Exception\RuntimeException If validation of $value is impossible
     */
    public function isValid($value)
    {
        if (strpos($value, ',') === false) {
            $this->error(GpsPoint::INCOMPLETE_COORDINATE, $value);
            return false;
        }

        list($lat, $long) = explode(',', $value);

        if ($this->isValidCoordinate($lat, 90.0000) && $this->isValidCoordinate($long, 180.000)) {
            return true;
        }

        return false;
    }

    /**
     * @param string $value
     * @param $maxBoundary
     * @return bool
     */
    private function isValidCoordinate($value, $maxBoundary)
    {
        $this->value = $value;

        $value = $this->removeWhiteSpace($value);
        if ($this->isDMSValue($value)) {
            $value = $this->convertValue($value);
        } else {
            $value = $this->removeDegreeSign($value);
        }

        if ($value === false || $value === null) {
            $this->error(self::CONVERT_ERROR);
            return false;
        }

        $doubleLatitude = (double)$value;

        if ($doubleLatitude <= $maxBoundary && $doubleLatitude >= $maxBoundary * -1) {
            return true;
        }

        $this->error(self::OUT_OF_BOUNDS);
        return false;
    }

    /**
     * Determines if the give value is a Degrees Minutes Second Definition
     *
     * @param $value
     * @return bool
     */
    private function isDMSValue($value)
    {
        return preg_match('/([°\'"]+[NESW])/', $value) > 0;
    }

    /**
     * @param string $value
     * @return bool|string
     */
    private function convertValue($value)
    {
        $matches = [];
        $result = preg_match_all('/(\d{1,3})°(\d{1,2})\'(\d{1,2}[\.\d]{0,6})"[NESW]/i', $value, $matches);

        if ($result === false || $result === 0) {
            return false;
        }

        return $matches[1][0] + $matches[2][0] / 60 + ((double)$matches[3][0]) / 3600;
    }

    /**
     * @param string $value
     * @return string
     */
    private function removeWhiteSpace($value)
    {
        return preg_replace('/\s/', '', $value);
    }

    /**
     * @param string $value
     * @return string
     */
    private function removeDegreeSign($value)
    {
        return str_replace('°', '', $value);
    }
}
laminas-validator/src/ValidatorInterface.php000064400000002367147361032560015240 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-validator for the canonical source repository
 * @copyright https://github.com/laminas/laminas-validator/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-validator/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Validator;

interface ValidatorInterface
{
    /**
     * Returns true if and only if $value meets the validation requirements
     *
     * If $value fails validation, then this method returns false, and
     * getMessages() will return an array of messages that explain why the
     * validation failed.
     *
     * @param  mixed $value
     * @return bool
     * @throws Exception\RuntimeException If validation of $value is impossible
     */
    public function isValid($value);

    /**
     * Returns an array of messages that explain why the most recent isValid()
     * call returned false. The array keys are validation failure message identifiers,
     * and the array values are the corresponding human-readable message strings.
     *
     * If isValid() was never called or if the most recent isValid() call
     * returned true, then this method returns an empty array.
     *
     * @return array
     */
    public function getMessages();
}
laminas-validator/src/Iban.php000064400000022254147361032560012340 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-validator for the canonical source repository
 * @copyright https://github.com/laminas/laminas-validator/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-validator/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Validator;

use Laminas\Stdlib\ArrayUtils;
use Traversable;

/**
 * Validates IBAN Numbers (International Bank Account Numbers)
 */
class Iban extends AbstractValidator
{
    const NOTSUPPORTED     = 'ibanNotSupported';
    const SEPANOTSUPPORTED = 'ibanSepaNotSupported';
    const FALSEFORMAT      = 'ibanFalseFormat';
    const CHECKFAILED      = 'ibanCheckFailed';

    /**
     * Validation failure message template definitions
     *
     * @var array
     */
    protected $messageTemplates = [
        self::NOTSUPPORTED     => 'Unknown country within the IBAN',
        self::SEPANOTSUPPORTED => 'Countries outside the Single Euro Payments Area (SEPA) are not supported',
        self::FALSEFORMAT      => 'The input has a false IBAN format',
        self::CHECKFAILED      => 'The input has failed the IBAN check',
    ];

    /**
     * Optional country code by ISO 3166-1
     *
     * @var string|null
     */
    protected $countryCode;

    /**
     * Optionally allow IBAN codes from non-SEPA countries. Defaults to true
     *
     * @var bool
     */
    protected $allowNonSepa = true;

    /**
     * The SEPA country codes
     *
     * @var array<ISO 3166-1>
     */
    protected static $sepaCountries = [
        'AT', 'BE', 'BG', 'CY', 'CZ', 'DK', 'FO', 'GL', 'EE', 'FI', 'FR', 'DE',
        'GI', 'GR', 'HU', 'IS', 'IE', 'IT', 'LV', 'LI', 'LT', 'LU', 'MT', 'MC',
        'NL', 'NO', 'PL', 'PT', 'RO', 'SK', 'SI', 'ES', 'SE', 'CH', 'GB', 'SM',
        'HR',
    ];

    /**
     * IBAN regexes by country code
     *
     * @var array
     */
    protected static $ibanRegex = [
        'AD' => 'AD[0-9]{2}[0-9]{4}[0-9]{4}[A-Z0-9]{12}',
        'AE' => 'AE[0-9]{2}[0-9]{3}[0-9]{16}',
        'AL' => 'AL[0-9]{2}[0-9]{8}[A-Z0-9]{16}',
        'AT' => 'AT[0-9]{2}[0-9]{5}[0-9]{11}',
        'AZ' => 'AZ[0-9]{2}[A-Z]{4}[A-Z0-9]{20}',
        'BA' => 'BA[0-9]{2}[0-9]{3}[0-9]{3}[0-9]{8}[0-9]{2}',
        'BE' => 'BE[0-9]{2}[0-9]{3}[0-9]{7}[0-9]{2}',
        'BG' => 'BG[0-9]{2}[A-Z]{4}[0-9]{4}[0-9]{2}[A-Z0-9]{8}',
        'BH' => 'BH[0-9]{2}[A-Z]{4}[A-Z0-9]{14}',
        'BR' => 'BR[0-9]{2}[0-9]{8}[0-9]{5}[0-9]{10}[A-Z][A-Z0-9]',
        'BY' => 'BY[0-9]{2}[A-Z0-9]{4}[0-9]{4}[A-Z0-9]{16}',
        'CH' => 'CH[0-9]{2}[0-9]{5}[A-Z0-9]{12}',
        'CR' => 'CR[0-9]{2}[0-9]{3}[0-9]{14}',
        'CY' => 'CY[0-9]{2}[0-9]{3}[0-9]{5}[A-Z0-9]{16}',
        'CZ' => 'CZ[0-9]{2}[0-9]{20}',
        'DE' => 'DE[0-9]{2}[0-9]{8}[0-9]{10}',
        'DO' => 'DO[0-9]{2}[A-Z0-9]{4}[0-9]{20}',
        'DK' => 'DK[0-9]{2}[0-9]{14}',
        'EE' => 'EE[0-9]{2}[0-9]{2}[0-9]{2}[0-9]{11}[0-9]{1}',
        'ES' => 'ES[0-9]{2}[0-9]{4}[0-9]{4}[0-9]{1}[0-9]{1}[0-9]{10}',
        'FI' => 'FI[0-9]{2}[0-9]{6}[0-9]{7}[0-9]{1}',
        'FO' => 'FO[0-9]{2}[0-9]{4}[0-9]{9}[0-9]{1}',
        'FR' => 'FR[0-9]{2}[0-9]{5}[0-9]{5}[A-Z0-9]{11}[0-9]{2}',
        'GB' => 'GB[0-9]{2}[A-Z]{4}[0-9]{6}[0-9]{8}',
        'GE' => 'GE[0-9]{2}[A-Z]{2}[0-9]{16}',
        'GI' => 'GI[0-9]{2}[A-Z]{4}[A-Z0-9]{15}',
        'GL' => 'GL[0-9]{2}[0-9]{4}[0-9]{9}[0-9]{1}',
        'GR' => 'GR[0-9]{2}[0-9]{3}[0-9]{4}[A-Z0-9]{16}',
        'GT' => 'GT[0-9]{2}[A-Z0-9]{4}[A-Z0-9]{20}',
        'HR' => 'HR[0-9]{2}[0-9]{7}[0-9]{10}',
        'HU' => 'HU[0-9]{2}[0-9]{3}[0-9]{4}[0-9]{1}[0-9]{15}[0-9]{1}',
        'IE' => 'IE[0-9]{2}[A-Z]{4}[0-9]{6}[0-9]{8}',
        'IL' => 'IL[0-9]{2}[0-9]{3}[0-9]{3}[0-9]{13}',
        'IS' => 'IS[0-9]{2}[0-9]{4}[0-9]{2}[0-9]{6}[0-9]{10}',
        'IT' => 'IT[0-9]{2}[A-Z]{1}[0-9]{5}[0-9]{5}[A-Z0-9]{12}',
        'KW' => 'KW[0-9]{2}[A-Z]{4}[0-9]{22}',
        'KZ' => 'KZ[0-9]{2}[0-9]{3}[A-Z0-9]{13}',
        'LB' => 'LB[0-9]{2}[0-9]{4}[A-Z0-9]{20}',
        'LI' => 'LI[0-9]{2}[0-9]{5}[A-Z0-9]{12}',
        'LT' => 'LT[0-9]{2}[0-9]{5}[0-9]{11}',
        'LU' => 'LU[0-9]{2}[0-9]{3}[A-Z0-9]{13}',
        'LV' => 'LV[0-9]{2}[A-Z]{4}[A-Z0-9]{13}',
        'MC' => 'MC[0-9]{2}[0-9]{5}[0-9]{5}[A-Z0-9]{11}[0-9]{2}',
        'MD' => 'MD[0-9]{2}[A-Z0-9]{20}',
        'ME' => 'ME[0-9]{2}[0-9]{3}[0-9]{13}[0-9]{2}',
        'MK' => 'MK[0-9]{2}[0-9]{3}[A-Z0-9]{10}[0-9]{2}',
        'MR' => 'MR13[0-9]{5}[0-9]{5}[0-9]{11}[0-9]{2}',
        'MT' => 'MT[0-9]{2}[A-Z]{4}[0-9]{5}[A-Z0-9]{18}',
        'MU' => 'MU[0-9]{2}[A-Z]{4}[0-9]{2}[0-9]{2}[0-9]{12}[0-9]{3}[A-Z]{3}',
        'NL' => 'NL[0-9]{2}[A-Z]{4}[0-9]{10}',
        'NO' => 'NO[0-9]{2}[0-9]{4}[0-9]{6}[0-9]{1}',
        'PK' => 'PK[0-9]{2}[A-Z]{4}[A-Z0-9]{16}',
        'PL' => 'PL[0-9]{2}[0-9]{8}[0-9]{16}',
        'PS' => 'PS[0-9]{2}[A-Z]{4}[A-Z0-9]{21}',
        'PT' => 'PT[0-9]{2}[0-9]{4}[0-9]{4}[0-9]{11}[0-9]{2}',
        'RO' => 'RO[0-9]{2}[A-Z]{4}[A-Z0-9]{16}',
        'RS' => 'RS[0-9]{2}[0-9]{3}[0-9]{13}[0-9]{2}',
        'SA' => 'SA[0-9]{2}[0-9]{2}[A-Z0-9]{18}',
        'SE' => 'SE[0-9]{2}[0-9]{3}[0-9]{16}[0-9]{1}',
        'SI' => 'SI[0-9]{2}[0-9]{5}[0-9]{8}[0-9]{2}',
        'SK' => 'SK[0-9]{2}[0-9]{4}[0-9]{6}[0-9]{10}',
        'SM' => 'SM[0-9]{2}[A-Z]{1}[0-9]{5}[0-9]{5}[A-Z0-9]{12}',
        'TN' => 'TN59[0-9]{2}[0-9]{3}[0-9]{13}[0-9]{2}',
        'TR' => 'TR[0-9]{2}[0-9]{5}[A-Z0-9]{1}[A-Z0-9]{16}',
        'VG' => 'VG[0-9]{2}[A-Z]{4}[0-9]{16}',
    ];

    /**
     * Sets validator options
     *
     * @param  array|Traversable $options OPTIONAL
     */
    public function __construct($options = [])
    {
        if ($options instanceof Traversable) {
            $options = ArrayUtils::iteratorToArray($options);
        }

        if (array_key_exists('country_code', $options)) {
            $this->setCountryCode($options['country_code']);
        }

        if (array_key_exists('allow_non_sepa', $options)) {
            $this->setAllowNonSepa($options['allow_non_sepa']);
        }

        parent::__construct($options);
    }

    /**
     * Returns the optional country code by ISO 3166-1
     *
     * @return string|null
     */
    public function getCountryCode()
    {
        return $this->countryCode;
    }

    /**
     * Sets an optional country code by ISO 3166-1
     *
     * @param  string|null $countryCode
     * @return $this provides a fluent interface
     * @throws Exception\InvalidArgumentException
     */
    public function setCountryCode($countryCode = null)
    {
        if ($countryCode !== null) {
            $countryCode = (string) $countryCode;

            if (! isset(static::$ibanRegex[$countryCode])) {
                throw new Exception\InvalidArgumentException(
                    "Country code '{$countryCode}' invalid by ISO 3166-1 or not supported"
                );
            }
        }

        $this->countryCode = $countryCode;
        return $this;
    }

    /**
     * Returns the optional allow non-sepa countries setting
     *
     * @return bool
     */
    public function allowNonSepa()
    {
        return $this->allowNonSepa;
    }

    /**
     * Sets the optional allow non-sepa countries setting
     *
     * @param  bool $allowNonSepa
     * @return $this provides a fluent interface
     */
    public function setAllowNonSepa($allowNonSepa)
    {
        $this->allowNonSepa = (bool) $allowNonSepa;
        return $this;
    }

    /**
     * Returns true if $value is a valid IBAN
     *
     * @param  string $value
     * @return bool
     */
    public function isValid($value)
    {
        if (! is_string($value)) {
            $this->error(self::FALSEFORMAT);
            return false;
        }

        $value = str_replace(' ', '', strtoupper($value));
        $this->setValue($value);

        $countryCode = $this->getCountryCode();
        if ($countryCode === null) {
            $countryCode = substr($value, 0, 2);
        }

        if (! array_key_exists($countryCode, static::$ibanRegex)) {
            $this->setValue($countryCode);
            $this->error(self::NOTSUPPORTED);
            return false;
        }

        if (! $this->allowNonSepa && ! in_array($countryCode, static::$sepaCountries)) {
            $this->setValue($countryCode);
            $this->error(self::SEPANOTSUPPORTED);
            return false;
        }

        if (! preg_match('/^' . static::$ibanRegex[$countryCode] . '$/', $value)) {
            $this->error(self::FALSEFORMAT);
            return false;
        }

        $format = substr($value, 4) . substr($value, 0, 4);
        $format = str_replace(
            ['A',  'B',  'C',  'D',  'E',  'F',  'G',  'H',  'I',  'J',  'K',  'L',  'M',
                  'N',  'O',  'P',  'Q',  'R',  'S',  'T',  'U',  'V',  'W',  'X',  'Y',  'Z'],
            ['10', '11', '12', '13', '14', '15', '16', '17', '18', '19', '20', '21', '22',
                  '23', '24', '25', '26', '27', '28', '29', '30', '31', '32', '33', '34', '35'],
            $format
        );

        $temp = intval(substr($format, 0, 1));
        $len  = strlen($format);
        for ($x = 1; $x < $len; ++$x) {
            $temp *= 10;
            $temp += intval(substr($format, $x, 1));
            $temp %= 97;
        }

        if ($temp != 1) {
            $this->error(self::CHECKFAILED);
            return false;
        }

        return true;
    }
}
laminas-validator/src/Csrf.php000064400000020252147361032560012360 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-validator for the canonical source repository
 * @copyright https://github.com/laminas/laminas-validator/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-validator/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Validator;

use Laminas\Math\Rand;
use Laminas\Session\Container as SessionContainer;
use Laminas\Stdlib\ArrayUtils;
use Traversable;

class Csrf extends AbstractValidator
{
    /**
     * Error codes
     * @const string
     */
    const NOT_SAME = 'notSame';

    /**
     * Error messages
     * @var array
     */
    protected $messageTemplates = [
        self::NOT_SAME => 'The form submitted did not originate from the expected site',
    ];

    /**
     * Actual hash used.
     *
     * @var mixed
     */
    protected $hash;

    /**
     * Static cache of the session names to generated hashes
     * @todo unused, left here to avoid BC breaks
     *
     * @var array
     */
    protected static $hashCache;

    /**
     * Name of CSRF element (used to create non-colliding hashes)
     *
     * @var string
     */
    protected $name = 'csrf';

    /**
     * Salt for CSRF token
     * @var string
     */
    protected $salt = 'salt';

    /**
     * @var SessionContainer
     */
    protected $session;

    /**
     * TTL for CSRF token
     * @var int|null
     */
    protected $timeout = 300;

    /**
     * Constructor
     *
     * @param  array|Traversable $options
     */
    public function __construct($options = [])
    {
        parent::__construct($options);

        if ($options instanceof Traversable) {
            $options = ArrayUtils::iteratorToArray($options);
        }

        if (! is_array($options)) {
            $options = (array) $options;
        }

        foreach ($options as $key => $value) {
            switch (strtolower($key)) {
                case 'name':
                    $this->setName($value);
                    break;
                case 'salt':
                    $this->setSalt($value);
                    break;
                case 'session':
                    $this->setSession($value);
                    break;
                case 'timeout':
                    $this->setTimeout($value);
                    break;
                default:
                    // ignore unknown options
                    break;
            }
        }
    }

    /**
     * Does the provided token match the one generated?
     *
     * @param  string $value
     * @param  mixed $context
     * @return bool
     */
    public function isValid($value, $context = null)
    {
        if (! is_string($value)) {
            return false;
        }

        $this->setValue($value);

        $tokenId = $this->getTokenIdFromHash($value);
        $hash = $this->getValidationToken($tokenId);

        $tokenFromValue = $this->getTokenFromHash($value);
        $tokenFromHash = $this->getTokenFromHash($hash);

        if (! $tokenFromValue || ! $tokenFromHash || ($tokenFromValue !== $tokenFromHash)) {
            $this->error(self::NOT_SAME);
            return false;
        }

        return true;
    }

    /**
     * Set CSRF name
     *
     * @param  string $name
     * @return $this
     */
    public function setName($name)
    {
        $this->name = (string) $name;
        return $this;
    }

    /**
     * Get CSRF name
     *
     * @return string
     */
    public function getName()
    {
        return $this->name;
    }

    /**
     * Set session container
     *
     * @param  SessionContainer $session
     * @return $this
     */
    public function setSession(SessionContainer $session)
    {
        $this->session = $session;
        if ($this->hash) {
            $this->initCsrfToken();
        }
        return $this;
    }

    /**
     * Get session container
     *
     * Instantiate session container if none currently exists
     *
     * @return SessionContainer
     */
    public function getSession()
    {
        if (null === $this->session) {
            // Using fully qualified name, to ensure polyfill class alias is used
            $this->session = new SessionContainer($this->getSessionName());
        }
        return $this->session;
    }

    /**
     * Salt for CSRF token
     *
     * @param  string $salt
     * @return $this
     */
    public function setSalt($salt)
    {
        $this->salt = (string) $salt;
        return $this;
    }

    /**
     * Retrieve salt for CSRF token
     *
     * @return string
     */
    public function getSalt()
    {
        return $this->salt;
    }

    /**
     * Retrieve CSRF token
     *
     * If no CSRF token currently exists, or should be regenerated,
     * generates one.
     *
     * @param  bool $regenerate    default false
     * @return string
     */
    public function getHash($regenerate = false)
    {
        if ((null === $this->hash) || $regenerate) {
            $this->generateHash();
        }
        return $this->hash;
    }

    /**
     * Get session namespace for CSRF token
     *
     * Generates a session namespace based on salt, element name, and class.
     *
     * @return string
     */
    public function getSessionName()
    {
        return str_replace('\\', '_', __CLASS__) . '_'
            . $this->getSalt() . '_'
            . strtr($this->getName(), ['[' => '_', ']' => '']);
    }

    /**
     * Set timeout for CSRF session token
     *
     * @param  int|null $ttl
     * @return $this
     */
    public function setTimeout($ttl)
    {
        $this->timeout = $ttl !== null ? (int) $ttl : null;
        return $this;
    }

    /**
     * Get CSRF session token timeout
     *
     * @return int
     */
    public function getTimeout()
    {
        return $this->timeout;
    }

    /**
     * Initialize CSRF token in session
     *
     * @return void
     */
    protected function initCsrfToken()
    {
        $session = $this->getSession();
        $timeout = $this->getTimeout();
        if (null !== $timeout) {
            $session->setExpirationSeconds($timeout);
        }

        $hash = $this->getHash();
        $token = $this->getTokenFromHash($hash);
        $tokenId = $this->getTokenIdFromHash($hash);

        if (! $session->tokenList) {
            $session->tokenList = [];
        }
        $session->tokenList[$tokenId] = $token;
        $session->hash = $hash; // @todo remove this, left for BC
    }

    /**
     * Generate CSRF token
     *
     * Generates CSRF token and stores both in {@link $hash} and element
     * value.
     *
     * @return void
     */
    protected function generateHash()
    {
        $token = md5($this->getSalt() . Rand::getBytes(32) .  $this->getName());

        $this->hash = $this->formatHash($token, $this->generateTokenId());

        $this->setValue($this->hash);
        $this->initCsrfToken();
    }

    /**
     * @return string
     */
    protected function generateTokenId()
    {
        return md5(Rand::getBytes(32));
    }

    /**
     * Get validation token
     *
     * Retrieve token from session, if it exists.
     *
     * @param string $tokenId
     * @return null|string
     */
    protected function getValidationToken($tokenId = null)
    {
        $session = $this->getSession();

        /**
         * if no tokenId is passed we revert to the old behaviour
         * @todo remove, here for BC
         */
        if (! $tokenId && isset($session->hash)) {
            return $session->hash;
        }

        if ($tokenId && isset($session->tokenList[$tokenId])) {
            return $this->formatHash($session->tokenList[$tokenId], $tokenId);
        }

        return;
    }

    /**
     * @param $token
     * @param $tokenId
     * @return string
     */
    protected function formatHash($token, $tokenId)
    {
        return sprintf('%s-%s', $token, $tokenId);
    }

    /**
     * @param $hash
     * @return string
     */
    protected function getTokenFromHash($hash)
    {
        $data = explode('-', $hash);
        return $data[0] ?: null;
    }

    /**
     * @param $hash
     * @return string
     */
    protected function getTokenIdFromHash($hash)
    {
        $data = explode('-', $hash);

        if (! isset($data[1])) {
            return;
        }

        return $data[1];
    }
}
laminas-validator/src/AbstractValidator.php000064400000040265147361032560015102 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-validator for the canonical source repository
 * @copyright https://github.com/laminas/laminas-validator/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-validator/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Validator;

use Laminas\Stdlib\ArrayUtils;
use Traversable;

abstract class AbstractValidator implements
    Translator\TranslatorAwareInterface,
    ValidatorInterface
{
    /**
     * The value to be validated
     *
     * @var mixed
     */
    protected $value;

    /**
     * Default translation object for all validate objects
     * @var Translator\TranslatorInterface
     */
    protected static $defaultTranslator;

    /**
     * Default text domain to be used with translator
     * @var string
     */
    protected static $defaultTranslatorTextDomain = 'default';

    /**
     * Limits the maximum returned length of an error message
     *
     * @var int
     */
    protected static $messageLength = -1;

    protected $abstractOptions = [
        'messages'             => [], // Array of validation failure messages
        'messageTemplates'     => [], // Array of validation failure message templates
        'messageVariables'     => [], // Array of additional variables available for validation failure messages
        'translator'           => null,    // Translation object to used -> Translator\TranslatorInterface
        'translatorTextDomain' => null,    // Translation text domain
        'translatorEnabled'    => true,    // Is translation enabled?
        'valueObscured'        => false,   // Flag indicating whether or not value should be obfuscated
                                           // in error messages
    ];

    /**
     * Abstract constructor for all validators
     * A validator should accept following parameters:
     *  - nothing f.e. Validator()
     *  - one or multiple scalar values f.e. Validator($first, $second, $third)
     *  - an array f.e. Validator(array($first => 'first', $second => 'second', $third => 'third'))
     *  - an instance of Traversable f.e. Validator($config_instance)
     *
     * @param array|Traversable $options
     */
    public function __construct($options = null)
    {
        // The abstract constructor allows no scalar values
        if ($options instanceof Traversable) {
            $options = ArrayUtils::iteratorToArray($options);
        }

        if (isset($this->messageTemplates)) {
            $this->abstractOptions['messageTemplates'] = $this->messageTemplates;
        }

        if (isset($this->messageVariables)) {
            $this->abstractOptions['messageVariables'] = $this->messageVariables;
        }

        if (is_array($options)) {
            $this->setOptions($options);
        }
    }

    /**
     * Returns an option
     *
     * @param string $option Option to be returned
     * @return mixed Returned option
     * @throws Exception\InvalidArgumentException
     */
    public function getOption($option)
    {
        if (array_key_exists($option, $this->abstractOptions)) {
            return $this->abstractOptions[$option];
        }

        if (isset($this->options) && array_key_exists($option, $this->options)) {
            return $this->options[$option];
        }

        throw new Exception\InvalidArgumentException("Invalid option '$option'");
    }

    /**
     * Returns all available options
     *
     * @return array Array with all available options
     */
    public function getOptions()
    {
        $result = $this->abstractOptions;
        if (isset($this->options)) {
            $result += $this->options;
        }
        return $result;
    }

    /**
     * Sets one or multiple options
     *
     * @param  array|Traversable $options Options to set
     * @throws Exception\InvalidArgumentException If $options is not an array or Traversable
     * @return $this Provides fluid interface
     */
    public function setOptions($options = [])
    {
        if (! is_array($options) && ! $options instanceof Traversable) {
            throw new Exception\InvalidArgumentException(__METHOD__ . ' expects an array or Traversable');
        }

        foreach ($options as $name => $option) {
            $fname = 'set' . ucfirst($name);
            $fname2 = 'is' . ucfirst($name);
            if (($name !== 'setOptions') && method_exists($this, $name)) {
                $this->{$name}($option);
            } elseif (($fname !== 'setOptions') && method_exists($this, $fname)) {
                $this->{$fname}($option);
            } elseif (method_exists($this, $fname2)) {
                $this->{$fname2}($option);
            } elseif (isset($this->options)) {
                $this->options[$name] = $option;
            } else {
                $this->abstractOptions[$name] = $option;
            }
        }

        return $this;
    }

    /**
     * Returns array of validation failure messages
     *
     * @return array
     */
    public function getMessages()
    {
        return array_unique($this->abstractOptions['messages'], SORT_REGULAR);
    }

    /**
     * Invoke as command
     *
     * @param  mixed $value
     * @return bool
     */
    public function __invoke($value)
    {
        return $this->isValid($value);
    }

    /**
     * Returns an array of the names of variables that are used in constructing validation failure messages
     *
     * @return array
     */
    public function getMessageVariables()
    {
        return array_keys($this->abstractOptions['messageVariables']);
    }

    /**
     * Returns the message templates from the validator
     *
     * @return array
     */
    public function getMessageTemplates()
    {
        return $this->abstractOptions['messageTemplates'];
    }

    /**
     * Sets the validation failure message template for a particular key
     *
     * @param  string $messageString
     * @param  string $messageKey     OPTIONAL
     * @return $this Provides a fluent interface
     * @throws Exception\InvalidArgumentException
     */
    public function setMessage($messageString, $messageKey = null)
    {
        if ($messageKey === null) {
            $keys = array_keys($this->abstractOptions['messageTemplates']);
            foreach ($keys as $key) {
                $this->setMessage($messageString, $key);
            }
            return $this;
        }

        if (! isset($this->abstractOptions['messageTemplates'][$messageKey])) {
            throw new Exception\InvalidArgumentException("No message template exists for key '$messageKey'");
        }

        $this->abstractOptions['messageTemplates'][$messageKey] = $messageString;
        return $this;
    }

    /**
     * Sets validation failure message templates given as an array, where the array keys are the message keys,
     * and the array values are the message template strings.
     *
     * @param  array $messages
     * @return $this
     */
    public function setMessages(array $messages)
    {
        foreach ($messages as $key => $message) {
            $this->setMessage($message, $key);
        }
        return $this;
    }

    /**
     * Magic function returns the value of the requested property, if and only if it is the value or a
     * message variable.
     *
     * @param  string $property
     * @return mixed
     * @throws Exception\InvalidArgumentException
     */
    public function __get($property)
    {
        if ($property == 'value') {
            return $this->value;
        }

        if (array_key_exists($property, $this->abstractOptions['messageVariables'])) {
            $result = $this->abstractOptions['messageVariables'][$property];
            if (is_array($result)) {
                return $this->{key($result)}[current($result)];
            }
            return $this->{$result};
        }

        if (isset($this->messageVariables) && array_key_exists($property, $this->messageVariables)) {
            $result = $this->{$this->messageVariables[$property]};
            if (is_array($result)) {
                return $this->{key($result)}[current($result)];
            }
            return $this->{$result};
        }

        throw new Exception\InvalidArgumentException("No property exists by the name '$property'");
    }

    /**
     * Constructs and returns a validation failure message with the given message key and value.
     *
     * Returns null if and only if $messageKey does not correspond to an existing template.
     *
     * If a translator is available and a translation exists for $messageKey,
     * the translation will be used.
     *
     * @param  string              $messageKey
     * @param  string|array|object $value
     * @return string
     */
    protected function createMessage($messageKey, $value)
    {
        if (! isset($this->abstractOptions['messageTemplates'][$messageKey])) {
            return;
        }

        $message = $this->abstractOptions['messageTemplates'][$messageKey];

        $message = $this->translateMessage($messageKey, $message);

        if (is_object($value) &&
            ! in_array('__toString', get_class_methods($value))
        ) {
            $value = get_class($value) . ' object';
        } elseif (is_array($value)) {
            $value = var_export($value, 1);
        } else {
            $value = (string) $value;
        }

        if ($this->isValueObscured()) {
            $value = str_repeat('*', strlen($value));
        }

        $message = str_replace('%value%', (string) $value, $message);
        foreach ($this->abstractOptions['messageVariables'] as $ident => $property) {
            if (is_array($property)) {
                $value = $this->{key($property)}[current($property)];
                if (is_array($value)) {
                    $value = '[' . implode(', ', $value) . ']';
                }
            } else {
                $value = $this->$property;
            }
            $message = str_replace("%$ident%", (string) $value, $message);
        }

        $length = self::getMessageLength();
        if (($length > -1) && (strlen($message) > $length)) {
            $message = substr($message, 0, $length - 3) . '...';
        }

        return $message;
    }

    /**
     * @param  string $messageKey
     * @param  string $value      OPTIONAL
     * @return void
     */
    protected function error($messageKey, $value = null)
    {
        if ($messageKey === null) {
            $keys = array_keys($this->abstractOptions['messageTemplates']);
            $messageKey = current($keys);
        }

        if ($value === null) {
            $value = $this->value;
        }

        $this->abstractOptions['messages'][$messageKey] = $this->createMessage($messageKey, $value);
    }

    /**
     * Returns the validation value
     *
     * @return mixed Value to be validated
     */
    protected function getValue()
    {
        return $this->value;
    }

    /**
     * Sets the value to be validated and clears the messages and errors arrays
     *
     * @param  mixed $value
     * @return void
     */
    protected function setValue($value)
    {
        $this->value               = $value;
        $this->abstractOptions['messages'] = [];
    }

    /**
     * Set flag indicating whether or not value should be obfuscated in messages
     *
     * @param  bool $flag
     * @return $this
     */
    public function setValueObscured($flag)
    {
        $this->abstractOptions['valueObscured'] = (bool) $flag;
        return $this;
    }

    /**
     * Retrieve flag indicating whether or not value should be obfuscated in
     * messages
     *
     * @return bool
     */
    public function isValueObscured()
    {
        return $this->abstractOptions['valueObscured'];
    }

    /**
     * Set translation object
     *
     * @param  Translator\TranslatorInterface|null $translator
     * @param  string          $textDomain (optional)
     * @return $this
     * @throws Exception\InvalidArgumentException
     */
    public function setTranslator(Translator\TranslatorInterface $translator = null, $textDomain = null)
    {
        $this->abstractOptions['translator'] = $translator;
        if (null !== $textDomain) {
            $this->setTranslatorTextDomain($textDomain);
        }
        return $this;
    }

    /**
     * Return translation object
     *
     * @return Translator\TranslatorInterface|null
     */
    public function getTranslator()
    {
        if (! $this->isTranslatorEnabled()) {
            return;
        }

        if (null === $this->abstractOptions['translator']) {
            $this->abstractOptions['translator'] = self::getDefaultTranslator();
        }

        return $this->abstractOptions['translator'];
    }

    /**
     * Does this validator have its own specific translator?
     *
     * @return bool
     */
    public function hasTranslator()
    {
        return (bool) $this->abstractOptions['translator'];
    }

    /**
     * Set translation text domain
     *
     * @param  string $textDomain
     * @return $this
     */
    public function setTranslatorTextDomain($textDomain = 'default')
    {
        $this->abstractOptions['translatorTextDomain'] = $textDomain;
        return $this;
    }

    /**
     * Return the translation text domain
     *
     * @return string
     */
    public function getTranslatorTextDomain()
    {
        if (null === $this->abstractOptions['translatorTextDomain']) {
            $this->abstractOptions['translatorTextDomain'] =
                self::getDefaultTranslatorTextDomain();
        }
        return $this->abstractOptions['translatorTextDomain'];
    }

    /**
     * Set default translation object for all validate objects
     *
     * @param  Translator\TranslatorInterface|null $translator
     * @param  string          $textDomain (optional)
     * @return void
     * @throws Exception\InvalidArgumentException
     */
    public static function setDefaultTranslator(Translator\TranslatorInterface $translator = null, $textDomain = null)
    {
        static::$defaultTranslator = $translator;
        if (null !== $textDomain) {
            self::setDefaultTranslatorTextDomain($textDomain);
        }
    }

    /**
     * Get default translation object for all validate objects
     *
     * @return Translator\TranslatorInterface|null
     */
    public static function getDefaultTranslator()
    {
        return static::$defaultTranslator;
    }

    /**
     * Is there a default translation object set?
     *
     * @return bool
     */
    public static function hasDefaultTranslator()
    {
        return (bool) static::$defaultTranslator;
    }

    /**
     * Set default translation text domain for all validate objects
     *
     * @param  string $textDomain
     * @return void
     */
    public static function setDefaultTranslatorTextDomain($textDomain = 'default')
    {
        static::$defaultTranslatorTextDomain = $textDomain;
    }

    /**
     * Get default translation text domain for all validate objects
     *
     * @return string
     */
    public static function getDefaultTranslatorTextDomain()
    {
        return static::$defaultTranslatorTextDomain;
    }

    /**
     * Indicate whether or not translation should be enabled
     *
     * @param  bool $flag
     * @return $this
     */
    public function setTranslatorEnabled($flag = true)
    {
        $this->abstractOptions['translatorEnabled'] = (bool) $flag;
        return $this;
    }

    /**
     * Is translation enabled?
     *
     * @return bool
     */
    public function isTranslatorEnabled()
    {
        return $this->abstractOptions['translatorEnabled'];
    }

    /**
     * Returns the maximum allowed message length
     *
     * @return int
     */
    public static function getMessageLength()
    {
        return static::$messageLength;
    }

    /**
     * Sets the maximum allowed message length
     *
     * @param int $length
     */
    public static function setMessageLength($length = -1)
    {
        static::$messageLength = $length;
    }

    /**
     * Translate a validation message
     *
     * @param  string $messageKey
     * @param  string $message
     * @return string
     */
    protected function translateMessage($messageKey, $message)
    {
        $translator = $this->getTranslator();
        if (! $translator) {
            return $message;
        }

        return $translator->translate($message, $this->getTranslatorTextDomain());
    }
}
laminas-validator/src/Translator/TranslatorInterface.php000064400000001107147361032560017564 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-validator for the canonical source repository
 * @copyright https://github.com/laminas/laminas-validator/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-validator/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Validator\Translator;

interface TranslatorInterface
{
    /**
     * @param  string $message
     * @param  string $textDomain
     * @param  string $locale
     * @return string
     */
    public function translate($message, $textDomain = 'default', $locale = null);
}
laminas-validator/src/Translator/TranslatorAwareInterface.php000064400000003473147361032560020554 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-validator for the canonical source repository
 * @copyright https://github.com/laminas/laminas-validator/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-validator/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Validator\Translator;

interface TranslatorAwareInterface
{
    /**
     * Sets translator to use in helper
     *
     * @param  TranslatorInterface $translator  [optional] translator.
     *             Default is null, which sets no translator.
     * @param  string $textDomain  [optional] text domain
     *             Default is null, which skips setTranslatorTextDomain
     * @return self
     */
    public function setTranslator(TranslatorInterface $translator = null, $textDomain = null);

    /**
     * Returns translator used in object
     *
     * @return TranslatorInterface|null
     */
    public function getTranslator();

    /**
     * Checks if the object has a translator
     *
     * @return bool
     */
    public function hasTranslator();

    /**
     * Sets whether translator is enabled and should be used
     *
     * @param  bool $enabled [optional] whether translator should be used.
     *                  Default is true.
     * @return self
     */
    public function setTranslatorEnabled($enabled = true);

    /**
     * Returns whether translator is enabled and should be used
     *
     * @return bool
     */
    public function isTranslatorEnabled();

    /**
     * Set translation text domain
     *
     * @param  string $textDomain
     * @return TranslatorAwareInterface
     */
    public function setTranslatorTextDomain($textDomain = 'default');

    /**
     * Return the translation text domain
     *
     * @return string
     */
    public function getTranslatorTextDomain();
}
laminas-validator/src/Barcode.php000064400000012704147361032560013025 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-validator for the canonical source repository
 * @copyright https://github.com/laminas/laminas-validator/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-validator/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Validator;

use Traversable;

class Barcode extends AbstractValidator
{
    const INVALID        = 'barcodeInvalid';
    const FAILED         = 'barcodeFailed';
    const INVALID_CHARS  = 'barcodeInvalidChars';
    const INVALID_LENGTH = 'barcodeInvalidLength';

    protected $messageTemplates = [
        self::FAILED         => 'The input failed checksum validation',
        self::INVALID_CHARS  => 'The input contains invalid characters',
        self::INVALID_LENGTH => 'The input should have a length of %length% characters',
        self::INVALID        => 'Invalid type given. String expected',
    ];

    /**
     * Additional variables available for validation failure messages
     *
     * @var array
     */
    protected $messageVariables = [
        'length' => ['options' => 'length'],
    ];

    protected $options = [
        'adapter'     => null,  // Barcode adapter Laminas\Validator\Barcode\AbstractAdapter
        'options'     => null,  // Options for this adapter
        'length'      => null,
        'useChecksum' => null,
    ];

    /**
     * Constructor for barcodes
     *
     * @param array|string $options Options to use
     */
    public function __construct($options = null)
    {
        if ($options === null) {
            $options = [];
        }

        if (is_array($options)) {
            if (array_key_exists('options', $options)) {
                $options['options'] = ['options' => $options['options']];
            }
        } elseif ($options instanceof Traversable) {
            if (property_exists($options, 'options')) {
                $options['options'] = ['options' => $options['options']];
            }
        } else {
            $options = ['adapter' => $options];
        }

        parent::__construct($options);
    }

    /**
     * Returns the set adapter
     *
     * @return Barcode\AbstractAdapter
     */
    public function getAdapter()
    {
        if (! $this->options['adapter'] instanceof Barcode\AdapterInterface) {
            $this->setAdapter('Ean13');
        }

        return $this->options['adapter'];
    }

    /**
     * Sets a new barcode adapter
     *
     * @param  string|Barcode\AbstractAdapter $adapter Barcode adapter to use
     * @param  array  $options Options for this adapter
     * @return $this
     * @throws Exception\InvalidArgumentException
     */
    public function setAdapter($adapter, $options = null)
    {
        if (is_string($adapter)) {
            $adapter = ucfirst(strtolower($adapter));
            $adapter = 'Laminas\\Validator\\Barcode\\' . $adapter;

            if (! class_exists($adapter)) {
                throw new Exception\InvalidArgumentException('Barcode adapter matching "' . $adapter . '" not found');
            }

            $adapter = new $adapter($options);
        }

        if (! $adapter instanceof Barcode\AdapterInterface) {
            throw new Exception\InvalidArgumentException(
                sprintf(
                    'Adapter %s does not implement Laminas\\Validator\\Barcode\\AdapterInterface',
                    is_object($adapter) ? get_class($adapter) : gettype($adapter)
                )
            );
        }

        $this->options['adapter'] = $adapter;

        return $this;
    }

    /**
     * Returns the checksum option
     *
     * @return string
     */
    public function getChecksum()
    {
        return $this->getAdapter()->getChecksum();
    }

    /**
     * Sets if checksum should be validated, if no value is given the actual setting is returned
     *
     * @param  bool $checksum
     * @return bool
     */
    public function useChecksum($checksum = null)
    {
        return $this->getAdapter()->useChecksum($checksum);
    }

    /**
     * Defined by Laminas\Validator\ValidatorInterface
     *
     * Returns true if and only if $value contains a valid barcode
     *
     * @param  string $value
     * @return bool
     */
    public function isValid($value)
    {
        if (! is_string($value)) {
            $this->error(self::INVALID);
            return false;
        }

        $this->setValue($value);
        $adapter                 = $this->getAdapter();
        $this->options['length'] = $adapter->getLength();
        $result                  = $adapter->hasValidLength($value);
        if (! $result) {
            if (is_array($this->options['length'])) {
                $temp = $this->options['length'];
                $this->options['length'] = '';
                foreach ($temp as $length) {
                    $this->options['length'] .= '/';
                    $this->options['length'] .= $length;
                }

                $this->options['length'] = substr($this->options['length'], 1);
            }

            $this->error(self::INVALID_LENGTH);
            return false;
        }

        $result = $adapter->hasValidCharacters($value);
        if (! $result) {
            $this->error(self::INVALID_CHARS);
            return false;
        }

        if ($this->useChecksum(null)) {
            $result = $adapter->hasValidChecksum($value);
            if (! $result) {
                $this->error(self::FAILED);
                return false;
            }
        }

        return true;
    }
}
laminas-validator/src/Module.php000064400000002314147361032560012707 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-validator for the canonical source repository
 * @copyright https://github.com/laminas/laminas-validator/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-validator/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Validator;

class Module
{
    /**
     * Return default laminas-validator configuration for laminas-mvc applications.
     */
    public function getConfig()
    {
        $provider = new ConfigProvider();

        return [
            'service_manager' => $provider->getDependencyConfig(),
        ];
    }

    /**
     * Register a specification for the ValidatorManager with the ServiceListener.
     *
     * @param \Laminas\ModuleManager\ModuleManager $moduleManager
     * @return void
     */
    public function init($moduleManager)
    {
        $event = $moduleManager->getEvent();
        $container = $event->getParam('ServiceManager');
        $serviceListener = $container->get('ServiceListener');

        $serviceListener->addServiceManager(
            'ValidatorManager',
            'validators',
            ValidatorProviderInterface::class,
            'getValidatorConfig'
        );
    }
}
laminas-validator/src/StaticValidator.php000064400000004515147361032560014564 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-validator for the canonical source repository
 * @copyright https://github.com/laminas/laminas-validator/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-validator/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Validator;

use Laminas\ServiceManager\ServiceManager;

class StaticValidator
{
    /**
     * @var ValidatorPluginManager
     */
    protected static $plugins;

    /**
     * Set plugin manager to use for locating validators
     *
     * @param  ValidatorPluginManager|null $plugins
     * @return void
     */
    public static function setPluginManager(ValidatorPluginManager $plugins = null)
    {
        // Don't share by default to allow different arguments on subsequent calls
        if ($plugins instanceof ValidatorPluginManager) {
            // Vary how the share by default flag is set based on laminas-servicemanager version
            if (method_exists($plugins, 'configure')) {
                $plugins->configure(['shared_by_default' => false]);
            } else {
                $plugins->setShareByDefault(false);
            }
        }
        static::$plugins = $plugins;
    }

    /**
     * Get plugin manager for locating validators
     *
     * @return ValidatorPluginManager
     */
    public static function getPluginManager()
    {
        if (null === static::$plugins) {
            static::setPluginManager(new ValidatorPluginManager(new ServiceManager));
        }
        return static::$plugins;
    }

    /**
     * @param  mixed    $value
     * @param  string   $classBaseName
     * @param  array    $options OPTIONAL associative array of options to pass as
     *     the sole argument to the validator constructor.
     * @return bool
     * @throws Exception\InvalidArgumentException for an invalid $options argument.
     */
    public static function execute($value, $classBaseName, array $options = [])
    {
        if ($options && array_values($options) === $options) {
            throw new Exception\InvalidArgumentException(
                'Invalid options provided via $options argument; must be an associative array'
            );
        }

        $plugins = static::getPluginManager();

        $validator = $plugins->get($classBaseName, $options);
        return $validator->isValid($value);
    }
}
laminas-validator/src/GreaterThan.php000064400000007034147361032560013672 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-validator for the canonical source repository
 * @copyright https://github.com/laminas/laminas-validator/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-validator/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Validator;

use Laminas\Stdlib\ArrayUtils;
use Traversable;

class GreaterThan extends AbstractValidator
{
    const NOT_GREATER           = 'notGreaterThan';
    const NOT_GREATER_INCLUSIVE = 'notGreaterThanInclusive';

    /**
     * Validation failure message template definitions
     *
     * @var array
     */
    protected $messageTemplates = [
        self::NOT_GREATER => "The input is not greater than '%min%'",
        self::NOT_GREATER_INCLUSIVE => "The input is not greater than or equal to '%min%'",
    ];

    /**
     * @var array
     */
    protected $messageVariables = [
        'min' => 'min',
    ];

    /**
     * Minimum value
     *
     * @var mixed
     */
    protected $min;

    /**
     * Whether to do inclusive comparisons, allowing equivalence to max
     *
     * If false, then strict comparisons are done, and the value may equal
     * the min option
     *
     * @var bool
     */
    protected $inclusive;

    /**
     * Sets validator options
     *
     * @param  array|Traversable $options
     * @throws Exception\InvalidArgumentException
     */
    public function __construct($options = null)
    {
        if ($options instanceof Traversable) {
            $options = ArrayUtils::iteratorToArray($options);
        }
        if (! is_array($options)) {
            $options = func_get_args();
            $temp['min'] = array_shift($options);

            if (! empty($options)) {
                $temp['inclusive'] = array_shift($options);
            }

            $options = $temp;
        }

        if (! array_key_exists('min', $options)) {
            throw new Exception\InvalidArgumentException("Missing option 'min'");
        }

        if (! array_key_exists('inclusive', $options)) {
            $options['inclusive'] = false;
        }

        $this->setMin($options['min'])
             ->setInclusive($options['inclusive']);

        parent::__construct($options);
    }

    /**
     * Returns the min option
     *
     * @return mixed
     */
    public function getMin()
    {
        return $this->min;
    }

    /**
     * Sets the min option
     *
     * @param  mixed $min
     * @return $this Provides a fluent interface
     */
    public function setMin($min)
    {
        $this->min = $min;
        return $this;
    }

    /**
     * Returns the inclusive option
     *
     * @return bool
     */
    public function getInclusive()
    {
        return $this->inclusive;
    }

    /**
     * Sets the inclusive option
     *
     * @param  bool $inclusive
     * @return $this Provides a fluent interface
     */
    public function setInclusive($inclusive)
    {
        $this->inclusive = $inclusive;
        return $this;
    }

    /**
     * Returns true if and only if $value is greater than min option
     *
     * @param  mixed $value
     * @return bool
     */
    public function isValid($value)
    {
        $this->setValue($value);

        if ($this->inclusive) {
            if ($this->min > $value) {
                $this->error(self::NOT_GREATER_INCLUSIVE);
                return false;
            }
        } else {
            if ($this->min >= $value) {
                $this->error(self::NOT_GREATER);
                return false;
            }
        }

        return true;
    }
}
laminas-validator/src/ValidatorPluginManagerAwareInterface.php000064400000001316147361032560020663 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-validator for the canonical source repository
 * @copyright https://github.com/laminas/laminas-validator/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-validator/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Validator;

interface ValidatorPluginManagerAwareInterface
{
    /**
     * Set validator plugin manager
     *
     * @param ValidatorPluginManager $pluginManager
     */
    public function setValidatorPluginManager(ValidatorPluginManager $pluginManager);

    /**
     * Get validator plugin manager
     *
     * @return ValidatorPluginManager
     */
    public function getValidatorPluginManager();
}
laminas-validator/src/DateStep.php000064400000037160147361032560013202 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-validator for the canonical source repository
 * @copyright https://github.com/laminas/laminas-validator/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-validator/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Validator;

use DateInterval;
use DateTime;
use DateTimeZone;
use Laminas\Stdlib\ArrayUtils;
use Traversable;

class DateStep extends Date
{
    const NOT_STEP       = 'dateStepNotStep';

    const FORMAT_DEFAULT = DateTime::ISO8601;

    /**
     * @var array
     */
    protected $messageTemplates = [
        self::INVALID      => 'Invalid type given. String, integer, array or DateTime expected',
        self::INVALID_DATE => 'The input does not appear to be a valid date',
        self::FALSEFORMAT  => "The input does not fit the date format '%format%'",
        self::NOT_STEP     => 'The input is not a valid step',
    ];

    /**
     * Optional base date value
     *
     * @var string|int|\DateTime
     */
    protected $baseValue = '1970-01-01T00:00:00Z';

    /**
     * Date step interval (defaults to 1 day).
     * Uses the DateInterval specification.
     *
     * @var DateInterval
     */
    protected $step;

    /**
     * Optional timezone to be used when the baseValue
     * and validation values do not contain timezone info
     *
     * @var DateTimeZone
     */
    protected $timezone;

    /**
     * Set default options for this instance
     *
     * @param array $options
     */
    public function __construct($options = [])
    {
        if ($options instanceof Traversable) {
            $options = ArrayUtils::iteratorToArray($options);
        } elseif (! is_array($options)) {
            $options = func_get_args();
            $temp['baseValue'] = array_shift($options);
            if (! empty($options)) {
                $temp['step'] = array_shift($options);
            }
            if (! empty($options)) {
                $temp['format'] = array_shift($options);
            }
            if (! empty($options)) {
                $temp['timezone'] = array_shift($options);
            }

            $options = $temp;
        }

        if (! isset($options['step'])) {
            $options['step'] = new DateInterval('P1D');
        }
        if (! isset($options['timezone'])) {
            $options['timezone'] = new DateTimeZone(date_default_timezone_get());
        }

        parent::__construct($options);
    }

    /**
     * Sets the base value from which the step should be computed
     *
     * @param  string|int|\DateTime $baseValue
     * @return $this
     */
    public function setBaseValue($baseValue)
    {
        $this->baseValue = $baseValue;
        return $this;
    }

    /**
     * Returns the base value from which the step should be computed
     *
     * @return string|int|\DateTime
     */
    public function getBaseValue()
    {
        return $this->baseValue;
    }

    /**
     * Sets the step date interval
     *
     * @param  DateInterval $step
     * @return $this
     */
    public function setStep(DateInterval $step)
    {
        $this->step = $step;
        return $this;
    }

    /**
     * Returns the step date interval
     *
     * @return DateInterval
     */
    public function getStep()
    {
        return $this->step;
    }

    /**
     * Returns the timezone option
     *
     * @return DateTimeZone
     */
    public function getTimezone()
    {
        return $this->timezone;
    }

    /**
     * Sets the timezone option
     *
     * @param  DateTimeZone $timezone
     * @return $this
     */
    public function setTimezone(DateTimeZone $timezone)
    {
        $this->timezone = $timezone;
        return $this;
    }

    /**
     * Supports formats with ISO week (W) definitions
     *
     * @see Date::convertString()
     */
    protected function convertString($value, $addErrors = true)
    {
        // Custom week format support
        if (strpos($this->format, 'Y-\WW') === 0
            && preg_match('/^([0-9]{4})\-W([0-9]{2})/', $value, $matches)
        ) {
            $date = new DateTime();
            $date->setISODate($matches[1], $matches[2]);
        } else {
            $date = DateTime::createFromFormat($this->format, $value, new DateTimeZone('UTC'));
        }

        // Invalid dates can show up as warnings (ie. "2007-02-99")
        // and still return a DateTime object.
        $errors = DateTime::getLastErrors();
        if ($errors['warning_count'] > 0) {
            if ($addErrors) {
                $this->error(self::FALSEFORMAT);
            }
            return false;
        }

        return $date;
    }

    /**
     * Returns true if a date is within a valid step
     *
     * @param  string|int|\DateTime $value
     * @return bool
     * @throws Exception\InvalidArgumentException
     */
    public function isValid($value)
    {
        if (! parent::isValid($value)) {
            return false;
        }

        $valueDate = $this->convertToDateTime($value, false); // avoid duplicate errors
        $baseDate  = $this->convertToDateTime($this->baseValue, false);
        $step      = $this->getStep();

        // Same date?
        if ($valueDate == $baseDate) {
            return true;
        }

        // Optimization for simple intervals.
        // Handle intervals of just one date or time unit.
        $intervalParts = explode('|', $step->format('%y|%m|%d|%h|%i|%s'));
        $partCounts    = array_count_values($intervalParts);

        $unitKeys = ['years', 'months', 'days', 'hours', 'minutes', 'seconds'];
        $intervalParts = array_combine($unitKeys, $intervalParts);

        // Get absolute time difference to avoid special cases of missing/added time
        $absoluteValueDate = new DateTime($valueDate->format('Y-m-d H:i:s'), new DateTimeZone('UTC'));
        $absoluteBaseDate = new DateTime($baseDate->format('Y-m-d H:i:s'), new DateTimeZone('UTC'));

        $timeDiff  = $absoluteValueDate->diff($absoluteBaseDate, 1);
        $diffParts = array_combine($unitKeys, explode('|', $timeDiff->format('%y|%m|%d|%h|%i|%s')));

        if (5 === $partCounts['0']) {
            // Find the unit with the non-zero interval
            $intervalUnit = null;
            $stepValue    = null;
            foreach ($intervalParts as $key => $value) {
                if (0 != $value) {
                    $intervalUnit = $key;
                    $stepValue    = (int) $value;
                    break;
                }
            }

            // Check date units
            if (in_array($intervalUnit, ['years', 'months', 'days'])) {
                switch ($intervalUnit) {
                    case 'years':
                        if (0 == $diffParts['months'] && 0 == $diffParts['days']
                            && 0 == $diffParts['hours'] && 0 == $diffParts['minutes']
                            && 0 == $diffParts['seconds']
                        ) {
                            if (($diffParts['years'] % $stepValue) === 0) {
                                return true;
                            }
                        }
                        break;
                    case 'months':
                        if (0 == $diffParts['days'] && 0 == $diffParts['hours']
                            && 0 == $diffParts['minutes'] && 0 == $diffParts['seconds']
                        ) {
                            $months = ($diffParts['years'] * 12) + $diffParts['months'];
                            if (($months % $stepValue) === 0) {
                                return true;
                            }
                        }
                        break;
                    case 'days':
                        if (0 == $diffParts['hours'] && 0 == $diffParts['minutes']
                            && 0 == $diffParts['seconds']
                        ) {
                            $days = $timeDiff->format('%a'); // Total days
                            if (($days % $stepValue) === 0) {
                                return true;
                            }
                        }
                        break;
                }
                $this->error(self::NOT_STEP);
                return false;
            }

            // Check time units
            if (in_array($intervalUnit, ['hours', 'minutes', 'seconds'])) {
                // Simple test if $stepValue is 1.
                if (1 == $stepValue) {
                    if ('hours' === $intervalUnit
                        && 0 == $diffParts['minutes'] && 0 == $diffParts['seconds']
                    ) {
                        return true;
                    } elseif ('minutes' === $intervalUnit && 0 == $diffParts['seconds']) {
                        return true;
                    } elseif ('seconds' === $intervalUnit) {
                        return true;
                    }

                    $this->error(self::NOT_STEP);

                    return false;
                }

                // Simple test for same day, when using default baseDate
                if ($baseDate->format('Y-m-d') == $valueDate->format('Y-m-d')
                    && $baseDate->format('Y-m-d') == '1970-01-01'
                ) {
                    switch ($intervalUnit) {
                        case 'hours':
                            if (0 == $diffParts['minutes'] && 0 == $diffParts['seconds']) {
                                if (($diffParts['hours'] % $stepValue) === 0) {
                                    return true;
                                }
                            }
                            break;
                        case 'minutes':
                            if (0 == $diffParts['seconds']) {
                                $minutes = ($diffParts['hours'] * 60) + $diffParts['minutes'];
                                if (($minutes % $stepValue) === 0) {
                                    return true;
                                }
                            }
                            break;
                        case 'seconds':
                            $seconds = ($diffParts['hours'] * 60 * 60)
                                       + ($diffParts['minutes'] * 60)
                                       + $diffParts['seconds'];
                            if (($seconds % $stepValue) === 0) {
                                return true;
                            }
                            break;
                    }
                    $this->error(self::NOT_STEP);
                    return false;
                }
            }
        }

        return $this->fallbackIncrementalIterationLogic($baseDate, $valueDate, $intervalParts, $diffParts, $step);
    }

    /**
     * Fall back to slower (but accurate) method for complex intervals.
     * Keep adding steps to the base date until a match is found
     * or until the value is exceeded.
     *
     * This is really slow if the interval is small, especially if the
     * default base date of 1/1/1970 is used. We can skip a chunk of
     * iterations by starting at the lower bound of steps needed to reach
     * the target
     *
     * @param DateTime     $baseDate
     * @param DateTime     $valueDate
     * @param int[]        $intervalParts
     * @param int[]        $diffParts
     * @param DateInterval $step
     *
     * @return bool
     */
    private function fallbackIncrementalIterationLogic(
        DateTime $baseDate,
        DateTime $valueDate,
        array $intervalParts,
        array $diffParts,
        DateInterval $step
    ) {
        list($minSteps, $requiredIterations) = $this->computeMinStepAndRequiredIterations($intervalParts, $diffParts);
        $minimumInterval                     = $this->computeMinimumInterval($intervalParts, $minSteps);
        $isIncrementalStepping               = $baseDate < $valueDate;
        $dateModificationOperation           = $isIncrementalStepping ? 'add' : 'sub';

        for ($offsetIterations = 0; $offsetIterations < $requiredIterations; $offsetIterations += 1) {
            $baseDate->{$dateModificationOperation}($minimumInterval);
        }

        while (($isIncrementalStepping && $baseDate < $valueDate)
            || (! $isIncrementalStepping && $baseDate > $valueDate)
        ) {
            $baseDate->{$dateModificationOperation}($step);

            if ($baseDate == $valueDate) {
                return true;
            }
        }

        $this->error(self::NOT_STEP);

        return false;
    }

    /**
     * Computes minimum interval to use for iterations while checking steps
     *
     * @param int[] $intervalParts
     * @param int   $minSteps
     *
     * @return DateInterval
     */
    private function computeMinimumInterval(array $intervalParts, $minSteps)
    {
        return new DateInterval(sprintf(
            'P%dY%dM%dDT%dH%dM%dS',
            $intervalParts['years'] * $minSteps,
            $intervalParts['months'] * $minSteps,
            $intervalParts['days'] * $minSteps,
            $intervalParts['hours'] * $minSteps,
            $intervalParts['minutes'] * $minSteps,
            $intervalParts['seconds'] * $minSteps
        ));
    }

    /**
     * @param int[] $intervalParts
     * @param int[] $diffParts
     *
     * @return int[] (ordered tuple containing minimum steps and required step iterations
     */
    private function computeMinStepAndRequiredIterations(array $intervalParts, array $diffParts)
    {
        $minSteps = $this->computeMinSteps($intervalParts, $diffParts);

        // If we use PHP_INT_MAX DateInterval::__construct falls over with a bad format error
        // before we reach the max on 64 bit machines
        $maxInteger             = min(pow(2, 31), PHP_INT_MAX);
        // check for integer overflow and split $minimum interval if needed
        $maximumInterval        = max($intervalParts);
        $requiredStepIterations = 1;

        if (($minSteps * $maximumInterval) > $maxInteger) {
            $requiredStepIterations = ceil(($minSteps * $maximumInterval) / $maxInteger);
            $minSteps               = floor($minSteps / $requiredStepIterations);
        }

        return [$minSteps, $minSteps ? $requiredStepIterations : 0];
    }

    /**
     * Multiply the step interval by the lower bound of steps to reach the target
     *
     * @param int[] $intervalParts
     * @param int[] $diffParts
     *
     * @return int
     */
    private function computeMinSteps(array $intervalParts, array $diffParts)
    {
        $intervalMaxSeconds = $this->computeIntervalMaxSeconds($intervalParts);

        return 0 == $intervalMaxSeconds
            ? 0
            : max(floor($this->computeDiffMinSeconds($diffParts) / $intervalMaxSeconds) - 1, 0);
    }

    /**
     * Get upper bound of the given interval in seconds
     * Converts a given `$intervalParts` array into seconds
     *
     * @param int[] $intervalParts
     *
     * @return int
     */
    private function computeIntervalMaxSeconds(array $intervalParts)
    {
        return ($intervalParts['years'] * 60 * 60 * 24 * 366)
            + ($intervalParts['months'] * 60 * 60 * 24 * 31)
            + ($intervalParts['days'] * 60 * 60 * 24)
            + ($intervalParts['hours'] * 60 * 60)
            + ($intervalParts['minutes'] * 60)
            + $intervalParts['seconds'];
    }

    /**
     * Get lower bound of difference in secondss
     * Converts a given `$diffParts` array into seconds
     *
     * @param int[] $diffParts
     *
     * @return int
     */
    private function computeDiffMinSeconds(array $diffParts)
    {
        return ($diffParts['years'] * 60 * 60 * 24 * 365)
            + ($diffParts['months'] * 60 * 60 * 24 * 28)
            + ($diffParts['days'] * 60 * 60 * 24)
            + ($diffParts['hours'] * 60 * 60)
            + ($diffParts['minutes'] * 60)
            + $diffParts['seconds'];
    }
}
laminas-validator/src/Db/AbstractDb.php000064400000020426147361032560014024 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-validator for the canonical source repository
 * @copyright https://github.com/laminas/laminas-validator/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-validator/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Validator\Db;

use Laminas\Db\Adapter\Adapter as DbAdapter;
use Laminas\Db\Adapter\AdapterAwareInterface;
use Laminas\Db\Adapter\AdapterAwareTrait;
use Laminas\Db\Sql\Select;
use Laminas\Db\Sql\Sql;
use Laminas\Db\Sql\TableIdentifier;
use Laminas\Stdlib\ArrayUtils;
use Laminas\Validator\AbstractValidator;
use Laminas\Validator\Exception;
use Traversable;

/**
 * Class for Database record validation
 */
abstract class AbstractDb extends AbstractValidator implements AdapterAwareInterface
{
    use AdapterAwareTrait;

    /**
     * Error constants
     */
    const ERROR_NO_RECORD_FOUND = 'noRecordFound';
    const ERROR_RECORD_FOUND    = 'recordFound';

    /**
     * @var array Message templates
     */
    protected $messageTemplates = [
        self::ERROR_NO_RECORD_FOUND => 'No record matching the input was found',
        self::ERROR_RECORD_FOUND    => 'A record matching the input was found',
    ];

    /**
     * Select object to use. can be set, or will be auto-generated
     *
     * @var Select
     */
    protected $select;

    /**
     * @var string
     */
    protected $schema = null;

    /**
     * @var string
     */
    protected $table = '';

    /**
     * @var string
     */
    protected $field = '';

    /**
     * @var mixed
     */
    protected $exclude = null;

    /**
     * Provides basic configuration for use with Laminas\Validator\Db Validators
     * Setting $exclude allows a single record to be excluded from matching.
     * Exclude can either be a String containing a where clause, or an array with `field` and `value` keys
     * to define the where clause added to the sql.
     * A database adapter may optionally be supplied to avoid using the registered default adapter.
     *
     * The following option keys are supported:
     * 'table'   => The database table to validate against
     * 'schema'  => The schema keys
     * 'field'   => The field to check for a match
     * 'exclude' => An optional where clause or field/value pair to exclude from the query
     * 'adapter' => An optional database adapter to use
     *
     * @param array|Traversable|Select $options Options to use for this validator
     * @throws \Laminas\Validator\Exception\InvalidArgumentException
     */
    public function __construct($options = null)
    {
        parent::__construct($options);

        if ($options instanceof Select) {
            $this->setSelect($options);
            return;
        }

        if ($options instanceof Traversable) {
            $options = ArrayUtils::iteratorToArray($options);
        } elseif (func_num_args() > 1) {
            $options       = func_get_args();
            $firstArgument = array_shift($options);
            if (is_array($firstArgument)) {
                $temp = ArrayUtils::iteratorToArray($firstArgument);
            } else {
                $temp['table'] = $firstArgument;
            }

            $temp['field'] = array_shift($options);

            if (! empty($options)) {
                $temp['exclude'] = array_shift($options);
            }

            if (! empty($options)) {
                $temp['adapter'] = array_shift($options);
            }

            $options = $temp;
        }

        if (! array_key_exists('table', $options) && ! array_key_exists('schema', $options)) {
            throw new Exception\InvalidArgumentException('Table or Schema option missing!');
        }

        if (! array_key_exists('field', $options)) {
            throw new Exception\InvalidArgumentException('Field option missing!');
        }

        if (array_key_exists('adapter', $options)) {
            $this->setAdapter($options['adapter']);
        }

        if (array_key_exists('exclude', $options)) {
            $this->setExclude($options['exclude']);
        }

        $this->setField($options['field']);
        if (array_key_exists('table', $options)) {
            $this->setTable($options['table']);
        }

        if (array_key_exists('schema', $options)) {
            $this->setSchema($options['schema']);
        }
    }

    /**
     * Returns the set adapter
     *
     * @throws \Laminas\Validator\Exception\RuntimeException When no database adapter is defined
     * @return DbAdapter
     */
    public function getAdapter()
    {
        return $this->adapter;
    }

    /**
     * Sets a new database adapter
     *
     * @param  DbAdapter $adapter
     * @return self Provides a fluent interface
     */
    public function setAdapter(DbAdapter $adapter)
    {
        return $this->setDbAdapter($adapter);
    }

    /**
     * Returns the set exclude clause
     *
     * @return string|array
     */
    public function getExclude()
    {
        return $this->exclude;
    }

    /**
     * Sets a new exclude clause
     *
     * @param string|array $exclude
     * @return $this Provides a fluent interface
     */
    public function setExclude($exclude)
    {
        $this->exclude = $exclude;
        $this->select  = null;
        return $this;
    }

    /**
     * Returns the set field
     *
     * @return string|array
     */
    public function getField()
    {
        return $this->field;
    }

    /**
     * Sets a new field
     *
     * @param string $field
     * @return $this
     */
    public function setField($field)
    {
        $this->field  = (string) $field;
        $this->select = null;
        return $this;
    }

    /**
     * Returns the set table
     *
     * @return string
     */
    public function getTable()
    {
        return $this->table;
    }

    /**
     * Sets a new table
     *
     * @param string $table
     * @return $this Provides a fluent interface
     */
    public function setTable($table)
    {
        $this->table  = (string) $table;
        $this->select = null;
        return $this;
    }

    /**
     * Returns the set schema
     *
     * @return string
     */
    public function getSchema()
    {
        return $this->schema;
    }

    /**
     * Sets a new schema
     *
     * @param string $schema
     * @return $this Provides a fluent interface
     */
    public function setSchema($schema)
    {
        $this->schema = $schema;
        $this->select = null;
        return $this;
    }

    /**
     * Sets the select object to be used by the validator
     *
     * @param  Select $select
     * @return $this Provides a fluent interface
     */
    public function setSelect(Select $select)
    {
        $this->select = $select;
        return $this;
    }

    /**
     * Gets the select object to be used by the validator.
     * If no select object was supplied to the constructor,
     * then it will auto-generate one from the given table,
     * schema, field, and adapter options.
     *
     * @return Select The Select object which will be used
     */
    public function getSelect()
    {
        if ($this->select instanceof Select) {
            return $this->select;
        }

        // Build select object
        $select          = new Select();
        $tableIdentifier = new TableIdentifier($this->table, $this->schema);
        $select->from($tableIdentifier)->columns([$this->field]);
        $select->where->equalTo($this->field, null);

        if ($this->exclude !== null) {
            if (is_array($this->exclude)) {
                $select->where->notEqualTo(
                    $this->exclude['field'],
                    $this->exclude['value']
                );
            } else {
                $select->where($this->exclude);
            }
        }

        $this->select = $select;

        return $this->select;
    }

    /**
     * Run query and returns matches, or null if no matches are found.
     *
     * @param  string $value
     * @return array when matches are found.
     */
    protected function query($value)
    {
        $sql = new Sql($this->getAdapter());
        $select = $this->getSelect();
        $statement = $sql->prepareStatementForSqlObject($select);
        $parameters = $statement->getParameterContainer();
        $parameters['where1'] = $value;
        $result = $statement->execute();

        return $result->current();
    }
}
laminas-validator/src/Db/RecordExists.php000064400000001706147361032560014431 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-validator for the canonical source repository
 * @copyright https://github.com/laminas/laminas-validator/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-validator/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Validator\Db;

use Laminas\Validator\Exception;

/**
 * Confirms a record exists in a table.
 */
class RecordExists extends AbstractDb
{
    public function isValid($value)
    {
        /*
         * Check for an adapter being defined. If not, throw an exception.
         */
        if (null === $this->adapter) {
            throw new Exception\RuntimeException('No database adapter present');
        }

        $valid = true;
        $this->setValue($value);

        $result = $this->query($value);
        if (! $result) {
            $valid = false;
            $this->error(self::ERROR_NO_RECORD_FOUND);
        }

        return $valid;
    }
}
laminas-validator/src/Db/NoRecordExists.php000064400000001713147361032560014724 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-validator for the canonical source repository
 * @copyright https://github.com/laminas/laminas-validator/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-validator/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Validator\Db;

use Laminas\Validator\Exception;

/**
 * Confirms a record does not exist in a table.
 */
class NoRecordExists extends AbstractDb
{
    public function isValid($value)
    {
        /*
         * Check for an adapter being defined. If not, throw an exception.
         */
        if (null === $this->adapter) {
            throw new Exception\RuntimeException('No database adapter present');
        }

        $valid = true;
        $this->setValue($value);

        $result = $this->query($value);
        if ($result) {
            $valid = false;
            $this->error(self::ERROR_RECORD_FOUND);
        }

        return $valid;
    }
}
laminas-validator/src/IsInstanceOf.php000064400000004611147361032560014011 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-validator for the canonical source repository
 * @copyright https://github.com/laminas/laminas-validator/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-validator/blob/master/LICENSE.md New BSD License
 */
namespace Laminas\Validator;

use Traversable;

class IsInstanceOf extends AbstractValidator
{
    const NOT_INSTANCE_OF = 'notInstanceOf';

    /**
     * Validation failure message template definitions
     *
     * @var array
     */
    protected $messageTemplates = [
        self::NOT_INSTANCE_OF => "The input is not an instance of '%className%'",
    ];

    /**
     * Additional variables available for validation failure messages
     *
     * @var array
     */
    protected $messageVariables = [
        'className' => 'className',
    ];

    /**
     * Class name
     *
     * @var string
     */
    protected $className;

    /**
     * Sets validator options
     *
     * @param  array|Traversable $options
     * @throws Exception\InvalidArgumentException
     */
    public function __construct($options = null)
    {
        if ($options instanceof Traversable) {
            $options = iterator_to_array($options);
        }

        // If argument is not an array, consider first argument as class name
        if (! is_array($options)) {
            $options = func_get_args();

            $tmpOptions = [];
            $tmpOptions['className'] = array_shift($options);

            $options = $tmpOptions;
        }

        if (! array_key_exists('className', $options)) {
            throw new Exception\InvalidArgumentException('Missing option "className"');
        }

        parent::__construct($options);
    }

    /**
     * Get class name
     *
     * @return string
     */
    public function getClassName()
    {
        return $this->className;
    }

    /**
     * Set class name
     *
     * @param  string $className
     * @return $this
     */
    public function setClassName($className)
    {
        $this->className = $className;
        return $this;
    }

    /**
     * Returns true if $value is instance of $this->className
     *
     * @param  mixed $value
     * @return bool
     */
    public function isValid($value)
    {
        if ($value instanceof $this->className) {
            return true;
        }
        $this->error(self::NOT_INSTANCE_OF);
        return false;
    }
}
laminas-validator/src/ConfigProvider.php000064400000002164147361032560014405 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-validator for the canonical source repository
 * @copyright https://github.com/laminas/laminas-validator/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-validator/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Validator;

class ConfigProvider
{
    /**
     * Return configuration for this component.
     *
     * @return array
     */
    public function __invoke()
    {
        return [
            'dependencies' => $this->getDependencyConfig(),
        ];
    }

    /**
     * Return dependency mappings for this component.
     *
     * @return array
     */
    public function getDependencyConfig()
    {
        return [
            'aliases' => [
                'ValidatorManager' => ValidatorPluginManager::class,

                // Legacy Zend Framework aliases
                \Zend\Validator\ValidatorPluginManager::class => ValidatorPluginManager::class,
            ],
            'factories' => [
                ValidatorPluginManager::class => ValidatorPluginManagerFactory::class,
            ],
        ];
    }
}
laminas-validator/src/Hostname/Com.php000064400000031313147361032560013757 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-validator for the canonical source repository
 * @copyright https://github.com/laminas/laminas-validator/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-validator/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Validator\Hostname;

/**
 * Resource file for com and net idn validation
 */
return [
    1  => '/^[\x{002d}0-9\x{0400}-\x{052f}]{1,63}$/iu',
    2  => '/^[\x{002d}0-9\x{0370}-\x{03ff}]{1,63}$/iu',
    3  => '/^[\x{002d}0-9a-z\x{ac00}-\x{d7a3}]{1,17}$/iu',
    // @codingStandardsIgnoreStart
    4  => '/^[\x{002d}0-9a-z·à-öø-ÿāăąćĉċčďđēĕėęěĝğġģĥħĩīĭįıĵķĸĺļľłńņňŋōŏőœŕŗřśŝşšţťŧũūŭůűųŵŷźżž]{1,63}$/iu',
    // @codingStandardsIgnoreEnd
    5  => '/^[\x{002d}0-9A-Za-z\x{3400}-\x{3401}\x{3404}-\x{3406}\x{340C}\x{3416}\x{341C}' .
'\x{3421}\x{3424}\x{3428}-\x{3429}\x{342B}-\x{342E}\x{3430}-\x{3434}\x{3436}' .
'\x{3438}-\x{343C}\x{343E}\x{3441}-\x{3445}\x{3447}\x{3449}-\x{3451}\x{3453}' .
'\x{3457}-\x{345F}\x{3463}-\x{3467}\x{346E}-\x{3471}\x{3473}-\x{3477}\x{3479}-\x{348E}\x{3491}-\x{3497}' .
'\x{3499}-\x{34A1}\x{34A4}-\x{34AD}\x{34AF}-\x{34B0}\x{34B2}-\x{34BF}\x{34C2}-\x{34C5}\x{34C7}-\x{34CC}' .
'\x{34CE}-\x{34D1}\x{34D3}-\x{34D8}\x{34DA}-\x{34E4}\x{34E7}-\x{34E9}\x{34EC}-\x{34EF}\x{34F1}-\x{34FE}' .
'\x{3500}-\x{3507}\x{350A}-\x{3513}\x{3515}\x{3517}-\x{351A}\x{351C}-\x{351E}\x{3520}-\x{352A}' .
'\x{352C}-\x{3552}\x{3554}-\x{355C}\x{355E}-\x{3567}\x{3569}-\x{3573}\x{3575}-\x{357C}\x{3580}-\x{3588}' .
'\x{358F}-\x{3598}\x{359E}-\x{35AB}\x{35B4}-\x{35CD}\x{35D0}\x{35D3}-\x{35DC}\x{35E2}-\x{35ED}' .
'\x{35F0}-\x{35F6}\x{35FB}-\x{3602}\x{3605}-\x{360E}\x{3610}-\x{3611}\x{3613}-\x{3616}\x{3619}-\x{362D}' .
'\x{362F}-\x{3634}\x{3636}-\x{363B}\x{363F}-\x{3645}\x{3647}-\x{364B}\x{364D}-\x{3653}\x{3655}' .
'\x{3659}-\x{365E}\x{3660}-\x{3665}\x{3667}-\x{367C}\x{367E}\x{3680}-\x{3685}\x{3687}' .
'\x{3689}-\x{3690}\x{3692}-\x{3698}\x{369A}\x{369C}-\x{36AE}\x{36B0}-\x{36BF}\x{36C1}-\x{36C5}' .
'\x{36C9}-\x{36CA}\x{36CD}-\x{36DE}\x{36E1}-\x{36E2}\x{36E5}-\x{36FE}\x{3701}-\x{3713}\x{3715}-\x{371E}' .
'\x{3720}-\x{372C}\x{372E}-\x{3745}\x{3747}-\x{3748}\x{374A}\x{374C}-\x{3759}\x{375B}-\x{3760}' .
'\x{3762}-\x{3767}\x{3769}-\x{3772}\x{3774}-\x{378C}\x{378F}-\x{379C}\x{379F}\x{37A1}-\x{37AD}' .
'\x{37AF}-\x{37B7}\x{37B9}-\x{37C1}\x{37C3}-\x{37C5}\x{37C7}-\x{37D4}\x{37D6}-\x{37E0}\x{37E2}' .
'\x{37E5}-\x{37ED}\x{37EF}-\x{37F6}\x{37F8}-\x{3802}\x{3804}-\x{381D}\x{3820}-\x{3822}\x{3825}-\x{382A}' .
'\x{382D}-\x{382F}\x{3831}-\x{3832}\x{3834}-\x{384C}\x{384E}-\x{3860}\x{3862}-\x{3863}\x{3865}-\x{386B}' .
'\x{386D}-\x{3886}\x{3888}-\x{38A1}\x{38A3}\x{38A5}-\x{38AA}\x{38AC}\x{38AE}-\x{38B0}' .
'\x{38B2}-\x{38B6}\x{38B8}\x{38BA}-\x{38BE}\x{38C0}-\x{38C9}\x{38CB}-\x{38D4}\x{38D8}-\x{38E0}' .
'\x{38E2}-\x{38E6}\x{38EB}-\x{38ED}\x{38EF}-\x{38F2}\x{38F5}-\x{38F7}\x{38FA}-\x{38FF}\x{3901}-\x{392A}' .
'\x{392C}\x{392E}-\x{393B}\x{393E}-\x{3956}\x{395A}-\x{3969}\x{396B}-\x{397A}\x{397C}-\x{3987}' .
'\x{3989}-\x{3998}\x{399A}-\x{39B0}\x{39B2}\x{39B4}-\x{39D0}\x{39D2}-\x{39DA}\x{39DE}-\x{39DF}' .
'\x{39E1}-\x{39EF}\x{39F1}-\x{3A17}\x{3A19}-\x{3A2A}\x{3A2D}-\x{3A40}\x{3A43}-\x{3A4E}\x{3A50}' .
'\x{3A52}-\x{3A5E}\x{3A60}-\x{3A6D}\x{3A6F}-\x{3A77}\x{3A79}-\x{3A82}\x{3A84}-\x{3A85}\x{3A87}-\x{3A89}' .
'\x{3A8B}-\x{3A8F}\x{3A91}-\x{3A93}\x{3A95}-\x{3A96}\x{3A9A}\x{3A9C}-\x{3AA6}\x{3AA8}-\x{3AA9}' .
'\x{3AAB}-\x{3AB1}\x{3AB4}-\x{3ABC}\x{3ABE}-\x{3AC5}\x{3ACA}-\x{3ACB}\x{3ACD}-\x{3AD5}\x{3AD7}-\x{3AE1}' .
'\x{3AE4}-\x{3AE7}\x{3AE9}-\x{3AEC}\x{3AEE}-\x{3AFD}\x{3B01}-\x{3B10}\x{3B12}-\x{3B15}\x{3B17}-\x{3B1E}' .
'\x{3B20}-\x{3B23}\x{3B25}-\x{3B27}\x{3B29}-\x{3B36}\x{3B38}-\x{3B39}\x{3B3B}-\x{3B3C}\x{3B3F}' .
'\x{3B41}-\x{3B44}\x{3B47}-\x{3B4C}\x{3B4E}\x{3B51}-\x{3B55}\x{3B58}-\x{3B62}\x{3B68}-\x{3B72}' .
'\x{3B78}-\x{3B88}\x{3B8B}-\x{3B9F}\x{3BA1}\x{3BA3}-\x{3BBA}\x{3BBC}\x{3BBF}-\x{3BD0}' .
'\x{3BD3}-\x{3BE6}\x{3BEA}-\x{3BFB}\x{3BFE}-\x{3C12}\x{3C14}-\x{3C1B}\x{3C1D}-\x{3C37}\x{3C39}-\x{3C4F}' .
'\x{3C52}\x{3C54}-\x{3C5C}\x{3C5E}-\x{3C68}\x{3C6A}-\x{3C76}\x{3C78}-\x{3C8F}\x{3C91}-\x{3CA8}' .
'\x{3CAA}-\x{3CAD}\x{3CAF}-\x{3CBE}\x{3CC0}-\x{3CC8}\x{3CCA}-\x{3CD3}\x{3CD6}-\x{3CE0}\x{3CE4}-\x{3CEE}' .
'\x{3CF3}-\x{3D0A}\x{3D0E}-\x{3D1E}\x{3D20}-\x{3D21}\x{3D25}-\x{3D38}\x{3D3B}-\x{3D46}\x{3D4A}-\x{3D59}' .
'\x{3D5D}-\x{3D7B}\x{3D7D}-\x{3D81}\x{3D84}-\x{3D88}\x{3D8C}-\x{3D8F}\x{3D91}-\x{3D98}\x{3D9A}-\x{3D9C}' .
'\x{3D9E}-\x{3DA1}\x{3DA3}-\x{3DB0}\x{3DB2}-\x{3DB5}\x{3DB9}-\x{3DBC}\x{3DBE}-\x{3DCB}\x{3DCD}-\x{3DDB}' .
'\x{3DDF}-\x{3DE8}\x{3DEB}-\x{3DF0}\x{3DF3}-\x{3DF9}\x{3DFB}-\x{3DFC}\x{3DFE}-\x{3E05}\x{3E08}-\x{3E33}' .
'\x{3E35}-\x{3E3E}\x{3E40}-\x{3E47}\x{3E49}-\x{3E67}\x{3E6B}-\x{3E6F}\x{3E71}-\x{3E85}\x{3E87}-\x{3E8C}' .
'\x{3E8E}-\x{3E98}\x{3E9A}-\x{3EA1}\x{3EA3}-\x{3EAE}\x{3EB0}-\x{3EB5}\x{3EB7}-\x{3EBA}\x{3EBD}' .
'\x{3EBF}-\x{3EC4}\x{3EC7}-\x{3ECE}\x{3ED1}-\x{3ED7}\x{3ED9}-\x{3EDA}\x{3EDD}-\x{3EE3}\x{3EE7}-\x{3EE8}' .
'\x{3EEB}-\x{3EF2}\x{3EF5}-\x{3EFF}\x{3F01}-\x{3F02}\x{3F04}-\x{3F07}\x{3F09}-\x{3F44}\x{3F46}-\x{3F4E}' .
'\x{3F50}-\x{3F53}\x{3F55}-\x{3F72}\x{3F74}-\x{3F75}\x{3F77}-\x{3F7B}\x{3F7D}-\x{3FB0}\x{3FB6}-\x{3FBF}' .
'\x{3FC1}-\x{3FCF}\x{3FD1}-\x{3FD3}\x{3FD5}-\x{3FDF}\x{3FE1}-\x{400B}\x{400D}-\x{401C}\x{401E}-\x{4024}' .
'\x{4027}-\x{403F}\x{4041}-\x{4060}\x{4062}-\x{4069}\x{406B}-\x{408A}\x{408C}-\x{40A7}\x{40A9}-\x{40B4}' .
'\x{40B6}-\x{40C2}\x{40C7}-\x{40CF}\x{40D1}-\x{40DE}\x{40E0}-\x{40E7}\x{40E9}-\x{40EE}\x{40F0}-\x{40FB}' .
'\x{40FD}-\x{4109}\x{410B}-\x{4115}\x{4118}-\x{411D}\x{411F}-\x{4122}\x{4124}-\x{4133}\x{4136}-\x{4138}' .
'\x{413A}-\x{4148}\x{414A}-\x{4169}\x{416C}-\x{4185}\x{4188}-\x{418B}\x{418D}-\x{41AD}\x{41AF}-\x{41B3}' .
'\x{41B5}-\x{41C3}\x{41C5}-\x{41C9}\x{41CB}-\x{41F2}\x{41F5}-\x{41FE}\x{4200}-\x{4227}\x{422A}-\x{4246}' .
'\x{4248}-\x{4263}\x{4265}-\x{428B}\x{428D}-\x{42A1}\x{42A3}-\x{42C4}\x{42C8}-\x{42DC}\x{42DE}-\x{430A}' .
'\x{430C}-\x{4335}\x{4337}\x{4342}-\x{435F}\x{4361}-\x{439A}\x{439C}-\x{439D}\x{439F}-\x{43A4}' .
'\x{43A6}-\x{43EC}\x{43EF}-\x{4405}\x{4407}-\x{4429}\x{442B}-\x{4455}\x{4457}-\x{4468}\x{446A}-\x{446D}' .
'\x{446F}-\x{4476}\x{4479}-\x{447D}\x{447F}-\x{4486}\x{4488}-\x{4490}\x{4492}-\x{4498}\x{449A}-\x{44AD}' .
'\x{44B0}-\x{44BD}\x{44C1}-\x{44D3}\x{44D6}-\x{44E7}\x{44EA}\x{44EC}-\x{44FA}\x{44FC}-\x{4541}' .
'\x{4543}-\x{454F}\x{4551}-\x{4562}\x{4564}-\x{4575}\x{4577}-\x{45AB}\x{45AD}-\x{45BD}\x{45BF}-\x{45D5}' .
'\x{45D7}-\x{45EC}\x{45EE}-\x{45F2}\x{45F4}-\x{45FA}\x{45FC}-\x{461A}\x{461C}-\x{461D}\x{461F}-\x{4631}' .
'\x{4633}-\x{4649}\x{464C}\x{464E}-\x{4652}\x{4654}-\x{466A}\x{466C}-\x{4675}\x{4677}-\x{467A}' .
'\x{467C}-\x{4694}\x{4696}-\x{46A3}\x{46A5}-\x{46AB}\x{46AD}-\x{46D2}\x{46D4}-\x{4723}\x{4729}-\x{4732}' .
'\x{4734}-\x{4758}\x{475A}\x{475C}-\x{478B}\x{478D}\x{4791}-\x{47B1}\x{47B3}-\x{47F1}' .
'\x{47F3}-\x{480B}\x{480D}-\x{4815}\x{4817}-\x{4839}\x{483B}-\x{4870}\x{4872}-\x{487A}\x{487C}-\x{487F}' .
'\x{4883}-\x{488E}\x{4890}-\x{4896}\x{4899}-\x{48A2}\x{48A4}-\x{48B9}\x{48BB}-\x{48C8}\x{48CA}-\x{48D1}' .
'\x{48D3}-\x{48E5}\x{48E7}-\x{48F2}\x{48F4}-\x{48FF}\x{4901}-\x{4922}\x{4924}-\x{4928}\x{492A}-\x{4931}' .
'\x{4933}-\x{495B}\x{495D}-\x{4978}\x{497A}\x{497D}\x{4982}-\x{4983}\x{4985}-\x{49A8}' .
'\x{49AA}-\x{49AF}\x{49B1}-\x{49B7}\x{49B9}-\x{49BD}\x{49C1}-\x{49C7}\x{49C9}-\x{49CE}\x{49D0}-\x{49E8}' .
'\x{49EA}\x{49EC}\x{49EE}-\x{4A19}\x{4A1B}-\x{4A43}\x{4A45}-\x{4A4D}\x{4A4F}-\x{4A9E}' .
'\x{4AA0}-\x{4AA9}\x{4AAB}-\x{4B4E}\x{4B50}-\x{4B5B}\x{4B5D}-\x{4B69}\x{4B6B}-\x{4BC2}\x{4BC6}-\x{4BE8}' .
'\x{4BEA}-\x{4BFA}\x{4BFC}-\x{4C06}\x{4C08}-\x{4C2D}\x{4C2F}-\x{4C32}\x{4C34}-\x{4C35}\x{4C37}-\x{4C69}' .
'\x{4C6B}-\x{4C73}\x{4C75}-\x{4C86}\x{4C88}-\x{4C97}\x{4C99}-\x{4C9C}\x{4C9F}-\x{4CA3}\x{4CA5}-\x{4CB5}' .
'\x{4CB7}-\x{4CF8}\x{4CFA}-\x{4D27}\x{4D29}-\x{4DAC}\x{4DAE}-\x{4DB1}\x{4DB3}-\x{4DB5}\x{4E00}-\x{4E54}' .
'\x{4E56}-\x{4E89}\x{4E8B}-\x{4EEC}\x{4EEE}-\x{4FAC}\x{4FAE}-\x{503C}\x{503E}-\x{51E5}\x{51E7}-\x{5270}' .
'\x{5272}-\x{56A1}\x{56A3}-\x{5840}\x{5842}-\x{58B5}\x{58B7}-\x{58CB}\x{58CD}-\x{5BC8}\x{5BCA}-\x{5C01}' .
'\x{5C03}-\x{5C25}\x{5C27}-\x{5D5B}\x{5D5D}-\x{5F08}\x{5F0A}-\x{61F3}\x{61F5}-\x{63BA}\x{63BC}-\x{6441}' .
'\x{6443}-\x{657C}\x{657E}-\x{663E}\x{6640}-\x{66FC}\x{66FE}-\x{6728}\x{672A}-\x{6766}\x{6768}-\x{67A8}' .
'\x{67AA}-\x{685B}\x{685D}-\x{685E}\x{6860}-\x{68B9}\x{68BB}-\x{6AC8}\x{6ACA}-\x{6BB0}\x{6BB2}-\x{6C16}' .
'\x{6C18}-\x{6D9B}\x{6D9D}-\x{6E12}\x{6E14}-\x{6E8B}\x{6E8D}-\x{704D}\x{704F}-\x{7113}\x{7115}-\x{713B}' .
'\x{713D}-\x{7154}\x{7156}-\x{729F}\x{72A1}-\x{731E}\x{7320}-\x{7362}\x{7364}-\x{7533}\x{7535}-\x{7551}' .
'\x{7553}-\x{7572}\x{7574}-\x{75E8}\x{75EA}-\x{7679}\x{767B}-\x{783E}\x{7840}-\x{7A62}\x{7A64}-\x{7AC2}' .
'\x{7AC4}-\x{7B06}\x{7B08}-\x{7B79}\x{7B7B}-\x{7BCE}\x{7BD0}-\x{7D99}\x{7D9B}-\x{7E49}\x{7E4C}-\x{8132}' .
'\x{8134}\x{8136}-\x{81D2}\x{81D4}-\x{8216}\x{8218}-\x{822D}\x{822F}-\x{83B4}\x{83B6}-\x{841F}' .
'\x{8421}-\x{86CC}\x{86CE}-\x{874A}\x{874C}-\x{877E}\x{8780}-\x{8A32}\x{8A34}-\x{8B71}\x{8B73}-\x{8B8E}' .
'\x{8B90}-\x{8DE4}\x{8DE6}-\x{8E9A}\x{8E9C}-\x{8EE1}\x{8EE4}-\x{8F0B}\x{8F0D}-\x{8FB9}\x{8FBB}-\x{9038}' .
'\x{903A}-\x{9196}\x{9198}-\x{91A3}\x{91A5}-\x{91B7}\x{91B9}-\x{91C7}\x{91C9}-\x{91E0}\x{91E2}-\x{91FB}' .
'\x{91FD}-\x{922B}\x{922D}-\x{9270}\x{9272}-\x{9420}\x{9422}-\x{9664}\x{9666}-\x{9679}\x{967B}-\x{9770}' .
'\x{9772}-\x{982B}\x{982D}-\x{98ED}\x{98EF}-\x{99C4}\x{99C6}-\x{9A11}\x{9A14}-\x{9A27}\x{9A29}-\x{9D0D}' .
'\x{9D0F}-\x{9D2B}\x{9D2D}-\x{9D8E}\x{9D90}-\x{9DC5}\x{9DC7}-\x{9E77}\x{9E79}-\x{9EB8}\x{9EBB}-\x{9F20}' .
'\x{9F22}-\x{9F61}\x{9F63}-\x{9FA5}\x{FA28}]{1,20}$/iu',
    6 => '/^[\x{002d}0-9A-Za-z]{1,63}$/iu',
    7 => '/^[\x{00A1}-\x{00FF}]{1,63}$/iu',
    8 => '/^[\x{0100}-\x{017f}]{1,63}$/iu',
    9 => '/^[\x{0180}-\x{024f}]{1,63}$/iu',
    10 => '/^[\x{0250}-\x{02af}]{1,63}$/iu',
    11 => '/^[\x{02b0}-\x{02ff}]{1,63}$/iu',
    12 => '/^[\x{0300}-\x{036f}]{1,63}$/iu',
    13 => '/^[\x{0370}-\x{03ff}]{1,63}$/iu',
    14 => '/^[\x{0400}-\x{04ff}]{1,63}$/iu',
    15 => '/^[\x{0500}-\x{052f}]{1,63}$/iu',
    16 => '/^[\x{0530}-\x{058F}]{1,63}$/iu',
    17 => '/^[\x{0590}-\x{05FF}]{1,63}$/iu',
    18 => '/^[\x{0600}-\x{06FF}]{1,63}$/iu',
    19 => '/^[\x{0700}-\x{074F}]{1,63}$/iu',
    20 => '/^[\x{0780}-\x{07BF}]{1,63}$/iu',
    21 => '/^[\x{0900}-\x{097F}]{1,63}$/iu',
    22 => '/^[\x{0980}-\x{09FF}]{1,63}$/iu',
    23 => '/^[\x{0A00}-\x{0A7F}]{1,63}$/iu',
    24 => '/^[\x{0A80}-\x{0AFF}]{1,63}$/iu',
    25 => '/^[\x{0B00}-\x{0B7F}]{1,63}$/iu',
    26 => '/^[\x{0B80}-\x{0BFF}]{1,63}$/iu',
    27 => '/^[\x{0C00}-\x{0C7F}]{1,63}$/iu',
    28 => '/^[\x{0C80}-\x{0CFF}]{1,63}$/iu',
    29 => '/^[\x{0D00}-\x{0D7F}]{1,63}$/iu',
    30 => '/^[\x{0D80}-\x{0DFF}]{1,63}$/iu',
    31 => '/^[\x{0E00}-\x{0E7F}]{1,63}$/iu',
    32 => '/^[\x{0E80}-\x{0EFF}]{1,63}$/iu',
    33 => '/^[\x{0F00}-\x{0FFF}]{1,63}$/iu',
    34 => '/^[\x{1000}-\x{109F}]{1,63}$/iu',
    35 => '/^[\x{10A0}-\x{10FF}]{1,63}$/iu',
    36 => '/^[\x{1100}-\x{11FF}]{1,63}$/iu',
    37 => '/^[\x{1200}-\x{137F}]{1,63}$/iu',
    38 => '/^[\x{13A0}-\x{13FF}]{1,63}$/iu',
    39 => '/^[\x{1400}-\x{167F}]{1,63}$/iu',
    40 => '/^[\x{1680}-\x{169F}]{1,63}$/iu',
    41 => '/^[\x{16A0}-\x{16FF}]{1,63}$/iu',
    42 => '/^[\x{1700}-\x{171F}]{1,63}$/iu',
    43 => '/^[\x{1720}-\x{173F}]{1,63}$/iu',
    44 => '/^[\x{1740}-\x{175F}]{1,63}$/iu',
    45 => '/^[\x{1760}-\x{177F}]{1,63}$/iu',
    46 => '/^[\x{1780}-\x{17FF}]{1,63}$/iu',
    47 => '/^[\x{1800}-\x{18AF}]{1,63}$/iu',
    48 => '/^[\x{1E00}-\x{1EFF}]{1,63}$/iu',
    49 => '/^[\x{1F00}-\x{1FFF}]{1,63}$/iu',
    50 => '/^[\x{2070}-\x{209F}]{1,63}$/iu',
    51 => '/^[\x{2100}-\x{214F}]{1,63}$/iu',
    52 => '/^[\x{2150}-\x{218F}]{1,63}$/iu',
    53 => '/^[\x{2460}-\x{24FF}]{1,63}$/iu',
    54 => '/^[\x{2E80}-\x{2EFF}]{1,63}$/iu',
    55 => '/^[\x{2F00}-\x{2FDF}]{1,63}$/iu',
    56 => '/^[\x{2FF0}-\x{2FFF}]{1,63}$/iu',
    57 => '/^[\x{3040}-\x{309F}]{1,63}$/iu',
    58 => '/^[\x{30A0}-\x{30FF}]{1,63}$/iu',
    59 => '/^[\x{3100}-\x{312F}]{1,63}$/iu',
    60 => '/^[\x{3130}-\x{318F}]{1,63}$/iu',
    61 => '/^[\x{3190}-\x{319F}]{1,63}$/iu',
    62 => '/^[\x{31A0}-\x{31BF}]{1,63}$/iu',
    63 => '/^[\x{31F0}-\x{31FF}]{1,63}$/iu',
    64 => '/^[\x{3200}-\x{32FF}]{1,63}$/iu',
    65 => '/^[\x{3300}-\x{33FF}]{1,63}$/iu',
    66 => '/^[\x{3400}-\x{4DBF}]{1,63}$/iu',
    67 => '/^[\x{4E00}-\x{9FFF}]{1,63}$/iu',
    68 => '/^[\x{A000}-\x{A48F}]{1,63}$/iu',
    69 => '/^[\x{A490}-\x{A4CF}]{1,63}$/iu',
    70 => '/^[\x{AC00}-\x{D7AF}]{1,63}$/iu',
    73 => '/^[\x{F900}-\x{FAFF}]{1,63}$/iu',
    74 => '/^[\x{FB00}-\x{FB4F}]{1,63}$/iu',
    75 => '/^[\x{FB50}-\x{FDFF}]{1,63}$/iu',
    76 => '/^[\x{FE20}-\x{FE2F}]{1,63}$/iu',
    77 => '/^[\x{FE70}-\x{FEFF}]{1,63}$/iu',
    78 => '/^[\x{FF00}-\x{FFEF}]{1,63}$/iu',
    79 => '/^[\x{20000}-\x{2A6DF}]{1,63}$/iu',
    80 => '/^[\x{2F800}-\x{2FA1F}]{1,63}$/iu',
];
laminas-validator/src/Hostname/Biz.php000064400000752657147361032560014012 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-validator for the canonical source repository
 * @copyright https://github.com/laminas/laminas-validator/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-validator/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Validator\Hostname;

/**
 * Resource file for biz idn validation
 */
return [
    1  => '/^[\x{002d}0-9a-zäåæéöøü]{1,63}$/iu',
    2  => '/^[\x{002d}0-9a-záéíñóúü]{1,63}$/iu',
    3  => '/^[\x{002d}0-9a-záéíóöúüőű]{1,63}$/iu',
    4  => '/^[\x{002d}0-9a-záæéíðóöúýþ]{1,63}$/iu',
    5  => '/^[\x{AC00}-\x{D7A3}]{1,17}$/iu',
    6  => '/^[\x{002d}0-9a-ząčėęįšūųž]{1,63}$/iu',
    7  => '/^[\x{002d}0-9a-zāčēģīķļņōŗšūž]{1,63}$/iu',
    8  => '/^[\x{002d}0-9a-zàáä-éêñ-ôöøüčđńŋšŧž]{1,63}$/iu',
    9  => '/^[\x{002d}0-9a-zóąćęłńśźż]{1,63}$/iu',
    10 => '/^[\x{002d}0-9a-záàâãçéêíóôõú]{1,63}$/iu',
    11 => '/^[\x{002d}0-9a-z\x{3005}-\x{3007}\x{3041}-\x{3093}\x{309D}\x{309E}\x{30A1}-\x{30F6}\x{30FC}' .
          '\x{30FD}\x{30FE}\x{4E00}\x{4E01}\x{4E03}\x{4E07}\x{4E08}\x{4E09}\x{4E0A}' .
          '\x{4E0B}\x{4E0D}\x{4E0E}\x{4E10}\x{4E11}\x{4E14}\x{4E15}\x{4E16}\x{4E17}' .
          '\x{4E18}\x{4E19}\x{4E1E}\x{4E21}\x{4E26}\x{4E2A}\x{4E2D}\x{4E31}\x{4E32}' .
          '\x{4E36}\x{4E38}\x{4E39}\x{4E3B}\x{4E3C}\x{4E3F}\x{4E42}\x{4E43}\x{4E45}' .
          '\x{4E4B}\x{4E4D}\x{4E4E}\x{4E4F}\x{4E55}\x{4E56}\x{4E57}\x{4E58}\x{4E59}' .
          '\x{4E5D}\x{4E5E}\x{4E5F}\x{4E62}\x{4E71}\x{4E73}\x{4E7E}\x{4E80}\x{4E82}' .
          '\x{4E85}\x{4E86}\x{4E88}\x{4E89}\x{4E8A}\x{4E8B}\x{4E8C}\x{4E8E}\x{4E91}' .
          '\x{4E92}\x{4E94}\x{4E95}\x{4E98}\x{4E99}\x{4E9B}\x{4E9C}\x{4E9E}\x{4E9F}' .
          '\x{4EA0}\x{4EA1}\x{4EA2}\x{4EA4}\x{4EA5}\x{4EA6}\x{4EA8}\x{4EAB}\x{4EAC}' .
          '\x{4EAD}\x{4EAE}\x{4EB0}\x{4EB3}\x{4EB6}\x{4EBA}\x{4EC0}\x{4EC1}\x{4EC2}' .
          '\x{4EC4}\x{4EC6}\x{4EC7}\x{4ECA}\x{4ECB}\x{4ECD}\x{4ECE}\x{4ECF}\x{4ED4}' .
          '\x{4ED5}\x{4ED6}\x{4ED7}\x{4ED8}\x{4ED9}\x{4EDD}\x{4EDE}\x{4EDF}\x{4EE3}' .
          '\x{4EE4}\x{4EE5}\x{4EED}\x{4EEE}\x{4EF0}\x{4EF2}\x{4EF6}\x{4EF7}\x{4EFB}' .
          '\x{4F01}\x{4F09}\x{4F0A}\x{4F0D}\x{4F0E}\x{4F0F}\x{4F10}\x{4F11}\x{4F1A}' .
          '\x{4F1C}\x{4F1D}\x{4F2F}\x{4F30}\x{4F34}\x{4F36}\x{4F38}\x{4F3A}\x{4F3C}' .
          '\x{4F3D}\x{4F43}\x{4F46}\x{4F47}\x{4F4D}\x{4F4E}\x{4F4F}\x{4F50}\x{4F51}' .
          '\x{4F53}\x{4F55}\x{4F57}\x{4F59}\x{4F5A}\x{4F5B}\x{4F5C}\x{4F5D}\x{4F5E}' .
          '\x{4F69}\x{4F6F}\x{4F70}\x{4F73}\x{4F75}\x{4F76}\x{4F7B}\x{4F7C}\x{4F7F}' .
          '\x{4F83}\x{4F86}\x{4F88}\x{4F8B}\x{4F8D}\x{4F8F}\x{4F91}\x{4F96}\x{4F98}' .
          '\x{4F9B}\x{4F9D}\x{4FA0}\x{4FA1}\x{4FAB}\x{4FAD}\x{4FAE}\x{4FAF}\x{4FB5}' .
          '\x{4FB6}\x{4FBF}\x{4FC2}\x{4FC3}\x{4FC4}\x{4FCA}\x{4FCE}\x{4FD0}\x{4FD1}' .
          '\x{4FD4}\x{4FD7}\x{4FD8}\x{4FDA}\x{4FDB}\x{4FDD}\x{4FDF}\x{4FE1}\x{4FE3}' .
          '\x{4FE4}\x{4FE5}\x{4FEE}\x{4FEF}\x{4FF3}\x{4FF5}\x{4FF6}\x{4FF8}\x{4FFA}' .
          '\x{4FFE}\x{5005}\x{5006}\x{5009}\x{500B}\x{500D}\x{500F}\x{5011}\x{5012}' .
          '\x{5014}\x{5016}\x{5019}\x{501A}\x{501F}\x{5021}\x{5023}\x{5024}\x{5025}' .
          '\x{5026}\x{5028}\x{5029}\x{502A}\x{502B}\x{502C}\x{502D}\x{5036}\x{5039}' .
          '\x{5043}\x{5047}\x{5048}\x{5049}\x{504F}\x{5050}\x{5055}\x{5056}\x{505A}' .
          '\x{505C}\x{5065}\x{506C}\x{5072}\x{5074}\x{5075}\x{5076}\x{5078}\x{507D}' .
          '\x{5080}\x{5085}\x{508D}\x{5091}\x{5098}\x{5099}\x{509A}\x{50AC}\x{50AD}' .
          '\x{50B2}\x{50B3}\x{50B4}\x{50B5}\x{50B7}\x{50BE}\x{50C2}\x{50C5}\x{50C9}' .
          '\x{50CA}\x{50CD}\x{50CF}\x{50D1}\x{50D5}\x{50D6}\x{50DA}\x{50DE}\x{50E3}' .
          '\x{50E5}\x{50E7}\x{50ED}\x{50EE}\x{50F5}\x{50F9}\x{50FB}\x{5100}\x{5101}' .
          '\x{5102}\x{5104}\x{5109}\x{5112}\x{5114}\x{5115}\x{5116}\x{5118}\x{511A}' .
          '\x{511F}\x{5121}\x{512A}\x{5132}\x{5137}\x{513A}\x{513B}\x{513C}\x{513F}' .
          '\x{5140}\x{5141}\x{5143}\x{5144}\x{5145}\x{5146}\x{5147}\x{5148}\x{5149}' .
          '\x{514B}\x{514C}\x{514D}\x{514E}\x{5150}\x{5152}\x{5154}\x{515A}\x{515C}' .
          '\x{5162}\x{5165}\x{5168}\x{5169}\x{516A}\x{516B}\x{516C}\x{516D}\x{516E}' .
          '\x{5171}\x{5175}\x{5176}\x{5177}\x{5178}\x{517C}\x{5180}\x{5182}\x{5185}' .
          '\x{5186}\x{5189}\x{518A}\x{518C}\x{518D}\x{518F}\x{5190}\x{5191}\x{5192}' .
          '\x{5193}\x{5195}\x{5196}\x{5197}\x{5199}\x{51A0}\x{51A2}\x{51A4}\x{51A5}' .
          '\x{51A6}\x{51A8}\x{51A9}\x{51AA}\x{51AB}\x{51AC}\x{51B0}\x{51B1}\x{51B2}' .
          '\x{51B3}\x{51B4}\x{51B5}\x{51B6}\x{51B7}\x{51BD}\x{51C4}\x{51C5}\x{51C6}' .
          '\x{51C9}\x{51CB}\x{51CC}\x{51CD}\x{51D6}\x{51DB}\x{51DC}\x{51DD}\x{51E0}' .
          '\x{51E1}\x{51E6}\x{51E7}\x{51E9}\x{51EA}\x{51ED}\x{51F0}\x{51F1}\x{51F5}' .
          '\x{51F6}\x{51F8}\x{51F9}\x{51FA}\x{51FD}\x{51FE}\x{5200}\x{5203}\x{5204}' .
          '\x{5206}\x{5207}\x{5208}\x{520A}\x{520B}\x{520E}\x{5211}\x{5214}\x{5217}' .
          '\x{521D}\x{5224}\x{5225}\x{5227}\x{5229}\x{522A}\x{522E}\x{5230}\x{5233}' .
          '\x{5236}\x{5237}\x{5238}\x{5239}\x{523A}\x{523B}\x{5243}\x{5244}\x{5247}' .
          '\x{524A}\x{524B}\x{524C}\x{524D}\x{524F}\x{5254}\x{5256}\x{525B}\x{525E}' .
          '\x{5263}\x{5264}\x{5265}\x{5269}\x{526A}\x{526F}\x{5270}\x{5271}\x{5272}' .
          '\x{5273}\x{5274}\x{5275}\x{527D}\x{527F}\x{5283}\x{5287}\x{5288}\x{5289}' .
          '\x{528D}\x{5291}\x{5292}\x{5294}\x{529B}\x{529F}\x{52A0}\x{52A3}\x{52A9}' .
          '\x{52AA}\x{52AB}\x{52AC}\x{52AD}\x{52B1}\x{52B4}\x{52B5}\x{52B9}\x{52BC}' .
          '\x{52BE}\x{52C1}\x{52C3}\x{52C5}\x{52C7}\x{52C9}\x{52CD}\x{52D2}\x{52D5}' .
          '\x{52D7}\x{52D8}\x{52D9}\x{52DD}\x{52DE}\x{52DF}\x{52E0}\x{52E2}\x{52E3}' .
          '\x{52E4}\x{52E6}\x{52E7}\x{52F2}\x{52F3}\x{52F5}\x{52F8}\x{52F9}\x{52FA}' .
          '\x{52FE}\x{52FF}\x{5301}\x{5302}\x{5305}\x{5306}\x{5308}\x{530D}\x{530F}' .
          '\x{5310}\x{5315}\x{5316}\x{5317}\x{5319}\x{531A}\x{531D}\x{5320}\x{5321}' .
          '\x{5323}\x{532A}\x{532F}\x{5331}\x{5333}\x{5338}\x{5339}\x{533A}\x{533B}' .
          '\x{533F}\x{5340}\x{5341}\x{5343}\x{5345}\x{5346}\x{5347}\x{5348}\x{5349}' .
          '\x{534A}\x{534D}\x{5351}\x{5352}\x{5353}\x{5354}\x{5357}\x{5358}\x{535A}' .
          '\x{535C}\x{535E}\x{5360}\x{5366}\x{5369}\x{536E}\x{536F}\x{5370}\x{5371}' .
          '\x{5373}\x{5374}\x{5375}\x{5377}\x{5378}\x{537B}\x{537F}\x{5382}\x{5384}' .
          '\x{5396}\x{5398}\x{539A}\x{539F}\x{53A0}\x{53A5}\x{53A6}\x{53A8}\x{53A9}' .
          '\x{53AD}\x{53AE}\x{53B0}\x{53B3}\x{53B6}\x{53BB}\x{53C2}\x{53C3}\x{53C8}' .
          '\x{53C9}\x{53CA}\x{53CB}\x{53CC}\x{53CD}\x{53CE}\x{53D4}\x{53D6}\x{53D7}' .
          '\x{53D9}\x{53DB}\x{53DF}\x{53E1}\x{53E2}\x{53E3}\x{53E4}\x{53E5}\x{53E8}' .
          '\x{53E9}\x{53EA}\x{53EB}\x{53EC}\x{53ED}\x{53EE}\x{53EF}\x{53F0}\x{53F1}' .
          '\x{53F2}\x{53F3}\x{53F6}\x{53F7}\x{53F8}\x{53FA}\x{5401}\x{5403}\x{5404}' .
          '\x{5408}\x{5409}\x{540A}\x{540B}\x{540C}\x{540D}\x{540E}\x{540F}\x{5410}' .
          '\x{5411}\x{541B}\x{541D}\x{541F}\x{5420}\x{5426}\x{5429}\x{542B}\x{542C}' .
          '\x{542D}\x{542E}\x{5436}\x{5438}\x{5439}\x{543B}\x{543C}\x{543D}\x{543E}' .
          '\x{5440}\x{5442}\x{5446}\x{5448}\x{5449}\x{544A}\x{544E}\x{5451}\x{545F}' .
          '\x{5468}\x{546A}\x{5470}\x{5471}\x{5473}\x{5475}\x{5476}\x{5477}\x{547B}' .
          '\x{547C}\x{547D}\x{5480}\x{5484}\x{5486}\x{548B}\x{548C}\x{548E}\x{548F}' .
          '\x{5490}\x{5492}\x{54A2}\x{54A4}\x{54A5}\x{54A8}\x{54AB}\x{54AC}\x{54AF}' .
          '\x{54B2}\x{54B3}\x{54B8}\x{54BC}\x{54BD}\x{54BE}\x{54C0}\x{54C1}\x{54C2}' .
          '\x{54C4}\x{54C7}\x{54C8}\x{54C9}\x{54D8}\x{54E1}\x{54E2}\x{54E5}\x{54E6}' .
          '\x{54E8}\x{54E9}\x{54ED}\x{54EE}\x{54F2}\x{54FA}\x{54FD}\x{5504}\x{5506}' .
          '\x{5507}\x{550F}\x{5510}\x{5514}\x{5516}\x{552E}\x{552F}\x{5531}\x{5533}' .
          '\x{5538}\x{5539}\x{553E}\x{5540}\x{5544}\x{5545}\x{5546}\x{554C}\x{554F}' .
          '\x{5553}\x{5556}\x{5557}\x{555C}\x{555D}\x{5563}\x{557B}\x{557C}\x{557E}' .
          '\x{5580}\x{5583}\x{5584}\x{5587}\x{5589}\x{558A}\x{558B}\x{5598}\x{5599}' .
          '\x{559A}\x{559C}\x{559D}\x{559E}\x{559F}\x{55A7}\x{55A8}\x{55A9}\x{55AA}' .
          '\x{55AB}\x{55AC}\x{55AE}\x{55B0}\x{55B6}\x{55C4}\x{55C5}\x{55C7}\x{55D4}' .
          '\x{55DA}\x{55DC}\x{55DF}\x{55E3}\x{55E4}\x{55F7}\x{55F9}\x{55FD}\x{55FE}' .
          '\x{5606}\x{5609}\x{5614}\x{5616}\x{5617}\x{5618}\x{561B}\x{5629}\x{562F}' .
          '\x{5631}\x{5632}\x{5634}\x{5636}\x{5638}\x{5642}\x{564C}\x{564E}\x{5650}' .
          '\x{565B}\x{5664}\x{5668}\x{566A}\x{566B}\x{566C}\x{5674}\x{5678}\x{567A}' .
          '\x{5680}\x{5686}\x{5687}\x{568A}\x{568F}\x{5694}\x{56A0}\x{56A2}\x{56A5}' .
          '\x{56AE}\x{56B4}\x{56B6}\x{56BC}\x{56C0}\x{56C1}\x{56C2}\x{56C3}\x{56C8}' .
          '\x{56CE}\x{56D1}\x{56D3}\x{56D7}\x{56D8}\x{56DA}\x{56DB}\x{56DE}\x{56E0}' .
          '\x{56E3}\x{56EE}\x{56F0}\x{56F2}\x{56F3}\x{56F9}\x{56FA}\x{56FD}\x{56FF}' .
          '\x{5700}\x{5703}\x{5704}\x{5708}\x{5709}\x{570B}\x{570D}\x{570F}\x{5712}' .
          '\x{5713}\x{5716}\x{5718}\x{571C}\x{571F}\x{5726}\x{5727}\x{5728}\x{572D}' .
          '\x{5730}\x{5737}\x{5738}\x{573B}\x{5740}\x{5742}\x{5747}\x{574A}\x{574E}' .
          '\x{574F}\x{5750}\x{5751}\x{5761}\x{5764}\x{5766}\x{5769}\x{576A}\x{577F}' .
          '\x{5782}\x{5788}\x{5789}\x{578B}\x{5793}\x{57A0}\x{57A2}\x{57A3}\x{57A4}' .
          '\x{57AA}\x{57B0}\x{57B3}\x{57C0}\x{57C3}\x{57C6}\x{57CB}\x{57CE}\x{57D2}' .
          '\x{57D3}\x{57D4}\x{57D6}\x{57DC}\x{57DF}\x{57E0}\x{57E3}\x{57F4}\x{57F7}' .
          '\x{57F9}\x{57FA}\x{57FC}\x{5800}\x{5802}\x{5805}\x{5806}\x{580A}\x{580B}' .
          '\x{5815}\x{5819}\x{581D}\x{5821}\x{5824}\x{582A}\x{582F}\x{5830}\x{5831}' .
          '\x{5834}\x{5835}\x{583A}\x{583D}\x{5840}\x{5841}\x{584A}\x{584B}\x{5851}' .
          '\x{5852}\x{5854}\x{5857}\x{5858}\x{5859}\x{585A}\x{585E}\x{5862}\x{5869}' .
          '\x{586B}\x{5870}\x{5872}\x{5875}\x{5879}\x{587E}\x{5883}\x{5885}\x{5893}' .
          '\x{5897}\x{589C}\x{589F}\x{58A8}\x{58AB}\x{58AE}\x{58B3}\x{58B8}\x{58B9}' .
          '\x{58BA}\x{58BB}\x{58BE}\x{58C1}\x{58C5}\x{58C7}\x{58CA}\x{58CC}\x{58D1}' .
          '\x{58D3}\x{58D5}\x{58D7}\x{58D8}\x{58D9}\x{58DC}\x{58DE}\x{58DF}\x{58E4}' .
          '\x{58E5}\x{58EB}\x{58EC}\x{58EE}\x{58EF}\x{58F0}\x{58F1}\x{58F2}\x{58F7}' .
          '\x{58F9}\x{58FA}\x{58FB}\x{58FC}\x{58FD}\x{5902}\x{5909}\x{590A}\x{590F}' .
          '\x{5910}\x{5915}\x{5916}\x{5918}\x{5919}\x{591A}\x{591B}\x{591C}\x{5922}' .
          '\x{5925}\x{5927}\x{5929}\x{592A}\x{592B}\x{592C}\x{592D}\x{592E}\x{5931}' .
          '\x{5932}\x{5937}\x{5938}\x{593E}\x{5944}\x{5947}\x{5948}\x{5949}\x{594E}' .
          '\x{594F}\x{5950}\x{5951}\x{5954}\x{5955}\x{5957}\x{5958}\x{595A}\x{5960}' .
          '\x{5962}\x{5965}\x{5967}\x{5968}\x{5969}\x{596A}\x{596C}\x{596E}\x{5973}' .
          '\x{5974}\x{5978}\x{597D}\x{5981}\x{5982}\x{5983}\x{5984}\x{598A}\x{598D}' .
          '\x{5993}\x{5996}\x{5999}\x{599B}\x{599D}\x{59A3}\x{59A5}\x{59A8}\x{59AC}' .
          '\x{59B2}\x{59B9}\x{59BB}\x{59BE}\x{59C6}\x{59C9}\x{59CB}\x{59D0}\x{59D1}' .
          '\x{59D3}\x{59D4}\x{59D9}\x{59DA}\x{59DC}\x{59E5}\x{59E6}\x{59E8}\x{59EA}' .
          '\x{59EB}\x{59F6}\x{59FB}\x{59FF}\x{5A01}\x{5A03}\x{5A09}\x{5A11}\x{5A18}' .
          '\x{5A1A}\x{5A1C}\x{5A1F}\x{5A20}\x{5A25}\x{5A29}\x{5A2F}\x{5A35}\x{5A36}' .
          '\x{5A3C}\x{5A40}\x{5A41}\x{5A46}\x{5A49}\x{5A5A}\x{5A62}\x{5A66}\x{5A6A}' .
          '\x{5A6C}\x{5A7F}\x{5A92}\x{5A9A}\x{5A9B}\x{5ABC}\x{5ABD}\x{5ABE}\x{5AC1}' .
          '\x{5AC2}\x{5AC9}\x{5ACB}\x{5ACC}\x{5AD0}\x{5AD6}\x{5AD7}\x{5AE1}\x{5AE3}' .
          '\x{5AE6}\x{5AE9}\x{5AFA}\x{5AFB}\x{5B09}\x{5B0B}\x{5B0C}\x{5B16}\x{5B22}' .
          '\x{5B2A}\x{5B2C}\x{5B30}\x{5B32}\x{5B36}\x{5B3E}\x{5B40}\x{5B43}\x{5B45}' .
          '\x{5B50}\x{5B51}\x{5B54}\x{5B55}\x{5B57}\x{5B58}\x{5B5A}\x{5B5B}\x{5B5C}' .
          '\x{5B5D}\x{5B5F}\x{5B63}\x{5B64}\x{5B65}\x{5B66}\x{5B69}\x{5B6B}\x{5B70}' .
          '\x{5B71}\x{5B73}\x{5B75}\x{5B78}\x{5B7A}\x{5B80}\x{5B83}\x{5B85}\x{5B87}' .
          '\x{5B88}\x{5B89}\x{5B8B}\x{5B8C}\x{5B8D}\x{5B8F}\x{5B95}\x{5B97}\x{5B98}' .
          '\x{5B99}\x{5B9A}\x{5B9B}\x{5B9C}\x{5B9D}\x{5B9F}\x{5BA2}\x{5BA3}\x{5BA4}' .
          '\x{5BA5}\x{5BA6}\x{5BAE}\x{5BB0}\x{5BB3}\x{5BB4}\x{5BB5}\x{5BB6}\x{5BB8}' .
          '\x{5BB9}\x{5BBF}\x{5BC2}\x{5BC3}\x{5BC4}\x{5BC5}\x{5BC6}\x{5BC7}\x{5BC9}' .
          '\x{5BCC}\x{5BD0}\x{5BD2}\x{5BD3}\x{5BD4}\x{5BDB}\x{5BDD}\x{5BDE}\x{5BDF}' .
          '\x{5BE1}\x{5BE2}\x{5BE4}\x{5BE5}\x{5BE6}\x{5BE7}\x{5BE8}\x{5BE9}\x{5BEB}' .
          '\x{5BEE}\x{5BF0}\x{5BF3}\x{5BF5}\x{5BF6}\x{5BF8}\x{5BFA}\x{5BFE}\x{5BFF}' .
          '\x{5C01}\x{5C02}\x{5C04}\x{5C05}\x{5C06}\x{5C07}\x{5C08}\x{5C09}\x{5C0A}' .
          '\x{5C0B}\x{5C0D}\x{5C0E}\x{5C0F}\x{5C11}\x{5C13}\x{5C16}\x{5C1A}\x{5C20}' .
          '\x{5C22}\x{5C24}\x{5C28}\x{5C2D}\x{5C31}\x{5C38}\x{5C39}\x{5C3A}\x{5C3B}' .
          '\x{5C3C}\x{5C3D}\x{5C3E}\x{5C3F}\x{5C40}\x{5C41}\x{5C45}\x{5C46}\x{5C48}' .
          '\x{5C4A}\x{5C4B}\x{5C4D}\x{5C4E}\x{5C4F}\x{5C50}\x{5C51}\x{5C53}\x{5C55}' .
          '\x{5C5E}\x{5C60}\x{5C61}\x{5C64}\x{5C65}\x{5C6C}\x{5C6E}\x{5C6F}\x{5C71}' .
          '\x{5C76}\x{5C79}\x{5C8C}\x{5C90}\x{5C91}\x{5C94}\x{5CA1}\x{5CA8}\x{5CA9}' .
          '\x{5CAB}\x{5CAC}\x{5CB1}\x{5CB3}\x{5CB6}\x{5CB7}\x{5CB8}\x{5CBB}\x{5CBC}' .
          '\x{5CBE}\x{5CC5}\x{5CC7}\x{5CD9}\x{5CE0}\x{5CE1}\x{5CE8}\x{5CE9}\x{5CEA}' .
          '\x{5CED}\x{5CEF}\x{5CF0}\x{5CF6}\x{5CFA}\x{5CFB}\x{5CFD}\x{5D07}\x{5D0B}' .
          '\x{5D0E}\x{5D11}\x{5D14}\x{5D15}\x{5D16}\x{5D17}\x{5D18}\x{5D19}\x{5D1A}' .
          '\x{5D1B}\x{5D1F}\x{5D22}\x{5D29}\x{5D4B}\x{5D4C}\x{5D4E}\x{5D50}\x{5D52}' .
          '\x{5D5C}\x{5D69}\x{5D6C}\x{5D6F}\x{5D73}\x{5D76}\x{5D82}\x{5D84}\x{5D87}' .
          '\x{5D8B}\x{5D8C}\x{5D90}\x{5D9D}\x{5DA2}\x{5DAC}\x{5DAE}\x{5DB7}\x{5DBA}' .
          '\x{5DBC}\x{5DBD}\x{5DC9}\x{5DCC}\x{5DCD}\x{5DD2}\x{5DD3}\x{5DD6}\x{5DDB}' .
          '\x{5DDD}\x{5DDE}\x{5DE1}\x{5DE3}\x{5DE5}\x{5DE6}\x{5DE7}\x{5DE8}\x{5DEB}' .
          '\x{5DEE}\x{5DF1}\x{5DF2}\x{5DF3}\x{5DF4}\x{5DF5}\x{5DF7}\x{5DFB}\x{5DFD}' .
          '\x{5DFE}\x{5E02}\x{5E03}\x{5E06}\x{5E0B}\x{5E0C}\x{5E11}\x{5E16}\x{5E19}' .
          '\x{5E1A}\x{5E1B}\x{5E1D}\x{5E25}\x{5E2B}\x{5E2D}\x{5E2F}\x{5E30}\x{5E33}' .
          '\x{5E36}\x{5E37}\x{5E38}\x{5E3D}\x{5E40}\x{5E43}\x{5E44}\x{5E45}\x{5E47}' .
          '\x{5E4C}\x{5E4E}\x{5E54}\x{5E55}\x{5E57}\x{5E5F}\x{5E61}\x{5E62}\x{5E63}' .
          '\x{5E64}\x{5E72}\x{5E73}\x{5E74}\x{5E75}\x{5E76}\x{5E78}\x{5E79}\x{5E7A}' .
          '\x{5E7B}\x{5E7C}\x{5E7D}\x{5E7E}\x{5E7F}\x{5E81}\x{5E83}\x{5E84}\x{5E87}' .
          '\x{5E8A}\x{5E8F}\x{5E95}\x{5E96}\x{5E97}\x{5E9A}\x{5E9C}\x{5EA0}\x{5EA6}' .
          '\x{5EA7}\x{5EAB}\x{5EAD}\x{5EB5}\x{5EB6}\x{5EB7}\x{5EB8}\x{5EC1}\x{5EC2}' .
          '\x{5EC3}\x{5EC8}\x{5EC9}\x{5ECA}\x{5ECF}\x{5ED0}\x{5ED3}\x{5ED6}\x{5EDA}' .
          '\x{5EDB}\x{5EDD}\x{5EDF}\x{5EE0}\x{5EE1}\x{5EE2}\x{5EE3}\x{5EE8}\x{5EE9}' .
          '\x{5EEC}\x{5EF0}\x{5EF1}\x{5EF3}\x{5EF4}\x{5EF6}\x{5EF7}\x{5EF8}\x{5EFA}' .
          '\x{5EFB}\x{5EFC}\x{5EFE}\x{5EFF}\x{5F01}\x{5F03}\x{5F04}\x{5F09}\x{5F0A}' .
          '\x{5F0B}\x{5F0C}\x{5F0D}\x{5F0F}\x{5F10}\x{5F11}\x{5F13}\x{5F14}\x{5F15}' .
          '\x{5F16}\x{5F17}\x{5F18}\x{5F1B}\x{5F1F}\x{5F25}\x{5F26}\x{5F27}\x{5F29}' .
          '\x{5F2D}\x{5F2F}\x{5F31}\x{5F35}\x{5F37}\x{5F38}\x{5F3C}\x{5F3E}\x{5F41}' .
          '\x{5F48}\x{5F4A}\x{5F4C}\x{5F4E}\x{5F51}\x{5F53}\x{5F56}\x{5F57}\x{5F59}' .
          '\x{5F5C}\x{5F5D}\x{5F61}\x{5F62}\x{5F66}\x{5F69}\x{5F6A}\x{5F6B}\x{5F6C}' .
          '\x{5F6D}\x{5F70}\x{5F71}\x{5F73}\x{5F77}\x{5F79}\x{5F7C}\x{5F7F}\x{5F80}' .
          '\x{5F81}\x{5F82}\x{5F83}\x{5F84}\x{5F85}\x{5F87}\x{5F88}\x{5F8A}\x{5F8B}' .
          '\x{5F8C}\x{5F90}\x{5F91}\x{5F92}\x{5F93}\x{5F97}\x{5F98}\x{5F99}\x{5F9E}' .
          '\x{5FA0}\x{5FA1}\x{5FA8}\x{5FA9}\x{5FAA}\x{5FAD}\x{5FAE}\x{5FB3}\x{5FB4}' .
          '\x{5FB9}\x{5FBC}\x{5FBD}\x{5FC3}\x{5FC5}\x{5FCC}\x{5FCD}\x{5FD6}\x{5FD7}' .
          '\x{5FD8}\x{5FD9}\x{5FDC}\x{5FDD}\x{5FE0}\x{5FE4}\x{5FEB}\x{5FF0}\x{5FF1}' .
          '\x{5FF5}\x{5FF8}\x{5FFB}\x{5FFD}\x{5FFF}\x{600E}\x{600F}\x{6010}\x{6012}' .
          '\x{6015}\x{6016}\x{6019}\x{601B}\x{601C}\x{601D}\x{6020}\x{6021}\x{6025}' .
          '\x{6026}\x{6027}\x{6028}\x{6029}\x{602A}\x{602B}\x{602F}\x{6031}\x{603A}' .
          '\x{6041}\x{6042}\x{6043}\x{6046}\x{604A}\x{604B}\x{604D}\x{6050}\x{6052}' .
          '\x{6055}\x{6059}\x{605A}\x{605F}\x{6060}\x{6062}\x{6063}\x{6064}\x{6065}' .
          '\x{6068}\x{6069}\x{606A}\x{606B}\x{606C}\x{606D}\x{606F}\x{6070}\x{6075}' .
          '\x{6077}\x{6081}\x{6083}\x{6084}\x{6089}\x{608B}\x{608C}\x{608D}\x{6092}' .
          '\x{6094}\x{6096}\x{6097}\x{609A}\x{609B}\x{609F}\x{60A0}\x{60A3}\x{60A6}' .
          '\x{60A7}\x{60A9}\x{60AA}\x{60B2}\x{60B3}\x{60B4}\x{60B5}\x{60B6}\x{60B8}' .
          '\x{60BC}\x{60BD}\x{60C5}\x{60C6}\x{60C7}\x{60D1}\x{60D3}\x{60D8}\x{60DA}' .
          '\x{60DC}\x{60DF}\x{60E0}\x{60E1}\x{60E3}\x{60E7}\x{60E8}\x{60F0}\x{60F1}' .
          '\x{60F3}\x{60F4}\x{60F6}\x{60F7}\x{60F9}\x{60FA}\x{60FB}\x{6100}\x{6101}' .
          '\x{6103}\x{6106}\x{6108}\x{6109}\x{610D}\x{610E}\x{610F}\x{6115}\x{611A}' .
          '\x{611B}\x{611F}\x{6121}\x{6127}\x{6128}\x{612C}\x{6134}\x{613C}\x{613D}' .
          '\x{613E}\x{613F}\x{6142}\x{6144}\x{6147}\x{6148}\x{614A}\x{614B}\x{614C}' .
          '\x{614D}\x{614E}\x{6153}\x{6155}\x{6158}\x{6159}\x{615A}\x{615D}\x{615F}' .
          '\x{6162}\x{6163}\x{6165}\x{6167}\x{6168}\x{616B}\x{616E}\x{616F}\x{6170}' .
          '\x{6171}\x{6173}\x{6174}\x{6175}\x{6176}\x{6177}\x{617E}\x{6182}\x{6187}' .
          '\x{618A}\x{618E}\x{6190}\x{6191}\x{6194}\x{6196}\x{6199}\x{619A}\x{61A4}' .
          '\x{61A7}\x{61A9}\x{61AB}\x{61AC}\x{61AE}\x{61B2}\x{61B6}\x{61BA}\x{61BE}' .
          '\x{61C3}\x{61C6}\x{61C7}\x{61C8}\x{61C9}\x{61CA}\x{61CB}\x{61CC}\x{61CD}' .
          '\x{61D0}\x{61E3}\x{61E6}\x{61F2}\x{61F4}\x{61F6}\x{61F7}\x{61F8}\x{61FA}' .
          '\x{61FC}\x{61FD}\x{61FE}\x{61FF}\x{6200}\x{6208}\x{6209}\x{620A}\x{620C}' .
          '\x{620D}\x{620E}\x{6210}\x{6211}\x{6212}\x{6214}\x{6216}\x{621A}\x{621B}' .
          '\x{621D}\x{621E}\x{621F}\x{6221}\x{6226}\x{622A}\x{622E}\x{622F}\x{6230}' .
          '\x{6232}\x{6233}\x{6234}\x{6238}\x{623B}\x{623F}\x{6240}\x{6241}\x{6247}' .
          '\x{6248}\x{6249}\x{624B}\x{624D}\x{624E}\x{6253}\x{6255}\x{6258}\x{625B}' .
          '\x{625E}\x{6260}\x{6263}\x{6268}\x{626E}\x{6271}\x{6276}\x{6279}\x{627C}' .
          '\x{627E}\x{627F}\x{6280}\x{6282}\x{6283}\x{6284}\x{6289}\x{628A}\x{6291}' .
          '\x{6292}\x{6293}\x{6294}\x{6295}\x{6296}\x{6297}\x{6298}\x{629B}\x{629C}' .
          '\x{629E}\x{62AB}\x{62AC}\x{62B1}\x{62B5}\x{62B9}\x{62BB}\x{62BC}\x{62BD}' .
          '\x{62C2}\x{62C5}\x{62C6}\x{62C7}\x{62C8}\x{62C9}\x{62CA}\x{62CC}\x{62CD}' .
          '\x{62CF}\x{62D0}\x{62D1}\x{62D2}\x{62D3}\x{62D4}\x{62D7}\x{62D8}\x{62D9}' .
          '\x{62DB}\x{62DC}\x{62DD}\x{62E0}\x{62E1}\x{62EC}\x{62ED}\x{62EE}\x{62EF}' .
          '\x{62F1}\x{62F3}\x{62F5}\x{62F6}\x{62F7}\x{62FE}\x{62FF}\x{6301}\x{6302}' .
          '\x{6307}\x{6308}\x{6309}\x{630C}\x{6311}\x{6319}\x{631F}\x{6327}\x{6328}' .
          '\x{632B}\x{632F}\x{633A}\x{633D}\x{633E}\x{633F}\x{6349}\x{634C}\x{634D}' .
          '\x{634F}\x{6350}\x{6355}\x{6357}\x{635C}\x{6367}\x{6368}\x{6369}\x{636B}' .
          '\x{636E}\x{6372}\x{6376}\x{6377}\x{637A}\x{637B}\x{6380}\x{6383}\x{6388}' .
          '\x{6389}\x{638C}\x{638E}\x{638F}\x{6392}\x{6396}\x{6398}\x{639B}\x{639F}' .
          '\x{63A0}\x{63A1}\x{63A2}\x{63A3}\x{63A5}\x{63A7}\x{63A8}\x{63A9}\x{63AA}' .
          '\x{63AB}\x{63AC}\x{63B2}\x{63B4}\x{63B5}\x{63BB}\x{63BE}\x{63C0}\x{63C3}' .
          '\x{63C4}\x{63C6}\x{63C9}\x{63CF}\x{63D0}\x{63D2}\x{63D6}\x{63DA}\x{63DB}' .
          '\x{63E1}\x{63E3}\x{63E9}\x{63EE}\x{63F4}\x{63F6}\x{63FA}\x{6406}\x{640D}' .
          '\x{640F}\x{6413}\x{6416}\x{6417}\x{641C}\x{6426}\x{6428}\x{642C}\x{642D}' .
          '\x{6434}\x{6436}\x{643A}\x{643E}\x{6442}\x{644E}\x{6458}\x{6467}\x{6469}' .
          '\x{646F}\x{6476}\x{6478}\x{647A}\x{6483}\x{6488}\x{6492}\x{6493}\x{6495}' .
          '\x{649A}\x{649E}\x{64A4}\x{64A5}\x{64A9}\x{64AB}\x{64AD}\x{64AE}\x{64B0}' .
          '\x{64B2}\x{64B9}\x{64BB}\x{64BC}\x{64C1}\x{64C2}\x{64C5}\x{64C7}\x{64CD}' .
          '\x{64D2}\x{64D4}\x{64D8}\x{64DA}\x{64E0}\x{64E1}\x{64E2}\x{64E3}\x{64E6}' .
          '\x{64E7}\x{64EC}\x{64EF}\x{64F1}\x{64F2}\x{64F4}\x{64F6}\x{64FA}\x{64FD}' .
          '\x{64FE}\x{6500}\x{6505}\x{6518}\x{651C}\x{651D}\x{6523}\x{6524}\x{652A}' .
          '\x{652B}\x{652C}\x{652F}\x{6534}\x{6535}\x{6536}\x{6537}\x{6538}\x{6539}' .
          '\x{653B}\x{653E}\x{653F}\x{6545}\x{6548}\x{654D}\x{654F}\x{6551}\x{6555}' .
          '\x{6556}\x{6557}\x{6558}\x{6559}\x{655D}\x{655E}\x{6562}\x{6563}\x{6566}' .
          '\x{656C}\x{6570}\x{6572}\x{6574}\x{6575}\x{6577}\x{6578}\x{6582}\x{6583}' .
          '\x{6587}\x{6588}\x{6589}\x{658C}\x{658E}\x{6590}\x{6591}\x{6597}\x{6599}' .
          '\x{659B}\x{659C}\x{659F}\x{65A1}\x{65A4}\x{65A5}\x{65A7}\x{65AB}\x{65AC}' .
          '\x{65AD}\x{65AF}\x{65B0}\x{65B7}\x{65B9}\x{65BC}\x{65BD}\x{65C1}\x{65C3}' .
          '\x{65C4}\x{65C5}\x{65C6}\x{65CB}\x{65CC}\x{65CF}\x{65D2}\x{65D7}\x{65D9}' .
          '\x{65DB}\x{65E0}\x{65E1}\x{65E2}\x{65E5}\x{65E6}\x{65E7}\x{65E8}\x{65E9}' .
          '\x{65EC}\x{65ED}\x{65F1}\x{65FA}\x{65FB}\x{6602}\x{6603}\x{6606}\x{6607}' .
          '\x{660A}\x{660C}\x{660E}\x{660F}\x{6613}\x{6614}\x{661C}\x{661F}\x{6620}' .
          '\x{6625}\x{6627}\x{6628}\x{662D}\x{662F}\x{6634}\x{6635}\x{6636}\x{663C}' .
          '\x{663F}\x{6641}\x{6642}\x{6643}\x{6644}\x{6649}\x{664B}\x{664F}\x{6652}' .
          '\x{665D}\x{665E}\x{665F}\x{6662}\x{6664}\x{6666}\x{6667}\x{6668}\x{6669}' .
          '\x{666E}\x{666F}\x{6670}\x{6674}\x{6676}\x{667A}\x{6681}\x{6683}\x{6684}' .
          '\x{6687}\x{6688}\x{6689}\x{668E}\x{6691}\x{6696}\x{6697}\x{6698}\x{669D}' .
          '\x{66A2}\x{66A6}\x{66AB}\x{66AE}\x{66B4}\x{66B8}\x{66B9}\x{66BC}\x{66BE}' .
          '\x{66C1}\x{66C4}\x{66C7}\x{66C9}\x{66D6}\x{66D9}\x{66DA}\x{66DC}\x{66DD}' .
          '\x{66E0}\x{66E6}\x{66E9}\x{66F0}\x{66F2}\x{66F3}\x{66F4}\x{66F5}\x{66F7}' .
          '\x{66F8}\x{66F9}\x{66FC}\x{66FD}\x{66FE}\x{66FF}\x{6700}\x{6703}\x{6708}' .
          '\x{6709}\x{670B}\x{670D}\x{670F}\x{6714}\x{6715}\x{6716}\x{6717}\x{671B}' .
          '\x{671D}\x{671E}\x{671F}\x{6726}\x{6727}\x{6728}\x{672A}\x{672B}\x{672C}' .
          '\x{672D}\x{672E}\x{6731}\x{6734}\x{6736}\x{6737}\x{6738}\x{673A}\x{673D}' .
          '\x{673F}\x{6741}\x{6746}\x{6749}\x{674E}\x{674F}\x{6750}\x{6751}\x{6753}' .
          '\x{6756}\x{6759}\x{675C}\x{675E}\x{675F}\x{6760}\x{6761}\x{6762}\x{6763}' .
          '\x{6764}\x{6765}\x{676A}\x{676D}\x{676F}\x{6770}\x{6771}\x{6772}\x{6773}' .
          '\x{6775}\x{6777}\x{677C}\x{677E}\x{677F}\x{6785}\x{6787}\x{6789}\x{678B}' .
          '\x{678C}\x{6790}\x{6795}\x{6797}\x{679A}\x{679C}\x{679D}\x{67A0}\x{67A1}' .
          '\x{67A2}\x{67A6}\x{67A9}\x{67AF}\x{67B3}\x{67B4}\x{67B6}\x{67B7}\x{67B8}' .
          '\x{67B9}\x{67C1}\x{67C4}\x{67C6}\x{67CA}\x{67CE}\x{67CF}\x{67D0}\x{67D1}' .
          '\x{67D3}\x{67D4}\x{67D8}\x{67DA}\x{67DD}\x{67DE}\x{67E2}\x{67E4}\x{67E7}' .
          '\x{67E9}\x{67EC}\x{67EE}\x{67EF}\x{67F1}\x{67F3}\x{67F4}\x{67F5}\x{67FB}' .
          '\x{67FE}\x{67FF}\x{6802}\x{6803}\x{6804}\x{6813}\x{6816}\x{6817}\x{681E}' .
          '\x{6821}\x{6822}\x{6829}\x{682A}\x{682B}\x{6832}\x{6834}\x{6838}\x{6839}' .
          '\x{683C}\x{683D}\x{6840}\x{6841}\x{6842}\x{6843}\x{6846}\x{6848}\x{684D}' .
          '\x{684E}\x{6850}\x{6851}\x{6853}\x{6854}\x{6859}\x{685C}\x{685D}\x{685F}' .
          '\x{6863}\x{6867}\x{6874}\x{6876}\x{6877}\x{687E}\x{687F}\x{6881}\x{6883}' .
          '\x{6885}\x{688D}\x{688F}\x{6893}\x{6894}\x{6897}\x{689B}\x{689D}\x{689F}' .
          '\x{68A0}\x{68A2}\x{68A6}\x{68A7}\x{68A8}\x{68AD}\x{68AF}\x{68B0}\x{68B1}' .
          '\x{68B3}\x{68B5}\x{68B6}\x{68B9}\x{68BA}\x{68BC}\x{68C4}\x{68C6}\x{68C9}' .
          '\x{68CA}\x{68CB}\x{68CD}\x{68D2}\x{68D4}\x{68D5}\x{68D7}\x{68D8}\x{68DA}' .
          '\x{68DF}\x{68E0}\x{68E1}\x{68E3}\x{68E7}\x{68EE}\x{68EF}\x{68F2}\x{68F9}' .
          '\x{68FA}\x{6900}\x{6901}\x{6904}\x{6905}\x{6908}\x{690B}\x{690C}\x{690D}' .
          '\x{690E}\x{690F}\x{6912}\x{6919}\x{691A}\x{691B}\x{691C}\x{6921}\x{6922}' .
          '\x{6923}\x{6925}\x{6926}\x{6928}\x{692A}\x{6930}\x{6934}\x{6936}\x{6939}' .
          '\x{693D}\x{693F}\x{694A}\x{6953}\x{6954}\x{6955}\x{6959}\x{695A}\x{695C}' .
          '\x{695D}\x{695E}\x{6960}\x{6961}\x{6962}\x{696A}\x{696B}\x{696D}\x{696E}' .
          '\x{696F}\x{6973}\x{6974}\x{6975}\x{6977}\x{6978}\x{6979}\x{697C}\x{697D}' .
          '\x{697E}\x{6981}\x{6982}\x{698A}\x{698E}\x{6991}\x{6994}\x{6995}\x{699B}' .
          '\x{699C}\x{69A0}\x{69A7}\x{69AE}\x{69B1}\x{69B2}\x{69B4}\x{69BB}\x{69BE}' .
          '\x{69BF}\x{69C1}\x{69C3}\x{69C7}\x{69CA}\x{69CB}\x{69CC}\x{69CD}\x{69CE}' .
          '\x{69D0}\x{69D3}\x{69D8}\x{69D9}\x{69DD}\x{69DE}\x{69E7}\x{69E8}\x{69EB}' .
          '\x{69ED}\x{69F2}\x{69F9}\x{69FB}\x{69FD}\x{69FF}\x{6A02}\x{6A05}\x{6A0A}' .
          '\x{6A0B}\x{6A0C}\x{6A12}\x{6A13}\x{6A14}\x{6A17}\x{6A19}\x{6A1B}\x{6A1E}' .
          '\x{6A1F}\x{6A21}\x{6A22}\x{6A23}\x{6A29}\x{6A2A}\x{6A2B}\x{6A2E}\x{6A35}' .
          '\x{6A36}\x{6A38}\x{6A39}\x{6A3A}\x{6A3D}\x{6A44}\x{6A47}\x{6A48}\x{6A4B}' .
          '\x{6A58}\x{6A59}\x{6A5F}\x{6A61}\x{6A62}\x{6A66}\x{6A72}\x{6A78}\x{6A7F}' .
          '\x{6A80}\x{6A84}\x{6A8D}\x{6A8E}\x{6A90}\x{6A97}\x{6A9C}\x{6AA0}\x{6AA2}' .
          '\x{6AA3}\x{6AAA}\x{6AAC}\x{6AAE}\x{6AB3}\x{6AB8}\x{6ABB}\x{6AC1}\x{6AC2}' .
          '\x{6AC3}\x{6AD1}\x{6AD3}\x{6ADA}\x{6ADB}\x{6ADE}\x{6ADF}\x{6AE8}\x{6AEA}' .
          '\x{6AFA}\x{6AFB}\x{6B04}\x{6B05}\x{6B0A}\x{6B12}\x{6B16}\x{6B1D}\x{6B1F}' .
          '\x{6B20}\x{6B21}\x{6B23}\x{6B27}\x{6B32}\x{6B37}\x{6B38}\x{6B39}\x{6B3A}' .
          '\x{6B3D}\x{6B3E}\x{6B43}\x{6B47}\x{6B49}\x{6B4C}\x{6B4E}\x{6B50}\x{6B53}' .
          '\x{6B54}\x{6B59}\x{6B5B}\x{6B5F}\x{6B61}\x{6B62}\x{6B63}\x{6B64}\x{6B66}' .
          '\x{6B69}\x{6B6A}\x{6B6F}\x{6B73}\x{6B74}\x{6B78}\x{6B79}\x{6B7B}\x{6B7F}' .
          '\x{6B80}\x{6B83}\x{6B84}\x{6B86}\x{6B89}\x{6B8A}\x{6B8B}\x{6B8D}\x{6B95}' .
          '\x{6B96}\x{6B98}\x{6B9E}\x{6BA4}\x{6BAA}\x{6BAB}\x{6BAF}\x{6BB1}\x{6BB2}' .
          '\x{6BB3}\x{6BB4}\x{6BB5}\x{6BB7}\x{6BBA}\x{6BBB}\x{6BBC}\x{6BBF}\x{6BC0}' .
          '\x{6BC5}\x{6BC6}\x{6BCB}\x{6BCD}\x{6BCE}\x{6BD2}\x{6BD3}\x{6BD4}\x{6BD8}' .
          '\x{6BDB}\x{6BDF}\x{6BEB}\x{6BEC}\x{6BEF}\x{6BF3}\x{6C08}\x{6C0F}\x{6C11}' .
          '\x{6C13}\x{6C14}\x{6C17}\x{6C1B}\x{6C23}\x{6C24}\x{6C34}\x{6C37}\x{6C38}' .
          '\x{6C3E}\x{6C40}\x{6C41}\x{6C42}\x{6C4E}\x{6C50}\x{6C55}\x{6C57}\x{6C5A}' .
          '\x{6C5D}\x{6C5E}\x{6C5F}\x{6C60}\x{6C62}\x{6C68}\x{6C6A}\x{6C70}\x{6C72}' .
          '\x{6C73}\x{6C7A}\x{6C7D}\x{6C7E}\x{6C81}\x{6C82}\x{6C83}\x{6C88}\x{6C8C}' .
          '\x{6C8D}\x{6C90}\x{6C92}\x{6C93}\x{6C96}\x{6C99}\x{6C9A}\x{6C9B}\x{6CA1}' .
          '\x{6CA2}\x{6CAB}\x{6CAE}\x{6CB1}\x{6CB3}\x{6CB8}\x{6CB9}\x{6CBA}\x{6CBB}' .
          '\x{6CBC}\x{6CBD}\x{6CBE}\x{6CBF}\x{6CC1}\x{6CC4}\x{6CC5}\x{6CC9}\x{6CCA}' .
          '\x{6CCC}\x{6CD3}\x{6CD5}\x{6CD7}\x{6CD9}\x{6CDB}\x{6CDD}\x{6CE1}\x{6CE2}' .
          '\x{6CE3}\x{6CE5}\x{6CE8}\x{6CEA}\x{6CEF}\x{6CF0}\x{6CF1}\x{6CF3}\x{6D0B}' .
          '\x{6D0C}\x{6D12}\x{6D17}\x{6D19}\x{6D1B}\x{6D1E}\x{6D1F}\x{6D25}\x{6D29}' .
          '\x{6D2A}\x{6D2B}\x{6D32}\x{6D33}\x{6D35}\x{6D36}\x{6D38}\x{6D3B}\x{6D3D}' .
          '\x{6D3E}\x{6D41}\x{6D44}\x{6D45}\x{6D59}\x{6D5A}\x{6D5C}\x{6D63}\x{6D64}' .
          '\x{6D66}\x{6D69}\x{6D6A}\x{6D6C}\x{6D6E}\x{6D74}\x{6D77}\x{6D78}\x{6D79}' .
          '\x{6D85}\x{6D88}\x{6D8C}\x{6D8E}\x{6D93}\x{6D95}\x{6D99}\x{6D9B}\x{6D9C}' .
          '\x{6DAF}\x{6DB2}\x{6DB5}\x{6DB8}\x{6DBC}\x{6DC0}\x{6DC5}\x{6DC6}\x{6DC7}' .
          '\x{6DCB}\x{6DCC}\x{6DD1}\x{6DD2}\x{6DD5}\x{6DD8}\x{6DD9}\x{6DDE}\x{6DE1}' .
          '\x{6DE4}\x{6DE6}\x{6DE8}\x{6DEA}\x{6DEB}\x{6DEC}\x{6DEE}\x{6DF1}\x{6DF3}' .
          '\x{6DF5}\x{6DF7}\x{6DF9}\x{6DFA}\x{6DFB}\x{6E05}\x{6E07}\x{6E08}\x{6E09}' .
          '\x{6E0A}\x{6E0B}\x{6E13}\x{6E15}\x{6E19}\x{6E1A}\x{6E1B}\x{6E1D}\x{6E1F}' .
          '\x{6E20}\x{6E21}\x{6E23}\x{6E24}\x{6E25}\x{6E26}\x{6E29}\x{6E2B}\x{6E2C}' .
          '\x{6E2D}\x{6E2E}\x{6E2F}\x{6E38}\x{6E3A}\x{6E3E}\x{6E43}\x{6E4A}\x{6E4D}' .
          '\x{6E4E}\x{6E56}\x{6E58}\x{6E5B}\x{6E5F}\x{6E67}\x{6E6B}\x{6E6E}\x{6E6F}' .
          '\x{6E72}\x{6E76}\x{6E7E}\x{6E7F}\x{6E80}\x{6E82}\x{6E8C}\x{6E8F}\x{6E90}' .
          '\x{6E96}\x{6E98}\x{6E9C}\x{6E9D}\x{6E9F}\x{6EA2}\x{6EA5}\x{6EAA}\x{6EAF}' .
          '\x{6EB2}\x{6EB6}\x{6EB7}\x{6EBA}\x{6EBD}\x{6EC2}\x{6EC4}\x{6EC5}\x{6EC9}' .
          '\x{6ECB}\x{6ECC}\x{6ED1}\x{6ED3}\x{6ED4}\x{6ED5}\x{6EDD}\x{6EDE}\x{6EEC}' .
          '\x{6EEF}\x{6EF2}\x{6EF4}\x{6EF7}\x{6EF8}\x{6EFE}\x{6EFF}\x{6F01}\x{6F02}' .
          '\x{6F06}\x{6F09}\x{6F0F}\x{6F11}\x{6F13}\x{6F14}\x{6F15}\x{6F20}\x{6F22}' .
          '\x{6F23}\x{6F2B}\x{6F2C}\x{6F31}\x{6F32}\x{6F38}\x{6F3E}\x{6F3F}\x{6F41}' .
          '\x{6F45}\x{6F54}\x{6F58}\x{6F5B}\x{6F5C}\x{6F5F}\x{6F64}\x{6F66}\x{6F6D}' .
          '\x{6F6E}\x{6F6F}\x{6F70}\x{6F74}\x{6F78}\x{6F7A}\x{6F7C}\x{6F80}\x{6F81}' .
          '\x{6F82}\x{6F84}\x{6F86}\x{6F8E}\x{6F91}\x{6F97}\x{6FA1}\x{6FA3}\x{6FA4}' .
          '\x{6FAA}\x{6FB1}\x{6FB3}\x{6FB9}\x{6FC0}\x{6FC1}\x{6FC2}\x{6FC3}\x{6FC6}' .
          '\x{6FD4}\x{6FD5}\x{6FD8}\x{6FDB}\x{6FDF}\x{6FE0}\x{6FE1}\x{6FE4}\x{6FEB}' .
          '\x{6FEC}\x{6FEE}\x{6FEF}\x{6FF1}\x{6FF3}\x{6FF6}\x{6FFA}\x{6FFE}\x{7001}' .
          '\x{7009}\x{700B}\x{700F}\x{7011}\x{7015}\x{7018}\x{701A}\x{701B}\x{701D}' .
          '\x{701E}\x{701F}\x{7026}\x{7027}\x{702C}\x{7030}\x{7032}\x{703E}\x{704C}' .
          '\x{7051}\x{7058}\x{7063}\x{706B}\x{706F}\x{7070}\x{7078}\x{707C}\x{707D}' .
          '\x{7089}\x{708A}\x{708E}\x{7092}\x{7099}\x{70AC}\x{70AD}\x{70AE}\x{70AF}' .
          '\x{70B3}\x{70B8}\x{70B9}\x{70BA}\x{70C8}\x{70CB}\x{70CF}\x{70D9}\x{70DD}' .
          '\x{70DF}\x{70F1}\x{70F9}\x{70FD}\x{7109}\x{7114}\x{7119}\x{711A}\x{711C}' .
          '\x{7121}\x{7126}\x{7136}\x{713C}\x{7149}\x{714C}\x{714E}\x{7155}\x{7156}' .
          '\x{7159}\x{7162}\x{7164}\x{7165}\x{7166}\x{7167}\x{7169}\x{716C}\x{716E}' .
          '\x{717D}\x{7184}\x{7188}\x{718A}\x{718F}\x{7194}\x{7195}\x{7199}\x{719F}' .
          '\x{71A8}\x{71AC}\x{71B1}\x{71B9}\x{71BE}\x{71C3}\x{71C8}\x{71C9}\x{71CE}' .
          '\x{71D0}\x{71D2}\x{71D4}\x{71D5}\x{71D7}\x{71DF}\x{71E0}\x{71E5}\x{71E6}' .
          '\x{71E7}\x{71EC}\x{71ED}\x{71EE}\x{71F5}\x{71F9}\x{71FB}\x{71FC}\x{71FF}' .
          '\x{7206}\x{720D}\x{7210}\x{721B}\x{7228}\x{722A}\x{722C}\x{722D}\x{7230}' .
          '\x{7232}\x{7235}\x{7236}\x{723A}\x{723B}\x{723C}\x{723D}\x{723E}\x{723F}' .
          '\x{7240}\x{7246}\x{7247}\x{7248}\x{724B}\x{724C}\x{7252}\x{7258}\x{7259}' .
          '\x{725B}\x{725D}\x{725F}\x{7261}\x{7262}\x{7267}\x{7269}\x{7272}\x{7274}' .
          '\x{7279}\x{727D}\x{727E}\x{7280}\x{7281}\x{7282}\x{7287}\x{7292}\x{7296}' .
          '\x{72A0}\x{72A2}\x{72A7}\x{72AC}\x{72AF}\x{72B2}\x{72B6}\x{72B9}\x{72C2}' .
          '\x{72C3}\x{72C4}\x{72C6}\x{72CE}\x{72D0}\x{72D2}\x{72D7}\x{72D9}\x{72DB}' .
          '\x{72E0}\x{72E1}\x{72E2}\x{72E9}\x{72EC}\x{72ED}\x{72F7}\x{72F8}\x{72F9}' .
          '\x{72FC}\x{72FD}\x{730A}\x{7316}\x{7317}\x{731B}\x{731C}\x{731D}\x{731F}' .
          '\x{7325}\x{7329}\x{732A}\x{732B}\x{732E}\x{732F}\x{7334}\x{7336}\x{7337}' .
          '\x{733E}\x{733F}\x{7344}\x{7345}\x{734E}\x{734F}\x{7357}\x{7363}\x{7368}' .
          '\x{736A}\x{7370}\x{7372}\x{7375}\x{7378}\x{737A}\x{737B}\x{7384}\x{7387}' .
          '\x{7389}\x{738B}\x{7396}\x{73A9}\x{73B2}\x{73B3}\x{73BB}\x{73C0}\x{73C2}' .
          '\x{73C8}\x{73CA}\x{73CD}\x{73CE}\x{73DE}\x{73E0}\x{73E5}\x{73EA}\x{73ED}' .
          '\x{73EE}\x{73F1}\x{73F8}\x{73FE}\x{7403}\x{7405}\x{7406}\x{7409}\x{7422}' .
          '\x{7425}\x{7432}\x{7433}\x{7434}\x{7435}\x{7436}\x{743A}\x{743F}\x{7441}' .
          '\x{7455}\x{7459}\x{745A}\x{745B}\x{745C}\x{745E}\x{745F}\x{7460}\x{7463}' .
          '\x{7464}\x{7469}\x{746A}\x{746F}\x{7470}\x{7473}\x{7476}\x{747E}\x{7483}' .
          '\x{748B}\x{749E}\x{74A2}\x{74A7}\x{74B0}\x{74BD}\x{74CA}\x{74CF}\x{74D4}' .
          '\x{74DC}\x{74E0}\x{74E2}\x{74E3}\x{74E6}\x{74E7}\x{74E9}\x{74EE}\x{74F0}' .
          '\x{74F1}\x{74F2}\x{74F6}\x{74F7}\x{74F8}\x{7503}\x{7504}\x{7505}\x{750C}' .
          '\x{750D}\x{750E}\x{7511}\x{7513}\x{7515}\x{7518}\x{751A}\x{751C}\x{751E}' .
          '\x{751F}\x{7523}\x{7525}\x{7526}\x{7528}\x{752B}\x{752C}\x{7530}\x{7531}' .
          '\x{7532}\x{7533}\x{7537}\x{7538}\x{753A}\x{753B}\x{753C}\x{7544}\x{7546}' .
          '\x{7549}\x{754A}\x{754B}\x{754C}\x{754D}\x{754F}\x{7551}\x{7554}\x{7559}' .
          '\x{755A}\x{755B}\x{755C}\x{755D}\x{7560}\x{7562}\x{7564}\x{7565}\x{7566}' .
          '\x{7567}\x{7569}\x{756A}\x{756B}\x{756D}\x{7570}\x{7573}\x{7574}\x{7576}' .
          '\x{7577}\x{7578}\x{757F}\x{7582}\x{7586}\x{7587}\x{7589}\x{758A}\x{758B}' .
          '\x{758E}\x{758F}\x{7591}\x{7594}\x{759A}\x{759D}\x{75A3}\x{75A5}\x{75AB}' .
          '\x{75B1}\x{75B2}\x{75B3}\x{75B5}\x{75B8}\x{75B9}\x{75BC}\x{75BD}\x{75BE}' .
          '\x{75C2}\x{75C3}\x{75C5}\x{75C7}\x{75CA}\x{75CD}\x{75D2}\x{75D4}\x{75D5}' .
          '\x{75D8}\x{75D9}\x{75DB}\x{75DE}\x{75E2}\x{75E3}\x{75E9}\x{75F0}\x{75F2}' .
          '\x{75F3}\x{75F4}\x{75FA}\x{75FC}\x{75FE}\x{75FF}\x{7601}\x{7609}\x{760B}' .
          '\x{760D}\x{761F}\x{7620}\x{7621}\x{7622}\x{7624}\x{7627}\x{7630}\x{7634}' .
          '\x{763B}\x{7642}\x{7646}\x{7647}\x{7648}\x{764C}\x{7652}\x{7656}\x{7658}' .
          '\x{765C}\x{7661}\x{7662}\x{7667}\x{7668}\x{7669}\x{766A}\x{766C}\x{7670}' .
          '\x{7672}\x{7676}\x{7678}\x{767A}\x{767B}\x{767C}\x{767D}\x{767E}\x{7680}' .
          '\x{7683}\x{7684}\x{7686}\x{7687}\x{7688}\x{768B}\x{768E}\x{7690}\x{7693}' .
          '\x{7696}\x{7699}\x{769A}\x{76AE}\x{76B0}\x{76B4}\x{76B7}\x{76B8}\x{76B9}' .
          '\x{76BA}\x{76BF}\x{76C2}\x{76C3}\x{76C6}\x{76C8}\x{76CA}\x{76CD}\x{76D2}' .
          '\x{76D6}\x{76D7}\x{76DB}\x{76DC}\x{76DE}\x{76DF}\x{76E1}\x{76E3}\x{76E4}' .
          '\x{76E5}\x{76E7}\x{76EA}\x{76EE}\x{76F2}\x{76F4}\x{76F8}\x{76FB}\x{76FE}' .
          '\x{7701}\x{7704}\x{7707}\x{7708}\x{7709}\x{770B}\x{770C}\x{771B}\x{771E}' .
          '\x{771F}\x{7720}\x{7724}\x{7725}\x{7726}\x{7729}\x{7737}\x{7738}\x{773A}' .
          '\x{773C}\x{7740}\x{7747}\x{775A}\x{775B}\x{7761}\x{7763}\x{7765}\x{7766}' .
          '\x{7768}\x{776B}\x{7779}\x{777E}\x{777F}\x{778B}\x{778E}\x{7791}\x{779E}' .
          '\x{77A0}\x{77A5}\x{77AC}\x{77AD}\x{77B0}\x{77B3}\x{77B6}\x{77B9}\x{77BB}' .
          '\x{77BC}\x{77BD}\x{77BF}\x{77C7}\x{77CD}\x{77D7}\x{77DA}\x{77DB}\x{77DC}' .
          '\x{77E2}\x{77E3}\x{77E5}\x{77E7}\x{77E9}\x{77ED}\x{77EE}\x{77EF}\x{77F3}' .
          '\x{77FC}\x{7802}\x{780C}\x{7812}\x{7814}\x{7815}\x{7820}\x{7825}\x{7826}' .
          '\x{7827}\x{7832}\x{7834}\x{783A}\x{783F}\x{7845}\x{785D}\x{786B}\x{786C}' .
          '\x{786F}\x{7872}\x{7874}\x{787C}\x{7881}\x{7886}\x{7887}\x{788C}\x{788D}' .
          '\x{788E}\x{7891}\x{7893}\x{7895}\x{7897}\x{789A}\x{78A3}\x{78A7}\x{78A9}' .
          '\x{78AA}\x{78AF}\x{78B5}\x{78BA}\x{78BC}\x{78BE}\x{78C1}\x{78C5}\x{78C6}' .
          '\x{78CA}\x{78CB}\x{78D0}\x{78D1}\x{78D4}\x{78DA}\x{78E7}\x{78E8}\x{78EC}' .
          '\x{78EF}\x{78F4}\x{78FD}\x{7901}\x{7907}\x{790E}\x{7911}\x{7912}\x{7919}' .
          '\x{7926}\x{792A}\x{792B}\x{792C}\x{793A}\x{793C}\x{793E}\x{7940}\x{7941}' .
          '\x{7947}\x{7948}\x{7949}\x{7950}\x{7953}\x{7955}\x{7956}\x{7957}\x{795A}' .
          '\x{795D}\x{795E}\x{795F}\x{7960}\x{7962}\x{7965}\x{7968}\x{796D}\x{7977}' .
          '\x{797A}\x{797F}\x{7980}\x{7981}\x{7984}\x{7985}\x{798A}\x{798D}\x{798E}' .
          '\x{798F}\x{799D}\x{79A6}\x{79A7}\x{79AA}\x{79AE}\x{79B0}\x{79B3}\x{79B9}' .
          '\x{79BA}\x{79BD}\x{79BE}\x{79BF}\x{79C0}\x{79C1}\x{79C9}\x{79CB}\x{79D1}' .
          '\x{79D2}\x{79D5}\x{79D8}\x{79DF}\x{79E1}\x{79E3}\x{79E4}\x{79E6}\x{79E7}' .
          '\x{79E9}\x{79EC}\x{79F0}\x{79FB}\x{7A00}\x{7A08}\x{7A0B}\x{7A0D}\x{7A0E}' .
          '\x{7A14}\x{7A17}\x{7A18}\x{7A19}\x{7A1A}\x{7A1C}\x{7A1F}\x{7A20}\x{7A2E}' .
          '\x{7A31}\x{7A32}\x{7A37}\x{7A3B}\x{7A3C}\x{7A3D}\x{7A3E}\x{7A3F}\x{7A40}' .
          '\x{7A42}\x{7A43}\x{7A46}\x{7A49}\x{7A4D}\x{7A4E}\x{7A4F}\x{7A50}\x{7A57}' .
          '\x{7A61}\x{7A62}\x{7A63}\x{7A69}\x{7A6B}\x{7A70}\x{7A74}\x{7A76}\x{7A79}' .
          '\x{7A7A}\x{7A7D}\x{7A7F}\x{7A81}\x{7A83}\x{7A84}\x{7A88}\x{7A92}\x{7A93}' .
          '\x{7A95}\x{7A96}\x{7A97}\x{7A98}\x{7A9F}\x{7AA9}\x{7AAA}\x{7AAE}\x{7AAF}' .
          '\x{7AB0}\x{7AB6}\x{7ABA}\x{7ABF}\x{7AC3}\x{7AC4}\x{7AC5}\x{7AC7}\x{7AC8}' .
          '\x{7ACA}\x{7ACB}\x{7ACD}\x{7ACF}\x{7AD2}\x{7AD3}\x{7AD5}\x{7AD9}\x{7ADA}' .
          '\x{7ADC}\x{7ADD}\x{7ADF}\x{7AE0}\x{7AE1}\x{7AE2}\x{7AE3}\x{7AE5}\x{7AE6}' .
          '\x{7AEA}\x{7AED}\x{7AEF}\x{7AF0}\x{7AF6}\x{7AF8}\x{7AF9}\x{7AFA}\x{7AFF}' .
          '\x{7B02}\x{7B04}\x{7B06}\x{7B08}\x{7B0A}\x{7B0B}\x{7B0F}\x{7B11}\x{7B18}' .
          '\x{7B19}\x{7B1B}\x{7B1E}\x{7B20}\x{7B25}\x{7B26}\x{7B28}\x{7B2C}\x{7B33}' .
          '\x{7B35}\x{7B36}\x{7B39}\x{7B45}\x{7B46}\x{7B48}\x{7B49}\x{7B4B}\x{7B4C}' .
          '\x{7B4D}\x{7B4F}\x{7B50}\x{7B51}\x{7B52}\x{7B54}\x{7B56}\x{7B5D}\x{7B65}' .
          '\x{7B67}\x{7B6C}\x{7B6E}\x{7B70}\x{7B71}\x{7B74}\x{7B75}\x{7B7A}\x{7B86}' .
          '\x{7B87}\x{7B8B}\x{7B8D}\x{7B8F}\x{7B92}\x{7B94}\x{7B95}\x{7B97}\x{7B98}' .
          '\x{7B99}\x{7B9A}\x{7B9C}\x{7B9D}\x{7B9F}\x{7BA1}\x{7BAA}\x{7BAD}\x{7BB1}' .
          '\x{7BB4}\x{7BB8}\x{7BC0}\x{7BC1}\x{7BC4}\x{7BC6}\x{7BC7}\x{7BC9}\x{7BCB}' .
          '\x{7BCC}\x{7BCF}\x{7BDD}\x{7BE0}\x{7BE4}\x{7BE5}\x{7BE6}\x{7BE9}\x{7BED}' .
          '\x{7BF3}\x{7BF6}\x{7BF7}\x{7C00}\x{7C07}\x{7C0D}\x{7C11}\x{7C12}\x{7C13}' .
          '\x{7C14}\x{7C17}\x{7C1F}\x{7C21}\x{7C23}\x{7C27}\x{7C2A}\x{7C2B}\x{7C37}' .
          '\x{7C38}\x{7C3D}\x{7C3E}\x{7C3F}\x{7C40}\x{7C43}\x{7C4C}\x{7C4D}\x{7C4F}' .
          '\x{7C50}\x{7C54}\x{7C56}\x{7C58}\x{7C5F}\x{7C60}\x{7C64}\x{7C65}\x{7C6C}' .
          '\x{7C73}\x{7C75}\x{7C7E}\x{7C81}\x{7C82}\x{7C83}\x{7C89}\x{7C8B}\x{7C8D}' .
          '\x{7C90}\x{7C92}\x{7C95}\x{7C97}\x{7C98}\x{7C9B}\x{7C9F}\x{7CA1}\x{7CA2}' .
          '\x{7CA4}\x{7CA5}\x{7CA7}\x{7CA8}\x{7CAB}\x{7CAD}\x{7CAE}\x{7CB1}\x{7CB2}' .
          '\x{7CB3}\x{7CB9}\x{7CBD}\x{7CBE}\x{7CC0}\x{7CC2}\x{7CC5}\x{7CCA}\x{7CCE}' .
          '\x{7CD2}\x{7CD6}\x{7CD8}\x{7CDC}\x{7CDE}\x{7CDF}\x{7CE0}\x{7CE2}\x{7CE7}' .
          '\x{7CEF}\x{7CF2}\x{7CF4}\x{7CF6}\x{7CF8}\x{7CFA}\x{7CFB}\x{7CFE}\x{7D00}' .
          '\x{7D02}\x{7D04}\x{7D05}\x{7D06}\x{7D0A}\x{7D0B}\x{7D0D}\x{7D10}\x{7D14}' .
          '\x{7D15}\x{7D17}\x{7D18}\x{7D19}\x{7D1A}\x{7D1B}\x{7D1C}\x{7D20}\x{7D21}' .
          '\x{7D22}\x{7D2B}\x{7D2C}\x{7D2E}\x{7D2F}\x{7D30}\x{7D32}\x{7D33}\x{7D35}' .
          '\x{7D39}\x{7D3A}\x{7D3F}\x{7D42}\x{7D43}\x{7D44}\x{7D45}\x{7D46}\x{7D4B}' .
          '\x{7D4C}\x{7D4E}\x{7D4F}\x{7D50}\x{7D56}\x{7D5B}\x{7D5E}\x{7D61}\x{7D62}' .
          '\x{7D63}\x{7D66}\x{7D68}\x{7D6E}\x{7D71}\x{7D72}\x{7D73}\x{7D75}\x{7D76}' .
          '\x{7D79}\x{7D7D}\x{7D89}\x{7D8F}\x{7D93}\x{7D99}\x{7D9A}\x{7D9B}\x{7D9C}' .
          '\x{7D9F}\x{7DA2}\x{7DA3}\x{7DAB}\x{7DAC}\x{7DAD}\x{7DAE}\x{7DAF}\x{7DB0}' .
          '\x{7DB1}\x{7DB2}\x{7DB4}\x{7DB5}\x{7DB8}\x{7DBA}\x{7DBB}\x{7DBD}\x{7DBE}' .
          '\x{7DBF}\x{7DC7}\x{7DCA}\x{7DCB}\x{7DCF}\x{7DD1}\x{7DD2}\x{7DD5}\x{7DD8}' .
          '\x{7DDA}\x{7DDC}\x{7DDD}\x{7DDE}\x{7DE0}\x{7DE1}\x{7DE4}\x{7DE8}\x{7DE9}' .
          '\x{7DEC}\x{7DEF}\x{7DF2}\x{7DF4}\x{7DFB}\x{7E01}\x{7E04}\x{7E05}\x{7E09}' .
          '\x{7E0A}\x{7E0B}\x{7E12}\x{7E1B}\x{7E1E}\x{7E1F}\x{7E21}\x{7E22}\x{7E23}' .
          '\x{7E26}\x{7E2B}\x{7E2E}\x{7E31}\x{7E32}\x{7E35}\x{7E37}\x{7E39}\x{7E3A}' .
          '\x{7E3B}\x{7E3D}\x{7E3E}\x{7E41}\x{7E43}\x{7E46}\x{7E4A}\x{7E4B}\x{7E4D}' .
          '\x{7E54}\x{7E55}\x{7E56}\x{7E59}\x{7E5A}\x{7E5D}\x{7E5E}\x{7E66}\x{7E67}' .
          '\x{7E69}\x{7E6A}\x{7E6D}\x{7E70}\x{7E79}\x{7E7B}\x{7E7C}\x{7E7D}\x{7E7F}' .
          '\x{7E82}\x{7E83}\x{7E88}\x{7E89}\x{7E8C}\x{7E8E}\x{7E8F}\x{7E90}\x{7E92}' .
          '\x{7E93}\x{7E94}\x{7E96}\x{7E9B}\x{7E9C}\x{7F36}\x{7F38}\x{7F3A}\x{7F45}' .
          '\x{7F4C}\x{7F4D}\x{7F4E}\x{7F50}\x{7F51}\x{7F54}\x{7F55}\x{7F58}\x{7F5F}' .
          '\x{7F60}\x{7F67}\x{7F68}\x{7F69}\x{7F6A}\x{7F6B}\x{7F6E}\x{7F70}\x{7F72}' .
          '\x{7F75}\x{7F77}\x{7F78}\x{7F79}\x{7F82}\x{7F83}\x{7F85}\x{7F86}\x{7F87}' .
          '\x{7F88}\x{7F8A}\x{7F8C}\x{7F8E}\x{7F94}\x{7F9A}\x{7F9D}\x{7F9E}\x{7FA3}' .
          '\x{7FA4}\x{7FA8}\x{7FA9}\x{7FAE}\x{7FAF}\x{7FB2}\x{7FB6}\x{7FB8}\x{7FB9}' .
          '\x{7FBD}\x{7FC1}\x{7FC5}\x{7FC6}\x{7FCA}\x{7FCC}\x{7FD2}\x{7FD4}\x{7FD5}' .
          '\x{7FE0}\x{7FE1}\x{7FE6}\x{7FE9}\x{7FEB}\x{7FF0}\x{7FF3}\x{7FF9}\x{7FFB}' .
          '\x{7FFC}\x{8000}\x{8001}\x{8003}\x{8004}\x{8005}\x{8006}\x{800B}\x{800C}' .
          '\x{8010}\x{8012}\x{8015}\x{8017}\x{8018}\x{8019}\x{801C}\x{8021}\x{8028}' .
          '\x{8033}\x{8036}\x{803B}\x{803D}\x{803F}\x{8046}\x{804A}\x{8052}\x{8056}' .
          '\x{8058}\x{805A}\x{805E}\x{805F}\x{8061}\x{8062}\x{8068}\x{806F}\x{8070}' .
          '\x{8072}\x{8073}\x{8074}\x{8076}\x{8077}\x{8079}\x{807D}\x{807E}\x{807F}' .
          '\x{8084}\x{8085}\x{8086}\x{8087}\x{8089}\x{808B}\x{808C}\x{8093}\x{8096}' .
          '\x{8098}\x{809A}\x{809B}\x{809D}\x{80A1}\x{80A2}\x{80A5}\x{80A9}\x{80AA}' .
          '\x{80AC}\x{80AD}\x{80AF}\x{80B1}\x{80B2}\x{80B4}\x{80BA}\x{80C3}\x{80C4}' .
          '\x{80C6}\x{80CC}\x{80CE}\x{80D6}\x{80D9}\x{80DA}\x{80DB}\x{80DD}\x{80DE}' .
          '\x{80E1}\x{80E4}\x{80E5}\x{80EF}\x{80F1}\x{80F4}\x{80F8}\x{80FC}\x{80FD}' .
          '\x{8102}\x{8105}\x{8106}\x{8107}\x{8108}\x{8109}\x{810A}\x{811A}\x{811B}' .
          '\x{8123}\x{8129}\x{812F}\x{8131}\x{8133}\x{8139}\x{813E}\x{8146}\x{814B}' .
          '\x{814E}\x{8150}\x{8151}\x{8153}\x{8154}\x{8155}\x{815F}\x{8165}\x{8166}' .
          '\x{816B}\x{816E}\x{8170}\x{8171}\x{8174}\x{8178}\x{8179}\x{817A}\x{817F}' .
          '\x{8180}\x{8182}\x{8183}\x{8188}\x{818A}\x{818F}\x{8193}\x{8195}\x{819A}' .
          '\x{819C}\x{819D}\x{81A0}\x{81A3}\x{81A4}\x{81A8}\x{81A9}\x{81B0}\x{81B3}' .
          '\x{81B5}\x{81B8}\x{81BA}\x{81BD}\x{81BE}\x{81BF}\x{81C0}\x{81C2}\x{81C6}' .
          '\x{81C8}\x{81C9}\x{81CD}\x{81D1}\x{81D3}\x{81D8}\x{81D9}\x{81DA}\x{81DF}' .
          '\x{81E0}\x{81E3}\x{81E5}\x{81E7}\x{81E8}\x{81EA}\x{81ED}\x{81F3}\x{81F4}' .
          '\x{81FA}\x{81FB}\x{81FC}\x{81FE}\x{8201}\x{8202}\x{8205}\x{8207}\x{8208}' .
          '\x{8209}\x{820A}\x{820C}\x{820D}\x{820E}\x{8210}\x{8212}\x{8216}\x{8217}' .
          '\x{8218}\x{821B}\x{821C}\x{821E}\x{821F}\x{8229}\x{822A}\x{822B}\x{822C}' .
          '\x{822E}\x{8233}\x{8235}\x{8236}\x{8237}\x{8238}\x{8239}\x{8240}\x{8247}' .
          '\x{8258}\x{8259}\x{825A}\x{825D}\x{825F}\x{8262}\x{8264}\x{8266}\x{8268}' .
          '\x{826A}\x{826B}\x{826E}\x{826F}\x{8271}\x{8272}\x{8276}\x{8277}\x{8278}' .
          '\x{827E}\x{828B}\x{828D}\x{8292}\x{8299}\x{829D}\x{829F}\x{82A5}\x{82A6}' .
          '\x{82AB}\x{82AC}\x{82AD}\x{82AF}\x{82B1}\x{82B3}\x{82B8}\x{82B9}\x{82BB}' .
          '\x{82BD}\x{82C5}\x{82D1}\x{82D2}\x{82D3}\x{82D4}\x{82D7}\x{82D9}\x{82DB}' .
          '\x{82DC}\x{82DE}\x{82DF}\x{82E1}\x{82E3}\x{82E5}\x{82E6}\x{82E7}\x{82EB}' .
          '\x{82F1}\x{82F3}\x{82F4}\x{82F9}\x{82FA}\x{82FB}\x{8302}\x{8303}\x{8304}' .
          '\x{8305}\x{8306}\x{8309}\x{830E}\x{8316}\x{8317}\x{8318}\x{831C}\x{8323}' .
          '\x{8328}\x{832B}\x{832F}\x{8331}\x{8332}\x{8334}\x{8335}\x{8336}\x{8338}' .
          '\x{8339}\x{8340}\x{8345}\x{8349}\x{834A}\x{834F}\x{8350}\x{8352}\x{8358}' .
          '\x{8373}\x{8375}\x{8377}\x{837B}\x{837C}\x{8385}\x{8387}\x{8389}\x{838A}' .
          '\x{838E}\x{8393}\x{8396}\x{839A}\x{839E}\x{839F}\x{83A0}\x{83A2}\x{83A8}' .
          '\x{83AA}\x{83AB}\x{83B1}\x{83B5}\x{83BD}\x{83C1}\x{83C5}\x{83CA}\x{83CC}' .
          '\x{83CE}\x{83D3}\x{83D6}\x{83D8}\x{83DC}\x{83DF}\x{83E0}\x{83E9}\x{83EB}' .
          '\x{83EF}\x{83F0}\x{83F1}\x{83F2}\x{83F4}\x{83F7}\x{83FB}\x{83FD}\x{8403}' .
          '\x{8404}\x{8407}\x{840B}\x{840C}\x{840D}\x{840E}\x{8413}\x{8420}\x{8422}' .
          '\x{8429}\x{842A}\x{842C}\x{8431}\x{8435}\x{8438}\x{843C}\x{843D}\x{8446}' .
          '\x{8449}\x{844E}\x{8457}\x{845B}\x{8461}\x{8462}\x{8463}\x{8466}\x{8469}' .
          '\x{846B}\x{846C}\x{846D}\x{846E}\x{846F}\x{8471}\x{8475}\x{8477}\x{8479}' .
          '\x{847A}\x{8482}\x{8484}\x{848B}\x{8490}\x{8494}\x{8499}\x{849C}\x{849F}' .
          '\x{84A1}\x{84AD}\x{84B2}\x{84B8}\x{84B9}\x{84BB}\x{84BC}\x{84BF}\x{84C1}' .
          '\x{84C4}\x{84C6}\x{84C9}\x{84CA}\x{84CB}\x{84CD}\x{84D0}\x{84D1}\x{84D6}' .
          '\x{84D9}\x{84DA}\x{84EC}\x{84EE}\x{84F4}\x{84FC}\x{84FF}\x{8500}\x{8506}' .
          '\x{8511}\x{8513}\x{8514}\x{8515}\x{8517}\x{8518}\x{851A}\x{851F}\x{8521}' .
          '\x{8526}\x{852C}\x{852D}\x{8535}\x{853D}\x{8540}\x{8541}\x{8543}\x{8548}' .
          '\x{8549}\x{854A}\x{854B}\x{854E}\x{8555}\x{8557}\x{8558}\x{855A}\x{8563}' .
          '\x{8568}\x{8569}\x{856A}\x{856D}\x{8577}\x{857E}\x{8580}\x{8584}\x{8587}' .
          '\x{8588}\x{858A}\x{8590}\x{8591}\x{8594}\x{8597}\x{8599}\x{859B}\x{859C}' .
          '\x{85A4}\x{85A6}\x{85A8}\x{85A9}\x{85AA}\x{85AB}\x{85AC}\x{85AE}\x{85AF}' .
          '\x{85B9}\x{85BA}\x{85C1}\x{85C9}\x{85CD}\x{85CF}\x{85D0}\x{85D5}\x{85DC}' .
          '\x{85DD}\x{85E4}\x{85E5}\x{85E9}\x{85EA}\x{85F7}\x{85F9}\x{85FA}\x{85FB}' .
          '\x{85FE}\x{8602}\x{8606}\x{8607}\x{860A}\x{860B}\x{8613}\x{8616}\x{8617}' .
          '\x{861A}\x{8622}\x{862D}\x{862F}\x{8630}\x{863F}\x{864D}\x{864E}\x{8650}' .
          '\x{8654}\x{8655}\x{865A}\x{865C}\x{865E}\x{865F}\x{8667}\x{866B}\x{8671}' .
          '\x{8679}\x{867B}\x{868A}\x{868B}\x{868C}\x{8693}\x{8695}\x{86A3}\x{86A4}' .
          '\x{86A9}\x{86AA}\x{86AB}\x{86AF}\x{86B0}\x{86B6}\x{86C4}\x{86C6}\x{86C7}' .
          '\x{86C9}\x{86CB}\x{86CD}\x{86CE}\x{86D4}\x{86D9}\x{86DB}\x{86DE}\x{86DF}' .
          '\x{86E4}\x{86E9}\x{86EC}\x{86ED}\x{86EE}\x{86EF}\x{86F8}\x{86F9}\x{86FB}' .
          '\x{86FE}\x{8700}\x{8702}\x{8703}\x{8706}\x{8708}\x{8709}\x{870A}\x{870D}' .
          '\x{8711}\x{8712}\x{8718}\x{871A}\x{871C}\x{8725}\x{8729}\x{8734}\x{8737}' .
          '\x{873B}\x{873F}\x{8749}\x{874B}\x{874C}\x{874E}\x{8753}\x{8755}\x{8757}' .
          '\x{8759}\x{875F}\x{8760}\x{8763}\x{8766}\x{8768}\x{876A}\x{876E}\x{8774}' .
          '\x{8776}\x{8778}\x{877F}\x{8782}\x{878D}\x{879F}\x{87A2}\x{87AB}\x{87AF}' .
          '\x{87B3}\x{87BA}\x{87BB}\x{87BD}\x{87C0}\x{87C4}\x{87C6}\x{87C7}\x{87CB}' .
          '\x{87D0}\x{87D2}\x{87E0}\x{87EF}\x{87F2}\x{87F6}\x{87F7}\x{87F9}\x{87FB}' .
          '\x{87FE}\x{8805}\x{880D}\x{880E}\x{880F}\x{8811}\x{8815}\x{8816}\x{8821}' .
          '\x{8822}\x{8823}\x{8827}\x{8831}\x{8836}\x{8839}\x{883B}\x{8840}\x{8842}' .
          '\x{8844}\x{8846}\x{884C}\x{884D}\x{8852}\x{8853}\x{8857}\x{8859}\x{885B}' .
          '\x{885D}\x{885E}\x{8861}\x{8862}\x{8863}\x{8868}\x{886B}\x{8870}\x{8872}' .
          '\x{8875}\x{8877}\x{887D}\x{887E}\x{887F}\x{8881}\x{8882}\x{8888}\x{888B}' .
          '\x{888D}\x{8892}\x{8896}\x{8897}\x{8899}\x{889E}\x{88A2}\x{88A4}\x{88AB}' .
          '\x{88AE}\x{88B0}\x{88B1}\x{88B4}\x{88B5}\x{88B7}\x{88BF}\x{88C1}\x{88C2}' .
          '\x{88C3}\x{88C4}\x{88C5}\x{88CF}\x{88D4}\x{88D5}\x{88D8}\x{88D9}\x{88DC}' .
          '\x{88DD}\x{88DF}\x{88E1}\x{88E8}\x{88F2}\x{88F3}\x{88F4}\x{88F8}\x{88F9}' .
          '\x{88FC}\x{88FD}\x{88FE}\x{8902}\x{8904}\x{8907}\x{890A}\x{890C}\x{8910}' .
          '\x{8912}\x{8913}\x{891D}\x{891E}\x{8925}\x{892A}\x{892B}\x{8936}\x{8938}' .
          '\x{893B}\x{8941}\x{8943}\x{8944}\x{894C}\x{894D}\x{8956}\x{895E}\x{895F}' .
          '\x{8960}\x{8964}\x{8966}\x{896A}\x{896D}\x{896F}\x{8972}\x{8974}\x{8977}' .
          '\x{897E}\x{897F}\x{8981}\x{8983}\x{8986}\x{8987}\x{8988}\x{898A}\x{898B}' .
          '\x{898F}\x{8993}\x{8996}\x{8997}\x{8998}\x{899A}\x{89A1}\x{89A6}\x{89A7}' .
          '\x{89A9}\x{89AA}\x{89AC}\x{89AF}\x{89B2}\x{89B3}\x{89BA}\x{89BD}\x{89BF}' .
          '\x{89C0}\x{89D2}\x{89DA}\x{89DC}\x{89DD}\x{89E3}\x{89E6}\x{89E7}\x{89F4}' .
          '\x{89F8}\x{8A00}\x{8A02}\x{8A03}\x{8A08}\x{8A0A}\x{8A0C}\x{8A0E}\x{8A10}' .
          '\x{8A13}\x{8A16}\x{8A17}\x{8A18}\x{8A1B}\x{8A1D}\x{8A1F}\x{8A23}\x{8A25}' .
          '\x{8A2A}\x{8A2D}\x{8A31}\x{8A33}\x{8A34}\x{8A36}\x{8A3A}\x{8A3B}\x{8A3C}' .
          '\x{8A41}\x{8A46}\x{8A48}\x{8A50}\x{8A51}\x{8A52}\x{8A54}\x{8A55}\x{8A5B}' .
          '\x{8A5E}\x{8A60}\x{8A62}\x{8A63}\x{8A66}\x{8A69}\x{8A6B}\x{8A6C}\x{8A6D}' .
          '\x{8A6E}\x{8A70}\x{8A71}\x{8A72}\x{8A73}\x{8A7C}\x{8A82}\x{8A84}\x{8A85}' .
          '\x{8A87}\x{8A89}\x{8A8C}\x{8A8D}\x{8A91}\x{8A93}\x{8A95}\x{8A98}\x{8A9A}' .
          '\x{8A9E}\x{8AA0}\x{8AA1}\x{8AA3}\x{8AA4}\x{8AA5}\x{8AA6}\x{8AA8}\x{8AAC}' .
          '\x{8AAD}\x{8AB0}\x{8AB2}\x{8AB9}\x{8ABC}\x{8ABF}\x{8AC2}\x{8AC4}\x{8AC7}' .
          '\x{8ACB}\x{8ACC}\x{8ACD}\x{8ACF}\x{8AD2}\x{8AD6}\x{8ADA}\x{8ADB}\x{8ADC}' .
          '\x{8ADE}\x{8AE0}\x{8AE1}\x{8AE2}\x{8AE4}\x{8AE6}\x{8AE7}\x{8AEB}\x{8AED}' .
          '\x{8AEE}\x{8AF1}\x{8AF3}\x{8AF7}\x{8AF8}\x{8AFA}\x{8AFE}\x{8B00}\x{8B01}' .
          '\x{8B02}\x{8B04}\x{8B07}\x{8B0C}\x{8B0E}\x{8B10}\x{8B14}\x{8B16}\x{8B17}' .
          '\x{8B19}\x{8B1A}\x{8B1B}\x{8B1D}\x{8B20}\x{8B21}\x{8B26}\x{8B28}\x{8B2B}' .
          '\x{8B2C}\x{8B33}\x{8B39}\x{8B3E}\x{8B41}\x{8B49}\x{8B4C}\x{8B4E}\x{8B4F}' .
          '\x{8B56}\x{8B58}\x{8B5A}\x{8B5B}\x{8B5C}\x{8B5F}\x{8B66}\x{8B6B}\x{8B6C}' .
          '\x{8B6F}\x{8B70}\x{8B71}\x{8B72}\x{8B74}\x{8B77}\x{8B7D}\x{8B80}\x{8B83}' .
          '\x{8B8A}\x{8B8C}\x{8B8E}\x{8B90}\x{8B92}\x{8B93}\x{8B96}\x{8B99}\x{8B9A}' .
          '\x{8C37}\x{8C3A}\x{8C3F}\x{8C41}\x{8C46}\x{8C48}\x{8C4A}\x{8C4C}\x{8C4E}' .
          '\x{8C50}\x{8C55}\x{8C5A}\x{8C61}\x{8C62}\x{8C6A}\x{8C6B}\x{8C6C}\x{8C78}' .
          '\x{8C79}\x{8C7A}\x{8C7C}\x{8C82}\x{8C85}\x{8C89}\x{8C8A}\x{8C8C}\x{8C8D}' .
          '\x{8C8E}\x{8C94}\x{8C98}\x{8C9D}\x{8C9E}\x{8CA0}\x{8CA1}\x{8CA2}\x{8CA7}' .
          '\x{8CA8}\x{8CA9}\x{8CAA}\x{8CAB}\x{8CAC}\x{8CAD}\x{8CAE}\x{8CAF}\x{8CB0}' .
          '\x{8CB2}\x{8CB3}\x{8CB4}\x{8CB6}\x{8CB7}\x{8CB8}\x{8CBB}\x{8CBC}\x{8CBD}' .
          '\x{8CBF}\x{8CC0}\x{8CC1}\x{8CC2}\x{8CC3}\x{8CC4}\x{8CC7}\x{8CC8}\x{8CCA}' .
          '\x{8CCD}\x{8CCE}\x{8CD1}\x{8CD3}\x{8CDA}\x{8CDB}\x{8CDC}\x{8CDE}\x{8CE0}' .
          '\x{8CE2}\x{8CE3}\x{8CE4}\x{8CE6}\x{8CEA}\x{8CED}\x{8CFA}\x{8CFB}\x{8CFC}' .
          '\x{8CFD}\x{8D04}\x{8D05}\x{8D07}\x{8D08}\x{8D0A}\x{8D0B}\x{8D0D}\x{8D0F}' .
          '\x{8D10}\x{8D13}\x{8D14}\x{8D16}\x{8D64}\x{8D66}\x{8D67}\x{8D6B}\x{8D6D}' .
          '\x{8D70}\x{8D71}\x{8D73}\x{8D74}\x{8D77}\x{8D81}\x{8D85}\x{8D8A}\x{8D99}' .
          '\x{8DA3}\x{8DA8}\x{8DB3}\x{8DBA}\x{8DBE}\x{8DC2}\x{8DCB}\x{8DCC}\x{8DCF}' .
          '\x{8DD6}\x{8DDA}\x{8DDB}\x{8DDD}\x{8DDF}\x{8DE1}\x{8DE3}\x{8DE8}\x{8DEA}' .
          '\x{8DEB}\x{8DEF}\x{8DF3}\x{8DF5}\x{8DFC}\x{8DFF}\x{8E08}\x{8E09}\x{8E0A}' .
          '\x{8E0F}\x{8E10}\x{8E1D}\x{8E1E}\x{8E1F}\x{8E2A}\x{8E30}\x{8E34}\x{8E35}' .
          '\x{8E42}\x{8E44}\x{8E47}\x{8E48}\x{8E49}\x{8E4A}\x{8E4C}\x{8E50}\x{8E55}' .
          '\x{8E59}\x{8E5F}\x{8E60}\x{8E63}\x{8E64}\x{8E72}\x{8E74}\x{8E76}\x{8E7C}' .
          '\x{8E81}\x{8E84}\x{8E85}\x{8E87}\x{8E8A}\x{8E8B}\x{8E8D}\x{8E91}\x{8E93}' .
          '\x{8E94}\x{8E99}\x{8EA1}\x{8EAA}\x{8EAB}\x{8EAC}\x{8EAF}\x{8EB0}\x{8EB1}' .
          '\x{8EBE}\x{8EC5}\x{8EC6}\x{8EC8}\x{8ECA}\x{8ECB}\x{8ECC}\x{8ECD}\x{8ED2}' .
          '\x{8EDB}\x{8EDF}\x{8EE2}\x{8EE3}\x{8EEB}\x{8EF8}\x{8EFB}\x{8EFC}\x{8EFD}' .
          '\x{8EFE}\x{8F03}\x{8F05}\x{8F09}\x{8F0A}\x{8F0C}\x{8F12}\x{8F13}\x{8F14}' .
          '\x{8F15}\x{8F19}\x{8F1B}\x{8F1C}\x{8F1D}\x{8F1F}\x{8F26}\x{8F29}\x{8F2A}' .
          '\x{8F2F}\x{8F33}\x{8F38}\x{8F39}\x{8F3B}\x{8F3E}\x{8F3F}\x{8F42}\x{8F44}' .
          '\x{8F45}\x{8F46}\x{8F49}\x{8F4C}\x{8F4D}\x{8F4E}\x{8F57}\x{8F5C}\x{8F5F}' .
          '\x{8F61}\x{8F62}\x{8F63}\x{8F64}\x{8F9B}\x{8F9C}\x{8F9E}\x{8F9F}\x{8FA3}' .
          '\x{8FA7}\x{8FA8}\x{8FAD}\x{8FAE}\x{8FAF}\x{8FB0}\x{8FB1}\x{8FB2}\x{8FB7}' .
          '\x{8FBA}\x{8FBB}\x{8FBC}\x{8FBF}\x{8FC2}\x{8FC4}\x{8FC5}\x{8FCE}\x{8FD1}' .
          '\x{8FD4}\x{8FDA}\x{8FE2}\x{8FE5}\x{8FE6}\x{8FE9}\x{8FEA}\x{8FEB}\x{8FED}' .
          '\x{8FEF}\x{8FF0}\x{8FF4}\x{8FF7}\x{8FF8}\x{8FF9}\x{8FFA}\x{8FFD}\x{9000}' .
          '\x{9001}\x{9003}\x{9005}\x{9006}\x{900B}\x{900D}\x{900E}\x{900F}\x{9010}' .
          '\x{9011}\x{9013}\x{9014}\x{9015}\x{9016}\x{9017}\x{9019}\x{901A}\x{901D}' .
          '\x{901E}\x{901F}\x{9020}\x{9021}\x{9022}\x{9023}\x{9027}\x{902E}\x{9031}' .
          '\x{9032}\x{9035}\x{9036}\x{9038}\x{9039}\x{903C}\x{903E}\x{9041}\x{9042}' .
          '\x{9045}\x{9047}\x{9049}\x{904A}\x{904B}\x{904D}\x{904E}\x{904F}\x{9050}' .
          '\x{9051}\x{9052}\x{9053}\x{9054}\x{9055}\x{9056}\x{9058}\x{9059}\x{905C}' .
          '\x{905E}\x{9060}\x{9061}\x{9063}\x{9065}\x{9068}\x{9069}\x{906D}\x{906E}' .
          '\x{906F}\x{9072}\x{9075}\x{9076}\x{9077}\x{9078}\x{907A}\x{907C}\x{907D}' .
          '\x{907F}\x{9080}\x{9081}\x{9082}\x{9083}\x{9084}\x{9087}\x{9089}\x{908A}' .
          '\x{908F}\x{9091}\x{90A3}\x{90A6}\x{90A8}\x{90AA}\x{90AF}\x{90B1}\x{90B5}' .
          '\x{90B8}\x{90C1}\x{90CA}\x{90CE}\x{90DB}\x{90E1}\x{90E2}\x{90E4}\x{90E8}' .
          '\x{90ED}\x{90F5}\x{90F7}\x{90FD}\x{9102}\x{9112}\x{9119}\x{912D}\x{9130}' .
          '\x{9132}\x{9149}\x{914A}\x{914B}\x{914C}\x{914D}\x{914E}\x{9152}\x{9154}' .
          '\x{9156}\x{9158}\x{9162}\x{9163}\x{9165}\x{9169}\x{916A}\x{916C}\x{9172}' .
          '\x{9173}\x{9175}\x{9177}\x{9178}\x{9182}\x{9187}\x{9189}\x{918B}\x{918D}' .
          '\x{9190}\x{9192}\x{9197}\x{919C}\x{91A2}\x{91A4}\x{91AA}\x{91AB}\x{91AF}' .
          '\x{91B4}\x{91B5}\x{91B8}\x{91BA}\x{91C0}\x{91C1}\x{91C6}\x{91C7}\x{91C8}' .
          '\x{91C9}\x{91CB}\x{91CC}\x{91CD}\x{91CE}\x{91CF}\x{91D0}\x{91D1}\x{91D6}' .
          '\x{91D8}\x{91DB}\x{91DC}\x{91DD}\x{91DF}\x{91E1}\x{91E3}\x{91E6}\x{91E7}' .
          '\x{91F5}\x{91F6}\x{91FC}\x{91FF}\x{920D}\x{920E}\x{9211}\x{9214}\x{9215}' .
          '\x{921E}\x{9229}\x{922C}\x{9234}\x{9237}\x{923F}\x{9244}\x{9245}\x{9248}' .
          '\x{9249}\x{924B}\x{9250}\x{9257}\x{925A}\x{925B}\x{925E}\x{9262}\x{9264}' .
          '\x{9266}\x{9271}\x{927E}\x{9280}\x{9283}\x{9285}\x{9291}\x{9293}\x{9295}' .
          '\x{9296}\x{9298}\x{929A}\x{929B}\x{929C}\x{92AD}\x{92B7}\x{92B9}\x{92CF}' .
          '\x{92D2}\x{92E4}\x{92E9}\x{92EA}\x{92ED}\x{92F2}\x{92F3}\x{92F8}\x{92FA}' .
          '\x{92FC}\x{9306}\x{930F}\x{9310}\x{9318}\x{9319}\x{931A}\x{9320}\x{9322}' .
          '\x{9323}\x{9326}\x{9328}\x{932B}\x{932C}\x{932E}\x{932F}\x{9332}\x{9335}' .
          '\x{933A}\x{933B}\x{9344}\x{934B}\x{934D}\x{9354}\x{9356}\x{935B}\x{935C}' .
          '\x{9360}\x{936C}\x{936E}\x{9375}\x{937C}\x{937E}\x{938C}\x{9394}\x{9396}' .
          '\x{9397}\x{939A}\x{93A7}\x{93AC}\x{93AD}\x{93AE}\x{93B0}\x{93B9}\x{93C3}' .
          '\x{93C8}\x{93D0}\x{93D1}\x{93D6}\x{93D7}\x{93D8}\x{93DD}\x{93E1}\x{93E4}' .
          '\x{93E5}\x{93E8}\x{9403}\x{9407}\x{9410}\x{9413}\x{9414}\x{9418}\x{9419}' .
          '\x{941A}\x{9421}\x{942B}\x{9435}\x{9436}\x{9438}\x{943A}\x{9441}\x{9444}' .
          '\x{9451}\x{9452}\x{9453}\x{945A}\x{945B}\x{945E}\x{9460}\x{9462}\x{946A}' .
          '\x{9470}\x{9475}\x{9477}\x{947C}\x{947D}\x{947E}\x{947F}\x{9481}\x{9577}' .
          '\x{9580}\x{9582}\x{9583}\x{9587}\x{9589}\x{958A}\x{958B}\x{958F}\x{9591}' .
          '\x{9593}\x{9594}\x{9596}\x{9598}\x{9599}\x{95A0}\x{95A2}\x{95A3}\x{95A4}' .
          '\x{95A5}\x{95A7}\x{95A8}\x{95AD}\x{95B2}\x{95B9}\x{95BB}\x{95BC}\x{95BE}' .
          '\x{95C3}\x{95C7}\x{95CA}\x{95CC}\x{95CD}\x{95D4}\x{95D5}\x{95D6}\x{95D8}' .
          '\x{95DC}\x{95E1}\x{95E2}\x{95E5}\x{961C}\x{9621}\x{9628}\x{962A}\x{962E}' .
          '\x{962F}\x{9632}\x{963B}\x{963F}\x{9640}\x{9642}\x{9644}\x{964B}\x{964C}' .
          '\x{964D}\x{964F}\x{9650}\x{965B}\x{965C}\x{965D}\x{965E}\x{965F}\x{9662}' .
          '\x{9663}\x{9664}\x{9665}\x{9666}\x{966A}\x{966C}\x{9670}\x{9672}\x{9673}' .
          '\x{9675}\x{9676}\x{9677}\x{9678}\x{967A}\x{967D}\x{9685}\x{9686}\x{9688}' .
          '\x{968A}\x{968B}\x{968D}\x{968E}\x{968F}\x{9694}\x{9695}\x{9697}\x{9698}' .
          '\x{9699}\x{969B}\x{969C}\x{96A0}\x{96A3}\x{96A7}\x{96A8}\x{96AA}\x{96B0}' .
          '\x{96B1}\x{96B2}\x{96B4}\x{96B6}\x{96B7}\x{96B8}\x{96B9}\x{96BB}\x{96BC}' .
          '\x{96C0}\x{96C1}\x{96C4}\x{96C5}\x{96C6}\x{96C7}\x{96C9}\x{96CB}\x{96CC}' .
          '\x{96CD}\x{96CE}\x{96D1}\x{96D5}\x{96D6}\x{96D9}\x{96DB}\x{96DC}\x{96E2}' .
          '\x{96E3}\x{96E8}\x{96EA}\x{96EB}\x{96F0}\x{96F2}\x{96F6}\x{96F7}\x{96F9}' .
          '\x{96FB}\x{9700}\x{9704}\x{9706}\x{9707}\x{9708}\x{970A}\x{970D}\x{970E}' .
          '\x{970F}\x{9711}\x{9713}\x{9716}\x{9719}\x{971C}\x{971E}\x{9724}\x{9727}' .
          '\x{972A}\x{9730}\x{9732}\x{9738}\x{9739}\x{973D}\x{973E}\x{9742}\x{9744}' .
          '\x{9746}\x{9748}\x{9749}\x{9752}\x{9756}\x{9759}\x{975C}\x{975E}\x{9760}' .
          '\x{9761}\x{9762}\x{9764}\x{9766}\x{9768}\x{9769}\x{976B}\x{976D}\x{9771}' .
          '\x{9774}\x{9779}\x{977A}\x{977C}\x{9781}\x{9784}\x{9785}\x{9786}\x{978B}' .
          '\x{978D}\x{978F}\x{9790}\x{9798}\x{979C}\x{97A0}\x{97A3}\x{97A6}\x{97A8}' .
          '\x{97AB}\x{97AD}\x{97B3}\x{97B4}\x{97C3}\x{97C6}\x{97C8}\x{97CB}\x{97D3}' .
          '\x{97DC}\x{97ED}\x{97EE}\x{97F2}\x{97F3}\x{97F5}\x{97F6}\x{97FB}\x{97FF}' .
          '\x{9801}\x{9802}\x{9803}\x{9805}\x{9806}\x{9808}\x{980C}\x{980F}\x{9810}' .
          '\x{9811}\x{9812}\x{9813}\x{9817}\x{9818}\x{981A}\x{9821}\x{9824}\x{982C}' .
          '\x{982D}\x{9834}\x{9837}\x{9838}\x{983B}\x{983C}\x{983D}\x{9846}\x{984B}' .
          '\x{984C}\x{984D}\x{984E}\x{984F}\x{9854}\x{9855}\x{9858}\x{985B}\x{985E}' .
          '\x{9867}\x{986B}\x{986F}\x{9870}\x{9871}\x{9873}\x{9874}\x{98A8}\x{98AA}' .
          '\x{98AF}\x{98B1}\x{98B6}\x{98C3}\x{98C4}\x{98C6}\x{98DB}\x{98DC}\x{98DF}' .
          '\x{98E2}\x{98E9}\x{98EB}\x{98ED}\x{98EE}\x{98EF}\x{98F2}\x{98F4}\x{98FC}' .
          '\x{98FD}\x{98FE}\x{9903}\x{9905}\x{9909}\x{990A}\x{990C}\x{9910}\x{9912}' .
          '\x{9913}\x{9914}\x{9918}\x{991D}\x{991E}\x{9920}\x{9921}\x{9924}\x{9928}' .
          '\x{992C}\x{992E}\x{993D}\x{993E}\x{9942}\x{9945}\x{9949}\x{994B}\x{994C}' .
          '\x{9950}\x{9951}\x{9952}\x{9955}\x{9957}\x{9996}\x{9997}\x{9998}\x{9999}' .
          '\x{99A5}\x{99A8}\x{99AC}\x{99AD}\x{99AE}\x{99B3}\x{99B4}\x{99BC}\x{99C1}' .
          '\x{99C4}\x{99C5}\x{99C6}\x{99C8}\x{99D0}\x{99D1}\x{99D2}\x{99D5}\x{99D8}' .
          '\x{99DB}\x{99DD}\x{99DF}\x{99E2}\x{99ED}\x{99EE}\x{99F1}\x{99F2}\x{99F8}' .
          '\x{99FB}\x{99FF}\x{9A01}\x{9A05}\x{9A0E}\x{9A0F}\x{9A12}\x{9A13}\x{9A19}' .
          '\x{9A28}\x{9A2B}\x{9A30}\x{9A37}\x{9A3E}\x{9A40}\x{9A42}\x{9A43}\x{9A45}' .
          '\x{9A4D}\x{9A55}\x{9A57}\x{9A5A}\x{9A5B}\x{9A5F}\x{9A62}\x{9A64}\x{9A65}' .
          '\x{9A69}\x{9A6A}\x{9A6B}\x{9AA8}\x{9AAD}\x{9AB0}\x{9AB8}\x{9ABC}\x{9AC0}' .
          '\x{9AC4}\x{9ACF}\x{9AD1}\x{9AD3}\x{9AD4}\x{9AD8}\x{9ADE}\x{9ADF}\x{9AE2}' .
          '\x{9AE3}\x{9AE6}\x{9AEA}\x{9AEB}\x{9AED}\x{9AEE}\x{9AEF}\x{9AF1}\x{9AF4}' .
          '\x{9AF7}\x{9AFB}\x{9B06}\x{9B18}\x{9B1A}\x{9B1F}\x{9B22}\x{9B23}\x{9B25}' .
          '\x{9B27}\x{9B28}\x{9B29}\x{9B2A}\x{9B2E}\x{9B2F}\x{9B31}\x{9B32}\x{9B3B}' .
          '\x{9B3C}\x{9B41}\x{9B42}\x{9B43}\x{9B44}\x{9B45}\x{9B4D}\x{9B4E}\x{9B4F}' .
          '\x{9B51}\x{9B54}\x{9B58}\x{9B5A}\x{9B6F}\x{9B74}\x{9B83}\x{9B8E}\x{9B91}' .
          '\x{9B92}\x{9B93}\x{9B96}\x{9B97}\x{9B9F}\x{9BA0}\x{9BA8}\x{9BAA}\x{9BAB}' .
          '\x{9BAD}\x{9BAE}\x{9BB4}\x{9BB9}\x{9BC0}\x{9BC6}\x{9BC9}\x{9BCA}\x{9BCF}' .
          '\x{9BD1}\x{9BD2}\x{9BD4}\x{9BD6}\x{9BDB}\x{9BE1}\x{9BE2}\x{9BE3}\x{9BE4}' .
          '\x{9BE8}\x{9BF0}\x{9BF1}\x{9BF2}\x{9BF5}\x{9C04}\x{9C06}\x{9C08}\x{9C09}' .
          '\x{9C0A}\x{9C0C}\x{9C0D}\x{9C10}\x{9C12}\x{9C13}\x{9C14}\x{9C15}\x{9C1B}' .
          '\x{9C21}\x{9C24}\x{9C25}\x{9C2D}\x{9C2E}\x{9C2F}\x{9C30}\x{9C32}\x{9C39}' .
          '\x{9C3A}\x{9C3B}\x{9C3E}\x{9C46}\x{9C47}\x{9C48}\x{9C52}\x{9C57}\x{9C5A}' .
          '\x{9C60}\x{9C67}\x{9C76}\x{9C78}\x{9CE5}\x{9CE7}\x{9CE9}\x{9CEB}\x{9CEC}' .
          '\x{9CF0}\x{9CF3}\x{9CF4}\x{9CF6}\x{9D03}\x{9D06}\x{9D07}\x{9D08}\x{9D09}' .
          '\x{9D0E}\x{9D12}\x{9D15}\x{9D1B}\x{9D1F}\x{9D23}\x{9D26}\x{9D28}\x{9D2A}' .
          '\x{9D2B}\x{9D2C}\x{9D3B}\x{9D3E}\x{9D3F}\x{9D41}\x{9D44}\x{9D46}\x{9D48}' .
          '\x{9D50}\x{9D51}\x{9D59}\x{9D5C}\x{9D5D}\x{9D5E}\x{9D60}\x{9D61}\x{9D64}' .
          '\x{9D6C}\x{9D6F}\x{9D72}\x{9D7A}\x{9D87}\x{9D89}\x{9D8F}\x{9D9A}\x{9DA4}' .
          '\x{9DA9}\x{9DAB}\x{9DAF}\x{9DB2}\x{9DB4}\x{9DB8}\x{9DBA}\x{9DBB}\x{9DC1}' .
          '\x{9DC2}\x{9DC4}\x{9DC6}\x{9DCF}\x{9DD3}\x{9DD9}\x{9DE6}\x{9DED}\x{9DEF}' .
          '\x{9DF2}\x{9DF8}\x{9DF9}\x{9DFA}\x{9DFD}\x{9E1A}\x{9E1B}\x{9E1E}\x{9E75}' .
          '\x{9E78}\x{9E79}\x{9E7D}\x{9E7F}\x{9E81}\x{9E88}\x{9E8B}\x{9E8C}\x{9E91}' .
          '\x{9E92}\x{9E93}\x{9E95}\x{9E97}\x{9E9D}\x{9E9F}\x{9EA5}\x{9EA6}\x{9EA9}' .
          '\x{9EAA}\x{9EAD}\x{9EB8}\x{9EB9}\x{9EBA}\x{9EBB}\x{9EBC}\x{9EBE}\x{9EBF}' .
          '\x{9EC4}\x{9ECC}\x{9ECD}\x{9ECE}\x{9ECF}\x{9ED0}\x{9ED2}\x{9ED4}\x{9ED8}' .
          '\x{9ED9}\x{9EDB}\x{9EDC}\x{9EDD}\x{9EDE}\x{9EE0}\x{9EE5}\x{9EE8}\x{9EEF}' .
          '\x{9EF4}\x{9EF6}\x{9EF7}\x{9EF9}\x{9EFB}\x{9EFC}\x{9EFD}\x{9F07}\x{9F08}' .
          '\x{9F0E}\x{9F13}\x{9F15}\x{9F20}\x{9F21}\x{9F2C}\x{9F3B}\x{9F3E}\x{9F4A}' .
          '\x{9F4B}\x{9F4E}\x{9F4F}\x{9F52}\x{9F54}\x{9F5F}\x{9F60}\x{9F61}\x{9F62}' .
          '\x{9F63}\x{9F66}\x{9F67}\x{9F6A}\x{9F6C}\x{9F72}\x{9F76}\x{9F77}\x{9F8D}' .
          '\x{9F95}\x{9F9C}\x{9F9D}\x{9FA0}]{1,15}$/iu',
    12 => '/^[\x{002d}0-9a-z\x{3447}\x{3473}\x{359E}\x{360E}\x{361A}\x{3918}\x{396E}\x{39CF}\x{39D0}' .
          '\x{39DF}\x{3A73}\x{3B4E}\x{3C6E}\x{3CE0}\x{4056}\x{415F}\x{4337}\x{43AC}' .
          '\x{43B1}\x{43DD}\x{44D6}\x{464C}\x{4661}\x{4723}\x{4729}\x{477C}\x{478D}' .
          '\x{4947}\x{497A}\x{497D}\x{4982}\x{4983}\x{4985}\x{4986}\x{499B}\x{499F}' .
          '\x{49B6}\x{49B7}\x{4C77}\x{4C9F}\x{4CA0}\x{4CA1}\x{4CA2}\x{4CA3}\x{4D13}' .
          '\x{4D14}\x{4D15}\x{4D16}\x{4D17}\x{4D18}\x{4D19}\x{4DAE}\x{4E00}\x{4E01}' .
          '\x{4E02}\x{4E03}\x{4E04}\x{4E05}\x{4E06}\x{4E07}\x{4E08}\x{4E09}\x{4E0A}' .
          '\x{4E0B}\x{4E0C}\x{4E0D}\x{4E0E}\x{4E0F}\x{4E10}\x{4E11}\x{4E13}\x{4E14}' .
          '\x{4E15}\x{4E16}\x{4E17}\x{4E18}\x{4E19}\x{4E1A}\x{4E1B}\x{4E1C}\x{4E1D}' .
          '\x{4E1E}\x{4E1F}\x{4E20}\x{4E21}\x{4E22}\x{4E23}\x{4E24}\x{4E25}\x{4E26}' .
          '\x{4E27}\x{4E28}\x{4E2A}\x{4E2B}\x{4E2C}\x{4E2D}\x{4E2E}\x{4E2F}\x{4E30}' .
          '\x{4E31}\x{4E32}\x{4E33}\x{4E34}\x{4E35}\x{4E36}\x{4E37}\x{4E38}\x{4E39}' .
          '\x{4E3A}\x{4E3B}\x{4E3C}\x{4E3D}\x{4E3E}\x{4E3F}\x{4E40}\x{4E41}\x{4E42}' .
          '\x{4E43}\x{4E44}\x{4E45}\x{4E46}\x{4E47}\x{4E48}\x{4E49}\x{4E4A}\x{4E4B}' .
          '\x{4E4C}\x{4E4D}\x{4E4E}\x{4E4F}\x{4E50}\x{4E51}\x{4E52}\x{4E53}\x{4E54}' .
          '\x{4E56}\x{4E57}\x{4E58}\x{4E59}\x{4E5A}\x{4E5B}\x{4E5C}\x{4E5D}\x{4E5E}' .
          '\x{4E5F}\x{4E60}\x{4E61}\x{4E62}\x{4E63}\x{4E64}\x{4E65}\x{4E66}\x{4E67}' .
          '\x{4E69}\x{4E6A}\x{4E6B}\x{4E6C}\x{4E6D}\x{4E6E}\x{4E6F}\x{4E70}\x{4E71}' .
          '\x{4E72}\x{4E73}\x{4E74}\x{4E75}\x{4E76}\x{4E77}\x{4E78}\x{4E7A}\x{4E7B}' .
          '\x{4E7C}\x{4E7D}\x{4E7E}\x{4E7F}\x{4E80}\x{4E81}\x{4E82}\x{4E83}\x{4E84}' .
          '\x{4E85}\x{4E86}\x{4E87}\x{4E88}\x{4E89}\x{4E8B}\x{4E8C}\x{4E8D}\x{4E8E}' .
          '\x{4E8F}\x{4E90}\x{4E91}\x{4E92}\x{4E93}\x{4E94}\x{4E95}\x{4E97}\x{4E98}' .
          '\x{4E99}\x{4E9A}\x{4E9B}\x{4E9C}\x{4E9D}\x{4E9E}\x{4E9F}\x{4EA0}\x{4EA1}' .
          '\x{4EA2}\x{4EA4}\x{4EA5}\x{4EA6}\x{4EA7}\x{4EA8}\x{4EA9}\x{4EAA}\x{4EAB}' .
          '\x{4EAC}\x{4EAD}\x{4EAE}\x{4EAF}\x{4EB0}\x{4EB1}\x{4EB2}\x{4EB3}\x{4EB4}' .
          '\x{4EB5}\x{4EB6}\x{4EB7}\x{4EB8}\x{4EB9}\x{4EBA}\x{4EBB}\x{4EBD}\x{4EBE}' .
          '\x{4EBF}\x{4EC0}\x{4EC1}\x{4EC2}\x{4EC3}\x{4EC4}\x{4EC5}\x{4EC6}\x{4EC7}' .
          '\x{4EC8}\x{4EC9}\x{4ECA}\x{4ECB}\x{4ECD}\x{4ECE}\x{4ECF}\x{4ED0}\x{4ED1}' .
          '\x{4ED2}\x{4ED3}\x{4ED4}\x{4ED5}\x{4ED6}\x{4ED7}\x{4ED8}\x{4ED9}\x{4EDA}' .
          '\x{4EDB}\x{4EDC}\x{4EDD}\x{4EDE}\x{4EDF}\x{4EE0}\x{4EE1}\x{4EE2}\x{4EE3}' .
          '\x{4EE4}\x{4EE5}\x{4EE6}\x{4EE8}\x{4EE9}\x{4EEA}\x{4EEB}\x{4EEC}\x{4EEF}' .
          '\x{4EF0}\x{4EF1}\x{4EF2}\x{4EF3}\x{4EF4}\x{4EF5}\x{4EF6}\x{4EF7}\x{4EFB}' .
          '\x{4EFD}\x{4EFF}\x{4F00}\x{4F01}\x{4F02}\x{4F03}\x{4F04}\x{4F05}\x{4F06}' .
          '\x{4F08}\x{4F09}\x{4F0A}\x{4F0B}\x{4F0C}\x{4F0D}\x{4F0E}\x{4F0F}\x{4F10}' .
          '\x{4F11}\x{4F12}\x{4F13}\x{4F14}\x{4F15}\x{4F17}\x{4F18}\x{4F19}\x{4F1A}' .
          '\x{4F1B}\x{4F1C}\x{4F1D}\x{4F1E}\x{4F1F}\x{4F20}\x{4F21}\x{4F22}\x{4F23}' .
          '\x{4F24}\x{4F25}\x{4F26}\x{4F27}\x{4F29}\x{4F2A}\x{4F2B}\x{4F2C}\x{4F2D}' .
          '\x{4F2E}\x{4F2F}\x{4F30}\x{4F32}\x{4F33}\x{4F34}\x{4F36}\x{4F38}\x{4F39}' .
          '\x{4F3A}\x{4F3B}\x{4F3C}\x{4F3D}\x{4F3E}\x{4F3F}\x{4F41}\x{4F42}\x{4F43}' .
          '\x{4F45}\x{4F46}\x{4F47}\x{4F48}\x{4F49}\x{4F4A}\x{4F4B}\x{4F4C}\x{4F4D}' .
          '\x{4F4E}\x{4F4F}\x{4F50}\x{4F51}\x{4F52}\x{4F53}\x{4F54}\x{4F55}\x{4F56}' .
          '\x{4F57}\x{4F58}\x{4F59}\x{4F5A}\x{4F5B}\x{4F5C}\x{4F5D}\x{4F5E}\x{4F5F}' .
          '\x{4F60}\x{4F61}\x{4F62}\x{4F63}\x{4F64}\x{4F65}\x{4F66}\x{4F67}\x{4F68}' .
          '\x{4F69}\x{4F6A}\x{4F6B}\x{4F6C}\x{4F6D}\x{4F6E}\x{4F6F}\x{4F70}\x{4F72}' .
          '\x{4F73}\x{4F74}\x{4F75}\x{4F76}\x{4F77}\x{4F78}\x{4F79}\x{4F7A}\x{4F7B}' .
          '\x{4F7C}\x{4F7D}\x{4F7E}\x{4F7F}\x{4F80}\x{4F81}\x{4F82}\x{4F83}\x{4F84}' .
          '\x{4F85}\x{4F86}\x{4F87}\x{4F88}\x{4F89}\x{4F8A}\x{4F8B}\x{4F8D}\x{4F8F}' .
          '\x{4F90}\x{4F91}\x{4F92}\x{4F93}\x{4F94}\x{4F95}\x{4F96}\x{4F97}\x{4F98}' .
          '\x{4F99}\x{4F9A}\x{4F9B}\x{4F9C}\x{4F9D}\x{4F9E}\x{4F9F}\x{4FA0}\x{4FA1}' .
          '\x{4FA3}\x{4FA4}\x{4FA5}\x{4FA6}\x{4FA7}\x{4FA8}\x{4FA9}\x{4FAA}\x{4FAB}' .
          '\x{4FAC}\x{4FAE}\x{4FAF}\x{4FB0}\x{4FB1}\x{4FB2}\x{4FB3}\x{4FB4}\x{4FB5}' .
          '\x{4FB6}\x{4FB7}\x{4FB8}\x{4FB9}\x{4FBA}\x{4FBB}\x{4FBC}\x{4FBE}\x{4FBF}' .
          '\x{4FC0}\x{4FC1}\x{4FC2}\x{4FC3}\x{4FC4}\x{4FC5}\x{4FC7}\x{4FC9}\x{4FCA}' .
          '\x{4FCB}\x{4FCD}\x{4FCE}\x{4FCF}\x{4FD0}\x{4FD1}\x{4FD2}\x{4FD3}\x{4FD4}' .
          '\x{4FD5}\x{4FD6}\x{4FD7}\x{4FD8}\x{4FD9}\x{4FDA}\x{4FDB}\x{4FDC}\x{4FDD}' .
          '\x{4FDE}\x{4FDF}\x{4FE0}\x{4FE1}\x{4FE3}\x{4FE4}\x{4FE5}\x{4FE6}\x{4FE7}' .
          '\x{4FE8}\x{4FE9}\x{4FEA}\x{4FEB}\x{4FEC}\x{4FED}\x{4FEE}\x{4FEF}\x{4FF0}' .
          '\x{4FF1}\x{4FF2}\x{4FF3}\x{4FF4}\x{4FF5}\x{4FF6}\x{4FF7}\x{4FF8}\x{4FF9}' .
          '\x{4FFA}\x{4FFB}\x{4FFE}\x{4FFF}\x{5000}\x{5001}\x{5002}\x{5003}\x{5004}' .
          '\x{5005}\x{5006}\x{5007}\x{5008}\x{5009}\x{500A}\x{500B}\x{500C}\x{500D}' .
          '\x{500E}\x{500F}\x{5011}\x{5012}\x{5013}\x{5014}\x{5015}\x{5016}\x{5017}' .
          '\x{5018}\x{5019}\x{501A}\x{501B}\x{501C}\x{501D}\x{501E}\x{501F}\x{5020}' .
          '\x{5021}\x{5022}\x{5023}\x{5024}\x{5025}\x{5026}\x{5027}\x{5028}\x{5029}' .
          '\x{502A}\x{502B}\x{502C}\x{502D}\x{502E}\x{502F}\x{5030}\x{5031}\x{5032}' .
          '\x{5033}\x{5035}\x{5036}\x{5037}\x{5039}\x{503A}\x{503B}\x{503C}\x{503E}' .
          '\x{503F}\x{5040}\x{5041}\x{5043}\x{5044}\x{5045}\x{5046}\x{5047}\x{5048}' .
          '\x{5049}\x{504A}\x{504B}\x{504C}\x{504D}\x{504E}\x{504F}\x{5051}\x{5053}' .
          '\x{5054}\x{5055}\x{5056}\x{5057}\x{5059}\x{505A}\x{505B}\x{505C}\x{505D}' .
          '\x{505E}\x{505F}\x{5060}\x{5061}\x{5062}\x{5063}\x{5064}\x{5065}\x{5066}' .
          '\x{5067}\x{5068}\x{5069}\x{506A}\x{506B}\x{506C}\x{506D}\x{506E}\x{506F}' .
          '\x{5070}\x{5071}\x{5072}\x{5073}\x{5074}\x{5075}\x{5076}\x{5077}\x{5078}' .
          '\x{5079}\x{507A}\x{507B}\x{507D}\x{507E}\x{507F}\x{5080}\x{5082}\x{5083}' .
          '\x{5084}\x{5085}\x{5086}\x{5087}\x{5088}\x{5089}\x{508A}\x{508B}\x{508C}' .
          '\x{508D}\x{508E}\x{508F}\x{5090}\x{5091}\x{5092}\x{5094}\x{5095}\x{5096}' .
          '\x{5098}\x{5099}\x{509A}\x{509B}\x{509C}\x{509D}\x{509E}\x{50A2}\x{50A3}' .
          '\x{50A4}\x{50A5}\x{50A6}\x{50A7}\x{50A8}\x{50A9}\x{50AA}\x{50AB}\x{50AC}' .
          '\x{50AD}\x{50AE}\x{50AF}\x{50B0}\x{50B1}\x{50B2}\x{50B3}\x{50B4}\x{50B5}' .
          '\x{50B6}\x{50B7}\x{50B8}\x{50BA}\x{50BB}\x{50BC}\x{50BD}\x{50BE}\x{50BF}' .
          '\x{50C0}\x{50C1}\x{50C2}\x{50C4}\x{50C5}\x{50C6}\x{50C7}\x{50C8}\x{50C9}' .
          '\x{50CA}\x{50CB}\x{50CC}\x{50CD}\x{50CE}\x{50CF}\x{50D0}\x{50D1}\x{50D2}' .
          '\x{50D3}\x{50D4}\x{50D5}\x{50D6}\x{50D7}\x{50D9}\x{50DA}\x{50DB}\x{50DC}' .
          '\x{50DD}\x{50DE}\x{50E0}\x{50E3}\x{50E4}\x{50E5}\x{50E6}\x{50E7}\x{50E8}' .
          '\x{50E9}\x{50EA}\x{50EC}\x{50ED}\x{50EE}\x{50EF}\x{50F0}\x{50F1}\x{50F2}' .
          '\x{50F3}\x{50F5}\x{50F6}\x{50F8}\x{50F9}\x{50FA}\x{50FB}\x{50FC}\x{50FD}' .
          '\x{50FE}\x{50FF}\x{5100}\x{5101}\x{5102}\x{5103}\x{5104}\x{5105}\x{5106}' .
          '\x{5107}\x{5108}\x{5109}\x{510A}\x{510B}\x{510C}\x{510D}\x{510E}\x{510F}' .
          '\x{5110}\x{5111}\x{5112}\x{5113}\x{5114}\x{5115}\x{5116}\x{5117}\x{5118}' .
          '\x{5119}\x{511A}\x{511C}\x{511D}\x{511E}\x{511F}\x{5120}\x{5121}\x{5122}' .
          '\x{5123}\x{5124}\x{5125}\x{5126}\x{5127}\x{5129}\x{512A}\x{512C}\x{512D}' .
          '\x{512E}\x{512F}\x{5130}\x{5131}\x{5132}\x{5133}\x{5134}\x{5135}\x{5136}' .
          '\x{5137}\x{5138}\x{5139}\x{513A}\x{513B}\x{513C}\x{513D}\x{513E}\x{513F}' .
          '\x{5140}\x{5141}\x{5143}\x{5144}\x{5145}\x{5146}\x{5147}\x{5148}\x{5149}' .
          '\x{514B}\x{514C}\x{514D}\x{514E}\x{5150}\x{5151}\x{5152}\x{5154}\x{5155}' .
          '\x{5156}\x{5157}\x{5159}\x{515A}\x{515B}\x{515C}\x{515D}\x{515E}\x{515F}' .
          '\x{5161}\x{5162}\x{5163}\x{5165}\x{5166}\x{5167}\x{5168}\x{5169}\x{516A}' .
          '\x{516B}\x{516C}\x{516D}\x{516E}\x{516F}\x{5170}\x{5171}\x{5173}\x{5174}' .
          '\x{5175}\x{5176}\x{5177}\x{5178}\x{5179}\x{517A}\x{517B}\x{517C}\x{517D}' .
          '\x{517F}\x{5180}\x{5181}\x{5182}\x{5185}\x{5186}\x{5187}\x{5188}\x{5189}' .
          '\x{518A}\x{518B}\x{518C}\x{518D}\x{518F}\x{5190}\x{5191}\x{5192}\x{5193}' .
          '\x{5194}\x{5195}\x{5196}\x{5197}\x{5198}\x{5199}\x{519A}\x{519B}\x{519C}' .
          '\x{519D}\x{519E}\x{519F}\x{51A0}\x{51A2}\x{51A4}\x{51A5}\x{51A6}\x{51A7}' .
          '\x{51A8}\x{51AA}\x{51AB}\x{51AC}\x{51AE}\x{51AF}\x{51B0}\x{51B1}\x{51B2}' .
          '\x{51B3}\x{51B5}\x{51B6}\x{51B7}\x{51B9}\x{51BB}\x{51BC}\x{51BD}\x{51BE}' .
          '\x{51BF}\x{51C0}\x{51C1}\x{51C3}\x{51C4}\x{51C5}\x{51C6}\x{51C7}\x{51C8}' .
          '\x{51C9}\x{51CA}\x{51CB}\x{51CC}\x{51CD}\x{51CE}\x{51CF}\x{51D0}\x{51D1}' .
          '\x{51D4}\x{51D5}\x{51D6}\x{51D7}\x{51D8}\x{51D9}\x{51DA}\x{51DB}\x{51DC}' .
          '\x{51DD}\x{51DE}\x{51E0}\x{51E1}\x{51E2}\x{51E3}\x{51E4}\x{51E5}\x{51E7}' .
          '\x{51E8}\x{51E9}\x{51EA}\x{51EB}\x{51ED}\x{51EF}\x{51F0}\x{51F1}\x{51F3}' .
          '\x{51F4}\x{51F5}\x{51F6}\x{51F7}\x{51F8}\x{51F9}\x{51FA}\x{51FB}\x{51FC}' .
          '\x{51FD}\x{51FE}\x{51FF}\x{5200}\x{5201}\x{5202}\x{5203}\x{5204}\x{5205}' .
          '\x{5206}\x{5207}\x{5208}\x{5209}\x{520A}\x{520B}\x{520C}\x{520D}\x{520E}' .
          '\x{520F}\x{5210}\x{5211}\x{5212}\x{5213}\x{5214}\x{5215}\x{5216}\x{5217}' .
          '\x{5218}\x{5219}\x{521A}\x{521B}\x{521C}\x{521D}\x{521E}\x{521F}\x{5220}' .
          '\x{5221}\x{5222}\x{5223}\x{5224}\x{5225}\x{5226}\x{5228}\x{5229}\x{522A}' .
          '\x{522B}\x{522C}\x{522D}\x{522E}\x{522F}\x{5230}\x{5231}\x{5232}\x{5233}' .
          '\x{5234}\x{5235}\x{5236}\x{5237}\x{5238}\x{5239}\x{523A}\x{523B}\x{523C}' .
          '\x{523D}\x{523E}\x{523F}\x{5240}\x{5241}\x{5242}\x{5243}\x{5244}\x{5245}' .
          '\x{5246}\x{5247}\x{5248}\x{5249}\x{524A}\x{524B}\x{524C}\x{524D}\x{524E}' .
          '\x{5250}\x{5251}\x{5252}\x{5254}\x{5255}\x{5256}\x{5257}\x{5258}\x{5259}' .
          '\x{525A}\x{525B}\x{525C}\x{525D}\x{525E}\x{525F}\x{5260}\x{5261}\x{5262}' .
          '\x{5263}\x{5264}\x{5265}\x{5267}\x{5268}\x{5269}\x{526A}\x{526B}\x{526C}' .
          '\x{526D}\x{526E}\x{526F}\x{5270}\x{5272}\x{5273}\x{5274}\x{5275}\x{5276}' .
          '\x{5277}\x{5278}\x{527A}\x{527B}\x{527C}\x{527D}\x{527E}\x{527F}\x{5280}' .
          '\x{5281}\x{5282}\x{5283}\x{5284}\x{5286}\x{5287}\x{5288}\x{5289}\x{528A}' .
          '\x{528B}\x{528C}\x{528D}\x{528F}\x{5290}\x{5291}\x{5292}\x{5293}\x{5294}' .
          '\x{5295}\x{5296}\x{5297}\x{5298}\x{5299}\x{529A}\x{529B}\x{529C}\x{529D}' .
          '\x{529E}\x{529F}\x{52A0}\x{52A1}\x{52A2}\x{52A3}\x{52A5}\x{52A6}\x{52A7}' .
          '\x{52A8}\x{52A9}\x{52AA}\x{52AB}\x{52AC}\x{52AD}\x{52AE}\x{52AF}\x{52B0}' .
          '\x{52B1}\x{52B2}\x{52B3}\x{52B4}\x{52B5}\x{52B6}\x{52B7}\x{52B8}\x{52B9}' .
          '\x{52BA}\x{52BB}\x{52BC}\x{52BD}\x{52BE}\x{52BF}\x{52C0}\x{52C1}\x{52C2}' .
          '\x{52C3}\x{52C6}\x{52C7}\x{52C9}\x{52CA}\x{52CB}\x{52CD}\x{52CF}\x{52D0}' .
          '\x{52D2}\x{52D3}\x{52D5}\x{52D6}\x{52D7}\x{52D8}\x{52D9}\x{52DA}\x{52DB}' .
          '\x{52DC}\x{52DD}\x{52DE}\x{52DF}\x{52E0}\x{52E2}\x{52E3}\x{52E4}\x{52E6}' .
          '\x{52E7}\x{52E8}\x{52E9}\x{52EA}\x{52EB}\x{52EC}\x{52ED}\x{52EF}\x{52F0}' .
          '\x{52F1}\x{52F2}\x{52F3}\x{52F4}\x{52F5}\x{52F6}\x{52F7}\x{52F8}\x{52F9}' .
          '\x{52FA}\x{52FB}\x{52FC}\x{52FD}\x{52FE}\x{52FF}\x{5300}\x{5301}\x{5302}' .
          '\x{5305}\x{5306}\x{5307}\x{5308}\x{5309}\x{530A}\x{530B}\x{530C}\x{530D}' .
          '\x{530E}\x{530F}\x{5310}\x{5311}\x{5312}\x{5313}\x{5314}\x{5315}\x{5316}' .
          '\x{5317}\x{5319}\x{531A}\x{531C}\x{531D}\x{531F}\x{5320}\x{5321}\x{5322}' .
          '\x{5323}\x{5324}\x{5325}\x{5326}\x{5328}\x{532A}\x{532B}\x{532C}\x{532D}' .
          '\x{532E}\x{532F}\x{5330}\x{5331}\x{5333}\x{5334}\x{5337}\x{5339}\x{533A}' .
          '\x{533B}\x{533C}\x{533D}\x{533E}\x{533F}\x{5340}\x{5341}\x{5343}\x{5344}' .
          '\x{5345}\x{5346}\x{5347}\x{5348}\x{5349}\x{534A}\x{534B}\x{534C}\x{534D}' .
          '\x{534E}\x{534F}\x{5350}\x{5351}\x{5352}\x{5353}\x{5354}\x{5355}\x{5356}' .
          '\x{5357}\x{5358}\x{5359}\x{535A}\x{535C}\x{535E}\x{535F}\x{5360}\x{5361}' .
          '\x{5362}\x{5363}\x{5364}\x{5365}\x{5366}\x{5367}\x{5369}\x{536B}\x{536C}' .
          '\x{536E}\x{536F}\x{5370}\x{5371}\x{5372}\x{5373}\x{5374}\x{5375}\x{5376}' .
          '\x{5377}\x{5378}\x{5379}\x{537A}\x{537B}\x{537C}\x{537D}\x{537E}\x{537F}' .
          '\x{5381}\x{5382}\x{5383}\x{5384}\x{5385}\x{5386}\x{5387}\x{5388}\x{5389}' .
          '\x{538A}\x{538B}\x{538C}\x{538D}\x{538E}\x{538F}\x{5390}\x{5391}\x{5392}' .
          '\x{5393}\x{5394}\x{5395}\x{5396}\x{5397}\x{5398}\x{5399}\x{539A}\x{539B}' .
          '\x{539C}\x{539D}\x{539E}\x{539F}\x{53A0}\x{53A2}\x{53A3}\x{53A4}\x{53A5}' .
          '\x{53A6}\x{53A7}\x{53A8}\x{53A9}\x{53AC}\x{53AD}\x{53AE}\x{53B0}\x{53B1}' .
          '\x{53B2}\x{53B3}\x{53B4}\x{53B5}\x{53B6}\x{53B7}\x{53B8}\x{53B9}\x{53BB}' .
          '\x{53BC}\x{53BD}\x{53BE}\x{53BF}\x{53C0}\x{53C1}\x{53C2}\x{53C3}\x{53C4}' .
          '\x{53C6}\x{53C7}\x{53C8}\x{53C9}\x{53CA}\x{53CB}\x{53CC}\x{53CD}\x{53CE}' .
          '\x{53D0}\x{53D1}\x{53D2}\x{53D3}\x{53D4}\x{53D5}\x{53D6}\x{53D7}\x{53D8}' .
          '\x{53D9}\x{53DB}\x{53DC}\x{53DF}\x{53E0}\x{53E1}\x{53E2}\x{53E3}\x{53E4}' .
          '\x{53E5}\x{53E6}\x{53E8}\x{53E9}\x{53EA}\x{53EB}\x{53EC}\x{53ED}\x{53EE}' .
          '\x{53EF}\x{53F0}\x{53F1}\x{53F2}\x{53F3}\x{53F4}\x{53F5}\x{53F6}\x{53F7}' .
          '\x{53F8}\x{53F9}\x{53FA}\x{53FB}\x{53FC}\x{53FD}\x{53FE}\x{5401}\x{5402}' .
          '\x{5403}\x{5404}\x{5405}\x{5406}\x{5407}\x{5408}\x{5409}\x{540A}\x{540B}' .
          '\x{540C}\x{540D}\x{540E}\x{540F}\x{5410}\x{5411}\x{5412}\x{5413}\x{5414}' .
          '\x{5415}\x{5416}\x{5417}\x{5418}\x{5419}\x{541B}\x{541C}\x{541D}\x{541E}' .
          '\x{541F}\x{5420}\x{5421}\x{5423}\x{5424}\x{5425}\x{5426}\x{5427}\x{5428}' .
          '\x{5429}\x{542A}\x{542B}\x{542C}\x{542D}\x{542E}\x{542F}\x{5430}\x{5431}' .
          '\x{5432}\x{5433}\x{5434}\x{5435}\x{5436}\x{5437}\x{5438}\x{5439}\x{543A}' .
          '\x{543B}\x{543C}\x{543D}\x{543E}\x{543F}\x{5440}\x{5441}\x{5442}\x{5443}' .
          '\x{5444}\x{5445}\x{5446}\x{5447}\x{5448}\x{5449}\x{544A}\x{544B}\x{544D}' .
          '\x{544E}\x{544F}\x{5450}\x{5451}\x{5452}\x{5453}\x{5454}\x{5455}\x{5456}' .
          '\x{5457}\x{5458}\x{5459}\x{545A}\x{545B}\x{545C}\x{545E}\x{545F}\x{5460}' .
          '\x{5461}\x{5462}\x{5463}\x{5464}\x{5465}\x{5466}\x{5467}\x{5468}\x{546A}' .
          '\x{546B}\x{546C}\x{546D}\x{546E}\x{546F}\x{5470}\x{5471}\x{5472}\x{5473}' .
          '\x{5474}\x{5475}\x{5476}\x{5477}\x{5478}\x{5479}\x{547A}\x{547B}\x{547C}' .
          '\x{547D}\x{547E}\x{547F}\x{5480}\x{5481}\x{5482}\x{5483}\x{5484}\x{5485}' .
          '\x{5486}\x{5487}\x{5488}\x{5489}\x{548B}\x{548C}\x{548D}\x{548E}\x{548F}' .
          '\x{5490}\x{5491}\x{5492}\x{5493}\x{5494}\x{5495}\x{5496}\x{5497}\x{5498}' .
          '\x{5499}\x{549A}\x{549B}\x{549C}\x{549D}\x{549E}\x{549F}\x{54A0}\x{54A1}' .
          '\x{54A2}\x{54A3}\x{54A4}\x{54A5}\x{54A6}\x{54A7}\x{54A8}\x{54A9}\x{54AA}' .
          '\x{54AB}\x{54AC}\x{54AD}\x{54AE}\x{54AF}\x{54B0}\x{54B1}\x{54B2}\x{54B3}' .
          '\x{54B4}\x{54B6}\x{54B7}\x{54B8}\x{54B9}\x{54BA}\x{54BB}\x{54BC}\x{54BD}' .
          '\x{54BE}\x{54BF}\x{54C0}\x{54C1}\x{54C2}\x{54C3}\x{54C4}\x{54C5}\x{54C6}' .
          '\x{54C7}\x{54C8}\x{54C9}\x{54CA}\x{54CB}\x{54CC}\x{54CD}\x{54CE}\x{54CF}' .
          '\x{54D0}\x{54D1}\x{54D2}\x{54D3}\x{54D4}\x{54D5}\x{54D6}\x{54D7}\x{54D8}' .
          '\x{54D9}\x{54DA}\x{54DB}\x{54DC}\x{54DD}\x{54DE}\x{54DF}\x{54E0}\x{54E1}' .
          '\x{54E2}\x{54E3}\x{54E4}\x{54E5}\x{54E6}\x{54E7}\x{54E8}\x{54E9}\x{54EA}' .
          '\x{54EB}\x{54EC}\x{54ED}\x{54EE}\x{54EF}\x{54F0}\x{54F1}\x{54F2}\x{54F3}' .
          '\x{54F4}\x{54F5}\x{54F7}\x{54F8}\x{54F9}\x{54FA}\x{54FB}\x{54FC}\x{54FD}' .
          '\x{54FE}\x{54FF}\x{5500}\x{5501}\x{5502}\x{5503}\x{5504}\x{5505}\x{5506}' .
          '\x{5507}\x{5508}\x{5509}\x{550A}\x{550B}\x{550C}\x{550D}\x{550E}\x{550F}' .
          '\x{5510}\x{5511}\x{5512}\x{5513}\x{5514}\x{5516}\x{5517}\x{551A}\x{551B}' .
          '\x{551C}\x{551D}\x{551E}\x{551F}\x{5520}\x{5521}\x{5522}\x{5523}\x{5524}' .
          '\x{5525}\x{5526}\x{5527}\x{5528}\x{5529}\x{552A}\x{552B}\x{552C}\x{552D}' .
          '\x{552E}\x{552F}\x{5530}\x{5531}\x{5532}\x{5533}\x{5534}\x{5535}\x{5536}' .
          '\x{5537}\x{5538}\x{5539}\x{553A}\x{553B}\x{553C}\x{553D}\x{553E}\x{553F}' .
          '\x{5540}\x{5541}\x{5542}\x{5543}\x{5544}\x{5545}\x{5546}\x{5548}\x{5549}' .
          '\x{554A}\x{554B}\x{554C}\x{554D}\x{554E}\x{554F}\x{5550}\x{5551}\x{5552}' .
          '\x{5553}\x{5554}\x{5555}\x{5556}\x{5557}\x{5558}\x{5559}\x{555A}\x{555B}' .
          '\x{555C}\x{555D}\x{555E}\x{555F}\x{5561}\x{5562}\x{5563}\x{5564}\x{5565}' .
          '\x{5566}\x{5567}\x{5568}\x{5569}\x{556A}\x{556B}\x{556C}\x{556D}\x{556E}' .
          '\x{556F}\x{5570}\x{5571}\x{5572}\x{5573}\x{5574}\x{5575}\x{5576}\x{5577}' .
          '\x{5578}\x{5579}\x{557B}\x{557C}\x{557D}\x{557E}\x{557F}\x{5580}\x{5581}' .
          '\x{5582}\x{5583}\x{5584}\x{5585}\x{5586}\x{5587}\x{5588}\x{5589}\x{558A}' .
          '\x{558B}\x{558C}\x{558D}\x{558E}\x{558F}\x{5590}\x{5591}\x{5592}\x{5593}' .
          '\x{5594}\x{5595}\x{5596}\x{5597}\x{5598}\x{5599}\x{559A}\x{559B}\x{559C}' .
          '\x{559D}\x{559E}\x{559F}\x{55A0}\x{55A1}\x{55A2}\x{55A3}\x{55A4}\x{55A5}' .
          '\x{55A6}\x{55A7}\x{55A8}\x{55A9}\x{55AA}\x{55AB}\x{55AC}\x{55AD}\x{55AE}' .
          '\x{55AF}\x{55B0}\x{55B1}\x{55B2}\x{55B3}\x{55B4}\x{55B5}\x{55B6}\x{55B7}' .
          '\x{55B8}\x{55B9}\x{55BA}\x{55BB}\x{55BC}\x{55BD}\x{55BE}\x{55BF}\x{55C0}' .
          '\x{55C1}\x{55C2}\x{55C3}\x{55C4}\x{55C5}\x{55C6}\x{55C7}\x{55C8}\x{55C9}' .
          '\x{55CA}\x{55CB}\x{55CC}\x{55CD}\x{55CE}\x{55CF}\x{55D0}\x{55D1}\x{55D2}' .
          '\x{55D3}\x{55D4}\x{55D5}\x{55D6}\x{55D7}\x{55D8}\x{55D9}\x{55DA}\x{55DB}' .
          '\x{55DC}\x{55DD}\x{55DE}\x{55DF}\x{55E1}\x{55E2}\x{55E3}\x{55E4}\x{55E5}' .
          '\x{55E6}\x{55E7}\x{55E8}\x{55E9}\x{55EA}\x{55EB}\x{55EC}\x{55ED}\x{55EE}' .
          '\x{55EF}\x{55F0}\x{55F1}\x{55F2}\x{55F3}\x{55F4}\x{55F5}\x{55F6}\x{55F7}' .
          '\x{55F9}\x{55FA}\x{55FB}\x{55FC}\x{55FD}\x{55FE}\x{55FF}\x{5600}\x{5601}' .
          '\x{5602}\x{5603}\x{5604}\x{5606}\x{5607}\x{5608}\x{5609}\x{560C}\x{560D}' .
          '\x{560E}\x{560F}\x{5610}\x{5611}\x{5612}\x{5613}\x{5614}\x{5615}\x{5616}' .
          '\x{5617}\x{5618}\x{5619}\x{561A}\x{561B}\x{561C}\x{561D}\x{561E}\x{561F}' .
          '\x{5621}\x{5622}\x{5623}\x{5624}\x{5625}\x{5626}\x{5627}\x{5628}\x{5629}' .
          '\x{562A}\x{562C}\x{562D}\x{562E}\x{562F}\x{5630}\x{5631}\x{5632}\x{5633}' .
          '\x{5634}\x{5635}\x{5636}\x{5638}\x{5639}\x{563A}\x{563B}\x{563D}\x{563E}' .
          '\x{563F}\x{5640}\x{5641}\x{5642}\x{5643}\x{5645}\x{5646}\x{5647}\x{5648}' .
          '\x{5649}\x{564A}\x{564C}\x{564D}\x{564E}\x{564F}\x{5650}\x{5652}\x{5653}' .
          '\x{5654}\x{5655}\x{5657}\x{5658}\x{5659}\x{565A}\x{565B}\x{565C}\x{565D}' .
          '\x{565E}\x{5660}\x{5662}\x{5663}\x{5664}\x{5665}\x{5666}\x{5667}\x{5668}' .
          '\x{5669}\x{566A}\x{566B}\x{566C}\x{566D}\x{566E}\x{566F}\x{5670}\x{5671}' .
          '\x{5672}\x{5673}\x{5674}\x{5676}\x{5677}\x{5678}\x{5679}\x{567A}\x{567B}' .
          '\x{567C}\x{567E}\x{567F}\x{5680}\x{5681}\x{5682}\x{5683}\x{5684}\x{5685}' .
          '\x{5686}\x{5687}\x{568A}\x{568C}\x{568D}\x{568E}\x{568F}\x{5690}\x{5691}' .
          '\x{5692}\x{5693}\x{5694}\x{5695}\x{5697}\x{5698}\x{5699}\x{569A}\x{569B}' .
          '\x{569C}\x{569D}\x{569F}\x{56A0}\x{56A1}\x{56A3}\x{56A4}\x{56A5}\x{56A6}' .
          '\x{56A7}\x{56A8}\x{56A9}\x{56AA}\x{56AB}\x{56AC}\x{56AD}\x{56AE}\x{56AF}' .
          '\x{56B0}\x{56B1}\x{56B2}\x{56B3}\x{56B4}\x{56B5}\x{56B6}\x{56B7}\x{56B8}' .
          '\x{56B9}\x{56BB}\x{56BC}\x{56BD}\x{56BE}\x{56BF}\x{56C0}\x{56C1}\x{56C2}' .
          '\x{56C3}\x{56C4}\x{56C5}\x{56C6}\x{56C7}\x{56C8}\x{56C9}\x{56CA}\x{56CB}' .
          '\x{56CC}\x{56CD}\x{56CE}\x{56D0}\x{56D1}\x{56D2}\x{56D3}\x{56D4}\x{56D5}' .
          '\x{56D6}\x{56D7}\x{56D8}\x{56DA}\x{56DB}\x{56DC}\x{56DD}\x{56DE}\x{56DF}' .
          '\x{56E0}\x{56E1}\x{56E2}\x{56E3}\x{56E4}\x{56E5}\x{56E7}\x{56E8}\x{56E9}' .
          '\x{56EA}\x{56EB}\x{56EC}\x{56ED}\x{56EE}\x{56EF}\x{56F0}\x{56F1}\x{56F2}' .
          '\x{56F3}\x{56F4}\x{56F5}\x{56F7}\x{56F9}\x{56FA}\x{56FD}\x{56FE}\x{56FF}' .
          '\x{5700}\x{5701}\x{5702}\x{5703}\x{5704}\x{5706}\x{5707}\x{5708}\x{5709}' .
          '\x{570A}\x{570B}\x{570C}\x{570D}\x{570E}\x{570F}\x{5710}\x{5712}\x{5713}' .
          '\x{5714}\x{5715}\x{5716}\x{5718}\x{5719}\x{571A}\x{571B}\x{571C}\x{571D}' .
          '\x{571E}\x{571F}\x{5720}\x{5722}\x{5723}\x{5725}\x{5726}\x{5727}\x{5728}' .
          '\x{5729}\x{572A}\x{572B}\x{572C}\x{572D}\x{572E}\x{572F}\x{5730}\x{5731}' .
          '\x{5732}\x{5733}\x{5734}\x{5735}\x{5736}\x{5737}\x{5738}\x{5739}\x{573A}' .
          '\x{573B}\x{573C}\x{573E}\x{573F}\x{5740}\x{5741}\x{5742}\x{5744}\x{5745}' .
          '\x{5746}\x{5747}\x{5749}\x{574A}\x{574B}\x{574C}\x{574D}\x{574E}\x{574F}' .
          '\x{5750}\x{5751}\x{5752}\x{5753}\x{5754}\x{5757}\x{5759}\x{575A}\x{575B}' .
          '\x{575C}\x{575D}\x{575E}\x{575F}\x{5760}\x{5761}\x{5762}\x{5764}\x{5765}' .
          '\x{5766}\x{5767}\x{5768}\x{5769}\x{576A}\x{576B}\x{576C}\x{576D}\x{576F}' .
          '\x{5770}\x{5771}\x{5772}\x{5773}\x{5774}\x{5775}\x{5776}\x{5777}\x{5779}' .
          '\x{577A}\x{577B}\x{577C}\x{577D}\x{577E}\x{577F}\x{5780}\x{5782}\x{5783}' .
          '\x{5784}\x{5785}\x{5786}\x{5788}\x{5789}\x{578A}\x{578B}\x{578C}\x{578D}' .
          '\x{578E}\x{578F}\x{5790}\x{5791}\x{5792}\x{5793}\x{5794}\x{5795}\x{5797}' .
          '\x{5798}\x{5799}\x{579A}\x{579B}\x{579C}\x{579D}\x{579E}\x{579F}\x{57A0}' .
          '\x{57A1}\x{57A2}\x{57A3}\x{57A4}\x{57A5}\x{57A6}\x{57A7}\x{57A9}\x{57AA}' .
          '\x{57AB}\x{57AC}\x{57AD}\x{57AE}\x{57AF}\x{57B0}\x{57B1}\x{57B2}\x{57B3}' .
          '\x{57B4}\x{57B5}\x{57B6}\x{57B7}\x{57B8}\x{57B9}\x{57BA}\x{57BB}\x{57BC}' .
          '\x{57BD}\x{57BE}\x{57BF}\x{57C0}\x{57C1}\x{57C2}\x{57C3}\x{57C4}\x{57C5}' .
          '\x{57C6}\x{57C7}\x{57C8}\x{57C9}\x{57CB}\x{57CC}\x{57CD}\x{57CE}\x{57CF}' .
          '\x{57D0}\x{57D2}\x{57D3}\x{57D4}\x{57D5}\x{57D6}\x{57D8}\x{57D9}\x{57DA}' .
          '\x{57DC}\x{57DD}\x{57DF}\x{57E0}\x{57E1}\x{57E2}\x{57E3}\x{57E4}\x{57E5}' .
          '\x{57E6}\x{57E7}\x{57E8}\x{57E9}\x{57EA}\x{57EB}\x{57EC}\x{57ED}\x{57EE}' .
          '\x{57EF}\x{57F0}\x{57F1}\x{57F2}\x{57F3}\x{57F4}\x{57F5}\x{57F6}\x{57F7}' .
          '\x{57F8}\x{57F9}\x{57FA}\x{57FB}\x{57FC}\x{57FD}\x{57FE}\x{57FF}\x{5800}' .
          '\x{5801}\x{5802}\x{5803}\x{5804}\x{5805}\x{5806}\x{5807}\x{5808}\x{5809}' .
          '\x{580A}\x{580B}\x{580C}\x{580D}\x{580E}\x{580F}\x{5810}\x{5811}\x{5812}' .
          '\x{5813}\x{5814}\x{5815}\x{5816}\x{5819}\x{581A}\x{581B}\x{581C}\x{581D}' .
          '\x{581E}\x{581F}\x{5820}\x{5821}\x{5822}\x{5823}\x{5824}\x{5825}\x{5826}' .
          '\x{5827}\x{5828}\x{5829}\x{582A}\x{582B}\x{582C}\x{582D}\x{582E}\x{582F}' .
          '\x{5830}\x{5831}\x{5832}\x{5833}\x{5834}\x{5835}\x{5836}\x{5837}\x{5838}' .
          '\x{5839}\x{583A}\x{583B}\x{583C}\x{583D}\x{583E}\x{583F}\x{5840}\x{5842}' .
          '\x{5843}\x{5844}\x{5845}\x{5846}\x{5847}\x{5848}\x{5849}\x{584A}\x{584B}' .
          '\x{584C}\x{584D}\x{584E}\x{584F}\x{5851}\x{5852}\x{5853}\x{5854}\x{5855}' .
          '\x{5857}\x{5858}\x{5859}\x{585A}\x{585B}\x{585C}\x{585D}\x{585E}\x{585F}' .
          '\x{5861}\x{5862}\x{5863}\x{5864}\x{5865}\x{5868}\x{5869}\x{586A}\x{586B}' .
          '\x{586C}\x{586D}\x{586E}\x{586F}\x{5870}\x{5871}\x{5872}\x{5873}\x{5874}' .
          '\x{5875}\x{5876}\x{5878}\x{5879}\x{587A}\x{587B}\x{587C}\x{587D}\x{587E}' .
          '\x{587F}\x{5880}\x{5881}\x{5882}\x{5883}\x{5884}\x{5885}\x{5886}\x{5887}' .
          '\x{5888}\x{5889}\x{588A}\x{588B}\x{588C}\x{588D}\x{588E}\x{588F}\x{5890}' .
          '\x{5891}\x{5892}\x{5893}\x{5894}\x{5896}\x{5897}\x{5898}\x{5899}\x{589A}' .
          '\x{589B}\x{589C}\x{589D}\x{589E}\x{589F}\x{58A0}\x{58A1}\x{58A2}\x{58A3}' .
          '\x{58A4}\x{58A5}\x{58A6}\x{58A7}\x{58A8}\x{58A9}\x{58AB}\x{58AC}\x{58AD}' .
          '\x{58AE}\x{58AF}\x{58B0}\x{58B1}\x{58B2}\x{58B3}\x{58B4}\x{58B7}\x{58B8}' .
          '\x{58B9}\x{58BA}\x{58BB}\x{58BC}\x{58BD}\x{58BE}\x{58BF}\x{58C1}\x{58C2}' .
          '\x{58C5}\x{58C6}\x{58C7}\x{58C8}\x{58C9}\x{58CA}\x{58CB}\x{58CE}\x{58CF}' .
          '\x{58D1}\x{58D2}\x{58D3}\x{58D4}\x{58D5}\x{58D6}\x{58D7}\x{58D8}\x{58D9}' .
          '\x{58DA}\x{58DB}\x{58DD}\x{58DE}\x{58DF}\x{58E0}\x{58E2}\x{58E3}\x{58E4}' .
          '\x{58E5}\x{58E7}\x{58E8}\x{58E9}\x{58EA}\x{58EB}\x{58EC}\x{58ED}\x{58EE}' .
          '\x{58EF}\x{58F0}\x{58F1}\x{58F2}\x{58F3}\x{58F4}\x{58F6}\x{58F7}\x{58F8}' .
          '\x{58F9}\x{58FA}\x{58FB}\x{58FC}\x{58FD}\x{58FE}\x{58FF}\x{5900}\x{5902}' .
          '\x{5903}\x{5904}\x{5906}\x{5907}\x{5909}\x{590A}\x{590B}\x{590C}\x{590D}' .
          '\x{590E}\x{590F}\x{5910}\x{5912}\x{5914}\x{5915}\x{5916}\x{5917}\x{5918}' .
          '\x{5919}\x{591A}\x{591B}\x{591C}\x{591D}\x{591E}\x{591F}\x{5920}\x{5921}' .
          '\x{5922}\x{5924}\x{5925}\x{5926}\x{5927}\x{5928}\x{5929}\x{592A}\x{592B}' .
          '\x{592C}\x{592D}\x{592E}\x{592F}\x{5930}\x{5931}\x{5932}\x{5934}\x{5935}' .
          '\x{5937}\x{5938}\x{5939}\x{593A}\x{593B}\x{593C}\x{593D}\x{593E}\x{593F}' .
          '\x{5940}\x{5941}\x{5942}\x{5943}\x{5944}\x{5945}\x{5946}\x{5947}\x{5948}' .
          '\x{5949}\x{594A}\x{594B}\x{594C}\x{594D}\x{594E}\x{594F}\x{5950}\x{5951}' .
          '\x{5952}\x{5953}\x{5954}\x{5955}\x{5956}\x{5957}\x{5958}\x{595A}\x{595C}' .
          '\x{595D}\x{595E}\x{595F}\x{5960}\x{5961}\x{5962}\x{5963}\x{5964}\x{5965}' .
          '\x{5966}\x{5967}\x{5968}\x{5969}\x{596A}\x{596B}\x{596C}\x{596D}\x{596E}' .
          '\x{596F}\x{5970}\x{5971}\x{5972}\x{5973}\x{5974}\x{5975}\x{5976}\x{5977}' .
          '\x{5978}\x{5979}\x{597A}\x{597B}\x{597C}\x{597D}\x{597E}\x{597F}\x{5980}' .
          '\x{5981}\x{5982}\x{5983}\x{5984}\x{5985}\x{5986}\x{5987}\x{5988}\x{5989}' .
          '\x{598A}\x{598B}\x{598C}\x{598D}\x{598E}\x{598F}\x{5990}\x{5991}\x{5992}' .
          '\x{5993}\x{5994}\x{5995}\x{5996}\x{5997}\x{5998}\x{5999}\x{599A}\x{599C}' .
          '\x{599D}\x{599E}\x{599F}\x{59A0}\x{59A1}\x{59A2}\x{59A3}\x{59A4}\x{59A5}' .
          '\x{59A6}\x{59A7}\x{59A8}\x{59A9}\x{59AA}\x{59AB}\x{59AC}\x{59AD}\x{59AE}' .
          '\x{59AF}\x{59B0}\x{59B1}\x{59B2}\x{59B3}\x{59B4}\x{59B5}\x{59B6}\x{59B8}' .
          '\x{59B9}\x{59BA}\x{59BB}\x{59BC}\x{59BD}\x{59BE}\x{59BF}\x{59C0}\x{59C1}' .
          '\x{59C2}\x{59C3}\x{59C4}\x{59C5}\x{59C6}\x{59C7}\x{59C8}\x{59C9}\x{59CA}' .
          '\x{59CB}\x{59CC}\x{59CD}\x{59CE}\x{59CF}\x{59D0}\x{59D1}\x{59D2}\x{59D3}' .
          '\x{59D4}\x{59D5}\x{59D6}\x{59D7}\x{59D8}\x{59D9}\x{59DA}\x{59DB}\x{59DC}' .
          '\x{59DD}\x{59DE}\x{59DF}\x{59E0}\x{59E1}\x{59E2}\x{59E3}\x{59E4}\x{59E5}' .
          '\x{59E6}\x{59E8}\x{59E9}\x{59EA}\x{59EB}\x{59EC}\x{59ED}\x{59EE}\x{59EF}' .
          '\x{59F0}\x{59F1}\x{59F2}\x{59F3}\x{59F4}\x{59F5}\x{59F6}\x{59F7}\x{59F8}' .
          '\x{59F9}\x{59FA}\x{59FB}\x{59FC}\x{59FD}\x{59FE}\x{59FF}\x{5A00}\x{5A01}' .
          '\x{5A02}\x{5A03}\x{5A04}\x{5A05}\x{5A06}\x{5A07}\x{5A08}\x{5A09}\x{5A0A}' .
          '\x{5A0B}\x{5A0C}\x{5A0D}\x{5A0E}\x{5A0F}\x{5A10}\x{5A11}\x{5A12}\x{5A13}' .
          '\x{5A14}\x{5A15}\x{5A16}\x{5A17}\x{5A18}\x{5A19}\x{5A1A}\x{5A1B}\x{5A1C}' .
          '\x{5A1D}\x{5A1E}\x{5A1F}\x{5A20}\x{5A21}\x{5A22}\x{5A23}\x{5A25}\x{5A27}' .
          '\x{5A28}\x{5A29}\x{5A2A}\x{5A2B}\x{5A2D}\x{5A2E}\x{5A2F}\x{5A31}\x{5A32}' .
          '\x{5A33}\x{5A34}\x{5A35}\x{5A36}\x{5A37}\x{5A38}\x{5A39}\x{5A3A}\x{5A3B}' .
          '\x{5A3C}\x{5A3D}\x{5A3E}\x{5A3F}\x{5A40}\x{5A41}\x{5A42}\x{5A43}\x{5A44}' .
          '\x{5A45}\x{5A46}\x{5A47}\x{5A48}\x{5A49}\x{5A4A}\x{5A4B}\x{5A4C}\x{5A4D}' .
          '\x{5A4E}\x{5A4F}\x{5A50}\x{5A51}\x{5A52}\x{5A53}\x{5A55}\x{5A56}\x{5A57}' .
          '\x{5A58}\x{5A5A}\x{5A5B}\x{5A5C}\x{5A5D}\x{5A5E}\x{5A5F}\x{5A60}\x{5A61}' .
          '\x{5A62}\x{5A63}\x{5A64}\x{5A65}\x{5A66}\x{5A67}\x{5A68}\x{5A69}\x{5A6A}' .
          '\x{5A6B}\x{5A6C}\x{5A6D}\x{5A6E}\x{5A70}\x{5A72}\x{5A73}\x{5A74}\x{5A75}' .
          '\x{5A76}\x{5A77}\x{5A78}\x{5A79}\x{5A7A}\x{5A7B}\x{5A7C}\x{5A7D}\x{5A7E}' .
          '\x{5A7F}\x{5A80}\x{5A81}\x{5A82}\x{5A83}\x{5A84}\x{5A85}\x{5A86}\x{5A88}' .
          '\x{5A89}\x{5A8A}\x{5A8B}\x{5A8C}\x{5A8E}\x{5A8F}\x{5A90}\x{5A91}\x{5A92}' .
          '\x{5A93}\x{5A94}\x{5A95}\x{5A96}\x{5A97}\x{5A98}\x{5A99}\x{5A9A}\x{5A9B}' .
          '\x{5A9C}\x{5A9D}\x{5A9E}\x{5A9F}\x{5AA0}\x{5AA1}\x{5AA2}\x{5AA3}\x{5AA4}' .
          '\x{5AA5}\x{5AA6}\x{5AA7}\x{5AA8}\x{5AA9}\x{5AAA}\x{5AAC}\x{5AAD}\x{5AAE}' .
          '\x{5AAF}\x{5AB0}\x{5AB1}\x{5AB2}\x{5AB3}\x{5AB4}\x{5AB5}\x{5AB6}\x{5AB7}' .
          '\x{5AB8}\x{5AB9}\x{5ABA}\x{5ABB}\x{5ABC}\x{5ABD}\x{5ABE}\x{5ABF}\x{5AC0}' .
          '\x{5AC1}\x{5AC2}\x{5AC3}\x{5AC4}\x{5AC5}\x{5AC6}\x{5AC7}\x{5AC8}\x{5AC9}' .
          '\x{5ACA}\x{5ACB}\x{5ACC}\x{5ACD}\x{5ACE}\x{5ACF}\x{5AD1}\x{5AD2}\x{5AD4}' .
          '\x{5AD5}\x{5AD6}\x{5AD7}\x{5AD8}\x{5AD9}\x{5ADA}\x{5ADB}\x{5ADC}\x{5ADD}' .
          '\x{5ADE}\x{5ADF}\x{5AE0}\x{5AE1}\x{5AE2}\x{5AE3}\x{5AE4}\x{5AE5}\x{5AE6}' .
          '\x{5AE7}\x{5AE8}\x{5AE9}\x{5AEA}\x{5AEB}\x{5AEC}\x{5AED}\x{5AEE}\x{5AF1}' .
          '\x{5AF2}\x{5AF3}\x{5AF4}\x{5AF5}\x{5AF6}\x{5AF7}\x{5AF8}\x{5AF9}\x{5AFA}' .
          '\x{5AFB}\x{5AFC}\x{5AFD}\x{5AFE}\x{5AFF}\x{5B00}\x{5B01}\x{5B02}\x{5B03}' .
          '\x{5B04}\x{5B05}\x{5B06}\x{5B07}\x{5B08}\x{5B09}\x{5B0B}\x{5B0C}\x{5B0E}' .
          '\x{5B0F}\x{5B10}\x{5B11}\x{5B12}\x{5B13}\x{5B14}\x{5B15}\x{5B16}\x{5B17}' .
          '\x{5B18}\x{5B19}\x{5B1A}\x{5B1B}\x{5B1C}\x{5B1D}\x{5B1E}\x{5B1F}\x{5B20}' .
          '\x{5B21}\x{5B22}\x{5B23}\x{5B24}\x{5B25}\x{5B26}\x{5B27}\x{5B28}\x{5B29}' .
          '\x{5B2A}\x{5B2B}\x{5B2C}\x{5B2D}\x{5B2E}\x{5B2F}\x{5B30}\x{5B31}\x{5B32}' .
          '\x{5B33}\x{5B34}\x{5B35}\x{5B36}\x{5B37}\x{5B38}\x{5B3A}\x{5B3B}\x{5B3C}' .
          '\x{5B3D}\x{5B3E}\x{5B3F}\x{5B40}\x{5B41}\x{5B42}\x{5B43}\x{5B44}\x{5B45}' .
          '\x{5B47}\x{5B48}\x{5B49}\x{5B4A}\x{5B4B}\x{5B4C}\x{5B4D}\x{5B4E}\x{5B50}' .
          '\x{5B51}\x{5B53}\x{5B54}\x{5B55}\x{5B56}\x{5B57}\x{5B58}\x{5B59}\x{5B5A}' .
          '\x{5B5B}\x{5B5C}\x{5B5D}\x{5B5E}\x{5B5F}\x{5B62}\x{5B63}\x{5B64}\x{5B65}' .
          '\x{5B66}\x{5B67}\x{5B68}\x{5B69}\x{5B6A}\x{5B6B}\x{5B6C}\x{5B6D}\x{5B6E}' .
          '\x{5B70}\x{5B71}\x{5B72}\x{5B73}\x{5B74}\x{5B75}\x{5B76}\x{5B77}\x{5B78}' .
          '\x{5B7A}\x{5B7B}\x{5B7C}\x{5B7D}\x{5B7F}\x{5B80}\x{5B81}\x{5B82}\x{5B83}' .
          '\x{5B84}\x{5B85}\x{5B87}\x{5B88}\x{5B89}\x{5B8A}\x{5B8B}\x{5B8C}\x{5B8D}' .
          '\x{5B8E}\x{5B8F}\x{5B91}\x{5B92}\x{5B93}\x{5B94}\x{5B95}\x{5B96}\x{5B97}' .
          '\x{5B98}\x{5B99}\x{5B9A}\x{5B9B}\x{5B9C}\x{5B9D}\x{5B9E}\x{5B9F}\x{5BA0}' .
          '\x{5BA1}\x{5BA2}\x{5BA3}\x{5BA4}\x{5BA5}\x{5BA6}\x{5BA7}\x{5BA8}\x{5BAA}' .
          '\x{5BAB}\x{5BAC}\x{5BAD}\x{5BAE}\x{5BAF}\x{5BB0}\x{5BB1}\x{5BB3}\x{5BB4}' .
          '\x{5BB5}\x{5BB6}\x{5BB8}\x{5BB9}\x{5BBA}\x{5BBB}\x{5BBD}\x{5BBE}\x{5BBF}' .
          '\x{5BC0}\x{5BC1}\x{5BC2}\x{5BC3}\x{5BC4}\x{5BC5}\x{5BC6}\x{5BC7}\x{5BCA}' .
          '\x{5BCB}\x{5BCC}\x{5BCD}\x{5BCE}\x{5BCF}\x{5BD0}\x{5BD1}\x{5BD2}\x{5BD3}' .
          '\x{5BD4}\x{5BD5}\x{5BD6}\x{5BD8}\x{5BD9}\x{5BDB}\x{5BDC}\x{5BDD}\x{5BDE}' .
          '\x{5BDF}\x{5BE0}\x{5BE1}\x{5BE2}\x{5BE3}\x{5BE4}\x{5BE5}\x{5BE6}\x{5BE7}' .
          '\x{5BE8}\x{5BE9}\x{5BEA}\x{5BEB}\x{5BEC}\x{5BED}\x{5BEE}\x{5BEF}\x{5BF0}' .
          '\x{5BF1}\x{5BF2}\x{5BF3}\x{5BF4}\x{5BF5}\x{5BF6}\x{5BF7}\x{5BF8}\x{5BF9}' .
          '\x{5BFA}\x{5BFB}\x{5BFC}\x{5BFD}\x{5BFF}\x{5C01}\x{5C03}\x{5C04}\x{5C05}' .
          '\x{5C06}\x{5C07}\x{5C08}\x{5C09}\x{5C0A}\x{5C0B}\x{5C0C}\x{5C0D}\x{5C0E}' .
          '\x{5C0F}\x{5C10}\x{5C11}\x{5C12}\x{5C13}\x{5C14}\x{5C15}\x{5C16}\x{5C17}' .
          '\x{5C18}\x{5C19}\x{5C1A}\x{5C1C}\x{5C1D}\x{5C1E}\x{5C1F}\x{5C20}\x{5C21}' .
          '\x{5C22}\x{5C24}\x{5C25}\x{5C27}\x{5C28}\x{5C2A}\x{5C2B}\x{5C2C}\x{5C2D}' .
          '\x{5C2E}\x{5C2F}\x{5C30}\x{5C31}\x{5C32}\x{5C33}\x{5C34}\x{5C35}\x{5C37}' .
          '\x{5C38}\x{5C39}\x{5C3A}\x{5C3B}\x{5C3C}\x{5C3D}\x{5C3E}\x{5C3F}\x{5C40}' .
          '\x{5C41}\x{5C42}\x{5C43}\x{5C44}\x{5C45}\x{5C46}\x{5C47}\x{5C48}\x{5C49}' .
          '\x{5C4A}\x{5C4B}\x{5C4C}\x{5C4D}\x{5C4E}\x{5C4F}\x{5C50}\x{5C51}\x{5C52}' .
          '\x{5C53}\x{5C54}\x{5C55}\x{5C56}\x{5C57}\x{5C58}\x{5C59}\x{5C5B}\x{5C5C}' .
          '\x{5C5D}\x{5C5E}\x{5C5F}\x{5C60}\x{5C61}\x{5C62}\x{5C63}\x{5C64}\x{5C65}' .
          '\x{5C66}\x{5C67}\x{5C68}\x{5C69}\x{5C6A}\x{5C6B}\x{5C6C}\x{5C6D}\x{5C6E}' .
          '\x{5C6F}\x{5C70}\x{5C71}\x{5C72}\x{5C73}\x{5C74}\x{5C75}\x{5C76}\x{5C77}' .
          '\x{5C78}\x{5C79}\x{5C7A}\x{5C7B}\x{5C7C}\x{5C7D}\x{5C7E}\x{5C7F}\x{5C80}' .
          '\x{5C81}\x{5C82}\x{5C83}\x{5C84}\x{5C86}\x{5C87}\x{5C88}\x{5C89}\x{5C8A}' .
          '\x{5C8B}\x{5C8C}\x{5C8D}\x{5C8E}\x{5C8F}\x{5C90}\x{5C91}\x{5C92}\x{5C93}' .
          '\x{5C94}\x{5C95}\x{5C96}\x{5C97}\x{5C98}\x{5C99}\x{5C9A}\x{5C9B}\x{5C9C}' .
          '\x{5C9D}\x{5C9E}\x{5C9F}\x{5CA0}\x{5CA1}\x{5CA2}\x{5CA3}\x{5CA4}\x{5CA5}' .
          '\x{5CA6}\x{5CA7}\x{5CA8}\x{5CA9}\x{5CAA}\x{5CAB}\x{5CAC}\x{5CAD}\x{5CAE}' .
          '\x{5CAF}\x{5CB0}\x{5CB1}\x{5CB2}\x{5CB3}\x{5CB5}\x{5CB6}\x{5CB7}\x{5CB8}' .
          '\x{5CBA}\x{5CBB}\x{5CBC}\x{5CBD}\x{5CBE}\x{5CBF}\x{5CC1}\x{5CC2}\x{5CC3}' .
          '\x{5CC4}\x{5CC5}\x{5CC6}\x{5CC7}\x{5CC8}\x{5CC9}\x{5CCA}\x{5CCB}\x{5CCC}' .
          '\x{5CCD}\x{5CCE}\x{5CCF}\x{5CD0}\x{5CD1}\x{5CD2}\x{5CD3}\x{5CD4}\x{5CD6}' .
          '\x{5CD7}\x{5CD8}\x{5CD9}\x{5CDA}\x{5CDB}\x{5CDC}\x{5CDE}\x{5CDF}\x{5CE0}' .
          '\x{5CE1}\x{5CE2}\x{5CE3}\x{5CE4}\x{5CE5}\x{5CE6}\x{5CE7}\x{5CE8}\x{5CE9}' .
          '\x{5CEA}\x{5CEB}\x{5CEC}\x{5CED}\x{5CEE}\x{5CEF}\x{5CF0}\x{5CF1}\x{5CF2}' .
          '\x{5CF3}\x{5CF4}\x{5CF6}\x{5CF7}\x{5CF8}\x{5CF9}\x{5CFA}\x{5CFB}\x{5CFC}' .
          '\x{5CFD}\x{5CFE}\x{5CFF}\x{5D00}\x{5D01}\x{5D02}\x{5D03}\x{5D04}\x{5D05}' .
          '\x{5D06}\x{5D07}\x{5D08}\x{5D09}\x{5D0A}\x{5D0B}\x{5D0C}\x{5D0D}\x{5D0E}' .
          '\x{5D0F}\x{5D10}\x{5D11}\x{5D12}\x{5D13}\x{5D14}\x{5D15}\x{5D16}\x{5D17}' .
          '\x{5D18}\x{5D19}\x{5D1A}\x{5D1B}\x{5D1C}\x{5D1D}\x{5D1E}\x{5D1F}\x{5D20}' .
          '\x{5D21}\x{5D22}\x{5D23}\x{5D24}\x{5D25}\x{5D26}\x{5D27}\x{5D28}\x{5D29}' .
          '\x{5D2A}\x{5D2C}\x{5D2D}\x{5D2E}\x{5D30}\x{5D31}\x{5D32}\x{5D33}\x{5D34}' .
          '\x{5D35}\x{5D36}\x{5D37}\x{5D38}\x{5D39}\x{5D3A}\x{5D3C}\x{5D3D}\x{5D3E}' .
          '\x{5D3F}\x{5D40}\x{5D41}\x{5D42}\x{5D43}\x{5D44}\x{5D45}\x{5D46}\x{5D47}' .
          '\x{5D48}\x{5D49}\x{5D4A}\x{5D4B}\x{5D4C}\x{5D4D}\x{5D4E}\x{5D4F}\x{5D50}' .
          '\x{5D51}\x{5D52}\x{5D54}\x{5D55}\x{5D56}\x{5D58}\x{5D59}\x{5D5A}\x{5D5B}' .
          '\x{5D5D}\x{5D5E}\x{5D5F}\x{5D61}\x{5D62}\x{5D63}\x{5D64}\x{5D65}\x{5D66}' .
          '\x{5D67}\x{5D68}\x{5D69}\x{5D6A}\x{5D6B}\x{5D6C}\x{5D6D}\x{5D6E}\x{5D6F}' .
          '\x{5D70}\x{5D71}\x{5D72}\x{5D73}\x{5D74}\x{5D75}\x{5D76}\x{5D77}\x{5D78}' .
          '\x{5D79}\x{5D7A}\x{5D7B}\x{5D7C}\x{5D7D}\x{5D7E}\x{5D7F}\x{5D80}\x{5D81}' .
          '\x{5D82}\x{5D84}\x{5D85}\x{5D86}\x{5D87}\x{5D88}\x{5D89}\x{5D8A}\x{5D8B}' .
          '\x{5D8C}\x{5D8D}\x{5D8E}\x{5D8F}\x{5D90}\x{5D91}\x{5D92}\x{5D93}\x{5D94}' .
          '\x{5D95}\x{5D97}\x{5D98}\x{5D99}\x{5D9A}\x{5D9B}\x{5D9C}\x{5D9D}\x{5D9E}' .
          '\x{5D9F}\x{5DA0}\x{5DA1}\x{5DA2}\x{5DA5}\x{5DA6}\x{5DA7}\x{5DA8}\x{5DA9}' .
          '\x{5DAA}\x{5DAC}\x{5DAD}\x{5DAE}\x{5DAF}\x{5DB0}\x{5DB1}\x{5DB2}\x{5DB4}' .
          '\x{5DB5}\x{5DB6}\x{5DB7}\x{5DB8}\x{5DBA}\x{5DBB}\x{5DBC}\x{5DBD}\x{5DBE}' .
          '\x{5DBF}\x{5DC0}\x{5DC1}\x{5DC2}\x{5DC3}\x{5DC5}\x{5DC6}\x{5DC7}\x{5DC8}' .
          '\x{5DC9}\x{5DCA}\x{5DCB}\x{5DCC}\x{5DCD}\x{5DCE}\x{5DCF}\x{5DD0}\x{5DD1}' .
          '\x{5DD2}\x{5DD3}\x{5DD4}\x{5DD5}\x{5DD6}\x{5DD8}\x{5DD9}\x{5DDB}\x{5DDD}' .
          '\x{5DDE}\x{5DDF}\x{5DE0}\x{5DE1}\x{5DE2}\x{5DE3}\x{5DE4}\x{5DE5}\x{5DE6}' .
          '\x{5DE7}\x{5DE8}\x{5DE9}\x{5DEA}\x{5DEB}\x{5DEC}\x{5DED}\x{5DEE}\x{5DEF}' .
          '\x{5DF0}\x{5DF1}\x{5DF2}\x{5DF3}\x{5DF4}\x{5DF5}\x{5DF7}\x{5DF8}\x{5DF9}' .
          '\x{5DFA}\x{5DFB}\x{5DFC}\x{5DFD}\x{5DFE}\x{5DFF}\x{5E00}\x{5E01}\x{5E02}' .
          '\x{5E03}\x{5E04}\x{5E05}\x{5E06}\x{5E07}\x{5E08}\x{5E09}\x{5E0A}\x{5E0B}' .
          '\x{5E0C}\x{5E0D}\x{5E0E}\x{5E0F}\x{5E10}\x{5E11}\x{5E13}\x{5E14}\x{5E15}' .
          '\x{5E16}\x{5E17}\x{5E18}\x{5E19}\x{5E1A}\x{5E1B}\x{5E1C}\x{5E1D}\x{5E1E}' .
          '\x{5E1F}\x{5E20}\x{5E21}\x{5E22}\x{5E23}\x{5E24}\x{5E25}\x{5E26}\x{5E27}' .
          '\x{5E28}\x{5E29}\x{5E2A}\x{5E2B}\x{5E2C}\x{5E2D}\x{5E2E}\x{5E2F}\x{5E30}' .
          '\x{5E31}\x{5E32}\x{5E33}\x{5E34}\x{5E35}\x{5E36}\x{5E37}\x{5E38}\x{5E39}' .
          '\x{5E3A}\x{5E3B}\x{5E3C}\x{5E3D}\x{5E3E}\x{5E40}\x{5E41}\x{5E42}\x{5E43}' .
          '\x{5E44}\x{5E45}\x{5E46}\x{5E47}\x{5E49}\x{5E4A}\x{5E4B}\x{5E4C}\x{5E4D}' .
          '\x{5E4E}\x{5E4F}\x{5E50}\x{5E52}\x{5E53}\x{5E54}\x{5E55}\x{5E56}\x{5E57}' .
          '\x{5E58}\x{5E59}\x{5E5A}\x{5E5B}\x{5E5C}\x{5E5D}\x{5E5E}\x{5E5F}\x{5E60}' .
          '\x{5E61}\x{5E62}\x{5E63}\x{5E64}\x{5E65}\x{5E66}\x{5E67}\x{5E68}\x{5E69}' .
          '\x{5E6A}\x{5E6B}\x{5E6C}\x{5E6D}\x{5E6E}\x{5E6F}\x{5E70}\x{5E71}\x{5E72}' .
          '\x{5E73}\x{5E74}\x{5E75}\x{5E76}\x{5E77}\x{5E78}\x{5E79}\x{5E7A}\x{5E7B}' .
          '\x{5E7C}\x{5E7D}\x{5E7E}\x{5E7F}\x{5E80}\x{5E81}\x{5E82}\x{5E83}\x{5E84}' .
          '\x{5E85}\x{5E86}\x{5E87}\x{5E88}\x{5E89}\x{5E8A}\x{5E8B}\x{5E8C}\x{5E8D}' .
          '\x{5E8E}\x{5E8F}\x{5E90}\x{5E91}\x{5E93}\x{5E94}\x{5E95}\x{5E96}\x{5E97}' .
          '\x{5E98}\x{5E99}\x{5E9A}\x{5E9B}\x{5E9C}\x{5E9D}\x{5E9E}\x{5E9F}\x{5EA0}' .
          '\x{5EA1}\x{5EA2}\x{5EA3}\x{5EA4}\x{5EA5}\x{5EA6}\x{5EA7}\x{5EA8}\x{5EA9}' .
          '\x{5EAA}\x{5EAB}\x{5EAC}\x{5EAD}\x{5EAE}\x{5EAF}\x{5EB0}\x{5EB1}\x{5EB2}' .
          '\x{5EB3}\x{5EB4}\x{5EB5}\x{5EB6}\x{5EB7}\x{5EB8}\x{5EB9}\x{5EBB}\x{5EBC}' .
          '\x{5EBD}\x{5EBE}\x{5EBF}\x{5EC1}\x{5EC2}\x{5EC3}\x{5EC4}\x{5EC5}\x{5EC6}' .
          '\x{5EC7}\x{5EC8}\x{5EC9}\x{5ECA}\x{5ECB}\x{5ECC}\x{5ECD}\x{5ECE}\x{5ECF}' .
          '\x{5ED0}\x{5ED1}\x{5ED2}\x{5ED3}\x{5ED4}\x{5ED5}\x{5ED6}\x{5ED7}\x{5ED8}' .
          '\x{5ED9}\x{5EDA}\x{5EDB}\x{5EDC}\x{5EDD}\x{5EDE}\x{5EDF}\x{5EE0}\x{5EE1}' .
          '\x{5EE2}\x{5EE3}\x{5EE4}\x{5EE5}\x{5EE6}\x{5EE7}\x{5EE8}\x{5EE9}\x{5EEA}' .
          '\x{5EEC}\x{5EED}\x{5EEE}\x{5EEF}\x{5EF0}\x{5EF1}\x{5EF2}\x{5EF3}\x{5EF4}' .
          '\x{5EF5}\x{5EF6}\x{5EF7}\x{5EF8}\x{5EFA}\x{5EFB}\x{5EFC}\x{5EFD}\x{5EFE}' .
          '\x{5EFF}\x{5F00}\x{5F01}\x{5F02}\x{5F03}\x{5F04}\x{5F05}\x{5F06}\x{5F07}' .
          '\x{5F08}\x{5F0A}\x{5F0B}\x{5F0C}\x{5F0D}\x{5F0F}\x{5F11}\x{5F12}\x{5F13}' .
          '\x{5F14}\x{5F15}\x{5F16}\x{5F17}\x{5F18}\x{5F19}\x{5F1A}\x{5F1B}\x{5F1C}' .
          '\x{5F1D}\x{5F1E}\x{5F1F}\x{5F20}\x{5F21}\x{5F22}\x{5F23}\x{5F24}\x{5F25}' .
          '\x{5F26}\x{5F27}\x{5F28}\x{5F29}\x{5F2A}\x{5F2B}\x{5F2C}\x{5F2D}\x{5F2E}' .
          '\x{5F2F}\x{5F30}\x{5F31}\x{5F32}\x{5F33}\x{5F34}\x{5F35}\x{5F36}\x{5F37}' .
          '\x{5F38}\x{5F39}\x{5F3A}\x{5F3C}\x{5F3E}\x{5F3F}\x{5F40}\x{5F41}\x{5F42}' .
          '\x{5F43}\x{5F44}\x{5F45}\x{5F46}\x{5F47}\x{5F48}\x{5F49}\x{5F4A}\x{5F4B}' .
          '\x{5F4C}\x{5F4D}\x{5F4E}\x{5F4F}\x{5F50}\x{5F51}\x{5F52}\x{5F53}\x{5F54}' .
          '\x{5F55}\x{5F56}\x{5F57}\x{5F58}\x{5F59}\x{5F5A}\x{5F5B}\x{5F5C}\x{5F5D}' .
          '\x{5F5E}\x{5F5F}\x{5F60}\x{5F61}\x{5F62}\x{5F63}\x{5F64}\x{5F65}\x{5F66}' .
          '\x{5F67}\x{5F68}\x{5F69}\x{5F6A}\x{5F6B}\x{5F6C}\x{5F6D}\x{5F6E}\x{5F6F}' .
          '\x{5F70}\x{5F71}\x{5F72}\x{5F73}\x{5F74}\x{5F75}\x{5F76}\x{5F77}\x{5F78}' .
          '\x{5F79}\x{5F7A}\x{5F7B}\x{5F7C}\x{5F7D}\x{5F7E}\x{5F7F}\x{5F80}\x{5F81}' .
          '\x{5F82}\x{5F83}\x{5F84}\x{5F85}\x{5F86}\x{5F87}\x{5F88}\x{5F89}\x{5F8A}' .
          '\x{5F8B}\x{5F8C}\x{5F8D}\x{5F8E}\x{5F90}\x{5F91}\x{5F92}\x{5F93}\x{5F94}' .
          '\x{5F95}\x{5F96}\x{5F97}\x{5F98}\x{5F99}\x{5F9B}\x{5F9C}\x{5F9D}\x{5F9E}' .
          '\x{5F9F}\x{5FA0}\x{5FA1}\x{5FA2}\x{5FA5}\x{5FA6}\x{5FA7}\x{5FA8}\x{5FA9}' .
          '\x{5FAA}\x{5FAB}\x{5FAC}\x{5FAD}\x{5FAE}\x{5FAF}\x{5FB1}\x{5FB2}\x{5FB3}' .
          '\x{5FB4}\x{5FB5}\x{5FB6}\x{5FB7}\x{5FB8}\x{5FB9}\x{5FBA}\x{5FBB}\x{5FBC}' .
          '\x{5FBD}\x{5FBE}\x{5FBF}\x{5FC0}\x{5FC1}\x{5FC3}\x{5FC4}\x{5FC5}\x{5FC6}' .
          '\x{5FC7}\x{5FC8}\x{5FC9}\x{5FCA}\x{5FCB}\x{5FCC}\x{5FCD}\x{5FCF}\x{5FD0}' .
          '\x{5FD1}\x{5FD2}\x{5FD3}\x{5FD4}\x{5FD5}\x{5FD6}\x{5FD7}\x{5FD8}\x{5FD9}' .
          '\x{5FDA}\x{5FDC}\x{5FDD}\x{5FDE}\x{5FE0}\x{5FE1}\x{5FE3}\x{5FE4}\x{5FE5}' .
          '\x{5FE6}\x{5FE7}\x{5FE8}\x{5FE9}\x{5FEA}\x{5FEB}\x{5FED}\x{5FEE}\x{5FEF}' .
          '\x{5FF0}\x{5FF1}\x{5FF2}\x{5FF3}\x{5FF4}\x{5FF5}\x{5FF6}\x{5FF7}\x{5FF8}' .
          '\x{5FF9}\x{5FFA}\x{5FFB}\x{5FFD}\x{5FFE}\x{5FFF}\x{6000}\x{6001}\x{6002}' .
          '\x{6003}\x{6004}\x{6005}\x{6006}\x{6007}\x{6008}\x{6009}\x{600A}\x{600B}' .
          '\x{600C}\x{600D}\x{600E}\x{600F}\x{6010}\x{6011}\x{6012}\x{6013}\x{6014}' .
          '\x{6015}\x{6016}\x{6017}\x{6018}\x{6019}\x{601A}\x{601B}\x{601C}\x{601D}' .
          '\x{601E}\x{601F}\x{6020}\x{6021}\x{6022}\x{6024}\x{6025}\x{6026}\x{6027}' .
          '\x{6028}\x{6029}\x{602A}\x{602B}\x{602C}\x{602D}\x{602E}\x{602F}\x{6030}' .
          '\x{6031}\x{6032}\x{6033}\x{6034}\x{6035}\x{6036}\x{6037}\x{6038}\x{6039}' .
          '\x{603A}\x{603B}\x{603C}\x{603D}\x{603E}\x{603F}\x{6040}\x{6041}\x{6042}' .
          '\x{6043}\x{6044}\x{6045}\x{6046}\x{6047}\x{6048}\x{6049}\x{604A}\x{604B}' .
          '\x{604C}\x{604D}\x{604E}\x{604F}\x{6050}\x{6051}\x{6052}\x{6053}\x{6054}' .
          '\x{6055}\x{6057}\x{6058}\x{6059}\x{605A}\x{605B}\x{605C}\x{605D}\x{605E}' .
          '\x{605F}\x{6062}\x{6063}\x{6064}\x{6065}\x{6066}\x{6067}\x{6068}\x{6069}' .
          '\x{606A}\x{606B}\x{606C}\x{606D}\x{606E}\x{606F}\x{6070}\x{6072}\x{6073}' .
          '\x{6075}\x{6076}\x{6077}\x{6078}\x{6079}\x{607A}\x{607B}\x{607C}\x{607D}' .
          '\x{607E}\x{607F}\x{6080}\x{6081}\x{6082}\x{6083}\x{6084}\x{6085}\x{6086}' .
          '\x{6087}\x{6088}\x{6089}\x{608A}\x{608B}\x{608C}\x{608D}\x{608E}\x{608F}' .
          '\x{6090}\x{6092}\x{6094}\x{6095}\x{6096}\x{6097}\x{6098}\x{6099}\x{609A}' .
          '\x{609B}\x{609C}\x{609D}\x{609E}\x{609F}\x{60A0}\x{60A1}\x{60A2}\x{60A3}' .
          '\x{60A4}\x{60A6}\x{60A7}\x{60A8}\x{60AA}\x{60AB}\x{60AC}\x{60AD}\x{60AE}' .
          '\x{60AF}\x{60B0}\x{60B1}\x{60B2}\x{60B3}\x{60B4}\x{60B5}\x{60B6}\x{60B7}' .
          '\x{60B8}\x{60B9}\x{60BA}\x{60BB}\x{60BC}\x{60BD}\x{60BE}\x{60BF}\x{60C0}' .
          '\x{60C1}\x{60C2}\x{60C3}\x{60C4}\x{60C5}\x{60C6}\x{60C7}\x{60C8}\x{60C9}' .
          '\x{60CA}\x{60CB}\x{60CC}\x{60CD}\x{60CE}\x{60CF}\x{60D0}\x{60D1}\x{60D3}' .
          '\x{60D4}\x{60D5}\x{60D7}\x{60D8}\x{60D9}\x{60DA}\x{60DB}\x{60DC}\x{60DD}' .
          '\x{60DF}\x{60E0}\x{60E1}\x{60E2}\x{60E4}\x{60E6}\x{60E7}\x{60E8}\x{60E9}' .
          '\x{60EA}\x{60EB}\x{60EC}\x{60ED}\x{60EE}\x{60EF}\x{60F0}\x{60F1}\x{60F2}' .
          '\x{60F3}\x{60F4}\x{60F5}\x{60F6}\x{60F7}\x{60F8}\x{60F9}\x{60FA}\x{60FB}' .
          '\x{60FC}\x{60FE}\x{60FF}\x{6100}\x{6101}\x{6103}\x{6104}\x{6105}\x{6106}' .
          '\x{6108}\x{6109}\x{610A}\x{610B}\x{610C}\x{610D}\x{610E}\x{610F}\x{6110}' .
          '\x{6112}\x{6113}\x{6114}\x{6115}\x{6116}\x{6117}\x{6118}\x{6119}\x{611A}' .
          '\x{611B}\x{611C}\x{611D}\x{611F}\x{6120}\x{6122}\x{6123}\x{6124}\x{6125}' .
          '\x{6126}\x{6127}\x{6128}\x{6129}\x{612A}\x{612B}\x{612C}\x{612D}\x{612E}' .
          '\x{612F}\x{6130}\x{6132}\x{6134}\x{6136}\x{6137}\x{613A}\x{613B}\x{613C}' .
          '\x{613D}\x{613E}\x{613F}\x{6140}\x{6141}\x{6142}\x{6143}\x{6144}\x{6145}' .
          '\x{6146}\x{6147}\x{6148}\x{6149}\x{614A}\x{614B}\x{614C}\x{614D}\x{614E}' .
          '\x{614F}\x{6150}\x{6151}\x{6152}\x{6153}\x{6154}\x{6155}\x{6156}\x{6157}' .
          '\x{6158}\x{6159}\x{615A}\x{615B}\x{615C}\x{615D}\x{615E}\x{615F}\x{6161}' .
          '\x{6162}\x{6163}\x{6164}\x{6165}\x{6166}\x{6167}\x{6168}\x{6169}\x{616A}' .
          '\x{616B}\x{616C}\x{616D}\x{616E}\x{6170}\x{6171}\x{6172}\x{6173}\x{6174}' .
          '\x{6175}\x{6176}\x{6177}\x{6178}\x{6179}\x{617A}\x{617C}\x{617E}\x{6180}' .
          '\x{6181}\x{6182}\x{6183}\x{6184}\x{6185}\x{6187}\x{6188}\x{6189}\x{618A}' .
          '\x{618B}\x{618C}\x{618D}\x{618E}\x{618F}\x{6190}\x{6191}\x{6192}\x{6193}' .
          '\x{6194}\x{6195}\x{6196}\x{6198}\x{6199}\x{619A}\x{619B}\x{619D}\x{619E}' .
          '\x{619F}\x{61A0}\x{61A1}\x{61A2}\x{61A3}\x{61A4}\x{61A5}\x{61A6}\x{61A7}' .
          '\x{61A8}\x{61A9}\x{61AA}\x{61AB}\x{61AC}\x{61AD}\x{61AE}\x{61AF}\x{61B0}' .
          '\x{61B1}\x{61B2}\x{61B3}\x{61B4}\x{61B5}\x{61B6}\x{61B7}\x{61B8}\x{61BA}' .
          '\x{61BC}\x{61BD}\x{61BE}\x{61BF}\x{61C0}\x{61C1}\x{61C2}\x{61C3}\x{61C4}' .
          '\x{61C5}\x{61C6}\x{61C7}\x{61C8}\x{61C9}\x{61CA}\x{61CB}\x{61CC}\x{61CD}' .
          '\x{61CE}\x{61CF}\x{61D0}\x{61D1}\x{61D2}\x{61D4}\x{61D6}\x{61D7}\x{61D8}' .
          '\x{61D9}\x{61DA}\x{61DB}\x{61DC}\x{61DD}\x{61DE}\x{61DF}\x{61E0}\x{61E1}' .
          '\x{61E2}\x{61E3}\x{61E4}\x{61E5}\x{61E6}\x{61E7}\x{61E8}\x{61E9}\x{61EA}' .
          '\x{61EB}\x{61ED}\x{61EE}\x{61F0}\x{61F1}\x{61F2}\x{61F3}\x{61F5}\x{61F6}' .
          '\x{61F7}\x{61F8}\x{61F9}\x{61FA}\x{61FB}\x{61FC}\x{61FD}\x{61FE}\x{61FF}' .
          '\x{6200}\x{6201}\x{6202}\x{6203}\x{6204}\x{6206}\x{6207}\x{6208}\x{6209}' .
          '\x{620A}\x{620B}\x{620C}\x{620D}\x{620E}\x{620F}\x{6210}\x{6211}\x{6212}' .
          '\x{6213}\x{6214}\x{6215}\x{6216}\x{6217}\x{6218}\x{6219}\x{621A}\x{621B}' .
          '\x{621C}\x{621D}\x{621E}\x{621F}\x{6220}\x{6221}\x{6222}\x{6223}\x{6224}' .
          '\x{6225}\x{6226}\x{6227}\x{6228}\x{6229}\x{622A}\x{622B}\x{622C}\x{622D}' .
          '\x{622E}\x{622F}\x{6230}\x{6231}\x{6232}\x{6233}\x{6234}\x{6236}\x{6237}' .
          '\x{6238}\x{623A}\x{623B}\x{623C}\x{623D}\x{623E}\x{623F}\x{6240}\x{6241}' .
          '\x{6242}\x{6243}\x{6244}\x{6245}\x{6246}\x{6247}\x{6248}\x{6249}\x{624A}' .
          '\x{624B}\x{624C}\x{624D}\x{624E}\x{624F}\x{6250}\x{6251}\x{6252}\x{6253}' .
          '\x{6254}\x{6255}\x{6256}\x{6258}\x{6259}\x{625A}\x{625B}\x{625C}\x{625D}' .
          '\x{625E}\x{625F}\x{6260}\x{6261}\x{6262}\x{6263}\x{6264}\x{6265}\x{6266}' .
          '\x{6267}\x{6268}\x{6269}\x{626A}\x{626B}\x{626C}\x{626D}\x{626E}\x{626F}' .
          '\x{6270}\x{6271}\x{6272}\x{6273}\x{6274}\x{6275}\x{6276}\x{6277}\x{6278}' .
          '\x{6279}\x{627A}\x{627B}\x{627C}\x{627D}\x{627E}\x{627F}\x{6280}\x{6281}' .
          '\x{6283}\x{6284}\x{6285}\x{6286}\x{6287}\x{6288}\x{6289}\x{628A}\x{628B}' .
          '\x{628C}\x{628E}\x{628F}\x{6290}\x{6291}\x{6292}\x{6293}\x{6294}\x{6295}' .
          '\x{6296}\x{6297}\x{6298}\x{6299}\x{629A}\x{629B}\x{629C}\x{629E}\x{629F}' .
          '\x{62A0}\x{62A1}\x{62A2}\x{62A3}\x{62A4}\x{62A5}\x{62A7}\x{62A8}\x{62A9}' .
          '\x{62AA}\x{62AB}\x{62AC}\x{62AD}\x{62AE}\x{62AF}\x{62B0}\x{62B1}\x{62B2}' .
          '\x{62B3}\x{62B4}\x{62B5}\x{62B6}\x{62B7}\x{62B8}\x{62B9}\x{62BA}\x{62BB}' .
          '\x{62BC}\x{62BD}\x{62BE}\x{62BF}\x{62C0}\x{62C1}\x{62C2}\x{62C3}\x{62C4}' .
          '\x{62C5}\x{62C6}\x{62C7}\x{62C8}\x{62C9}\x{62CA}\x{62CB}\x{62CC}\x{62CD}' .
          '\x{62CE}\x{62CF}\x{62D0}\x{62D1}\x{62D2}\x{62D3}\x{62D4}\x{62D5}\x{62D6}' .
          '\x{62D7}\x{62D8}\x{62D9}\x{62DA}\x{62DB}\x{62DC}\x{62DD}\x{62DF}\x{62E0}' .
          '\x{62E1}\x{62E2}\x{62E3}\x{62E4}\x{62E5}\x{62E6}\x{62E7}\x{62E8}\x{62E9}' .
          '\x{62EB}\x{62EC}\x{62ED}\x{62EE}\x{62EF}\x{62F0}\x{62F1}\x{62F2}\x{62F3}' .
          '\x{62F4}\x{62F5}\x{62F6}\x{62F7}\x{62F8}\x{62F9}\x{62FA}\x{62FB}\x{62FC}' .
          '\x{62FD}\x{62FE}\x{62FF}\x{6300}\x{6301}\x{6302}\x{6303}\x{6304}\x{6305}' .
          '\x{6306}\x{6307}\x{6308}\x{6309}\x{630B}\x{630C}\x{630D}\x{630E}\x{630F}' .
          '\x{6310}\x{6311}\x{6312}\x{6313}\x{6314}\x{6315}\x{6316}\x{6318}\x{6319}' .
          '\x{631A}\x{631B}\x{631C}\x{631D}\x{631E}\x{631F}\x{6320}\x{6321}\x{6322}' .
          '\x{6323}\x{6324}\x{6325}\x{6326}\x{6327}\x{6328}\x{6329}\x{632A}\x{632B}' .
          '\x{632C}\x{632D}\x{632E}\x{632F}\x{6330}\x{6332}\x{6333}\x{6334}\x{6336}' .
          '\x{6338}\x{6339}\x{633A}\x{633B}\x{633C}\x{633D}\x{633E}\x{6340}\x{6341}' .
          '\x{6342}\x{6343}\x{6344}\x{6345}\x{6346}\x{6347}\x{6348}\x{6349}\x{634A}' .
          '\x{634B}\x{634C}\x{634D}\x{634E}\x{634F}\x{6350}\x{6351}\x{6352}\x{6353}' .
          '\x{6354}\x{6355}\x{6356}\x{6357}\x{6358}\x{6359}\x{635A}\x{635C}\x{635D}' .
          '\x{635E}\x{635F}\x{6360}\x{6361}\x{6362}\x{6363}\x{6364}\x{6365}\x{6366}' .
          '\x{6367}\x{6368}\x{6369}\x{636A}\x{636B}\x{636C}\x{636D}\x{636E}\x{636F}' .
          '\x{6370}\x{6371}\x{6372}\x{6373}\x{6374}\x{6375}\x{6376}\x{6377}\x{6378}' .
          '\x{6379}\x{637A}\x{637B}\x{637C}\x{637D}\x{637E}\x{6380}\x{6381}\x{6382}' .
          '\x{6383}\x{6384}\x{6385}\x{6386}\x{6387}\x{6388}\x{6389}\x{638A}\x{638C}' .
          '\x{638D}\x{638E}\x{638F}\x{6390}\x{6391}\x{6392}\x{6394}\x{6395}\x{6396}' .
          '\x{6397}\x{6398}\x{6399}\x{639A}\x{639B}\x{639C}\x{639D}\x{639E}\x{639F}' .
          '\x{63A0}\x{63A1}\x{63A2}\x{63A3}\x{63A4}\x{63A5}\x{63A6}\x{63A7}\x{63A8}' .
          '\x{63A9}\x{63AA}\x{63AB}\x{63AC}\x{63AD}\x{63AE}\x{63AF}\x{63B0}\x{63B1}' .
          '\x{63B2}\x{63B3}\x{63B4}\x{63B5}\x{63B6}\x{63B7}\x{63B8}\x{63B9}\x{63BA}' .
          '\x{63BC}\x{63BD}\x{63BE}\x{63BF}\x{63C0}\x{63C1}\x{63C2}\x{63C3}\x{63C4}' .
          '\x{63C5}\x{63C6}\x{63C7}\x{63C8}\x{63C9}\x{63CA}\x{63CB}\x{63CC}\x{63CD}' .
          '\x{63CE}\x{63CF}\x{63D0}\x{63D2}\x{63D3}\x{63D4}\x{63D5}\x{63D6}\x{63D7}' .
          '\x{63D8}\x{63D9}\x{63DA}\x{63DB}\x{63DC}\x{63DD}\x{63DE}\x{63DF}\x{63E0}' .
          '\x{63E1}\x{63E2}\x{63E3}\x{63E4}\x{63E5}\x{63E6}\x{63E7}\x{63E8}\x{63E9}' .
          '\x{63EA}\x{63EB}\x{63EC}\x{63ED}\x{63EE}\x{63EF}\x{63F0}\x{63F1}\x{63F2}' .
          '\x{63F3}\x{63F4}\x{63F5}\x{63F6}\x{63F7}\x{63F8}\x{63F9}\x{63FA}\x{63FB}' .
          '\x{63FC}\x{63FD}\x{63FE}\x{63FF}\x{6400}\x{6401}\x{6402}\x{6403}\x{6404}' .
          '\x{6405}\x{6406}\x{6408}\x{6409}\x{640A}\x{640B}\x{640C}\x{640D}\x{640E}' .
          '\x{640F}\x{6410}\x{6411}\x{6412}\x{6413}\x{6414}\x{6415}\x{6416}\x{6417}' .
          '\x{6418}\x{6419}\x{641A}\x{641B}\x{641C}\x{641D}\x{641E}\x{641F}\x{6420}' .
          '\x{6421}\x{6422}\x{6423}\x{6424}\x{6425}\x{6426}\x{6427}\x{6428}\x{6429}' .
          '\x{642A}\x{642B}\x{642C}\x{642D}\x{642E}\x{642F}\x{6430}\x{6431}\x{6432}' .
          '\x{6433}\x{6434}\x{6435}\x{6436}\x{6437}\x{6438}\x{6439}\x{643A}\x{643D}' .
          '\x{643E}\x{643F}\x{6440}\x{6441}\x{6443}\x{6444}\x{6445}\x{6446}\x{6447}' .
          '\x{6448}\x{644A}\x{644B}\x{644C}\x{644D}\x{644E}\x{644F}\x{6450}\x{6451}' .
          '\x{6452}\x{6453}\x{6454}\x{6455}\x{6456}\x{6457}\x{6458}\x{6459}\x{645B}' .
          '\x{645C}\x{645D}\x{645E}\x{645F}\x{6460}\x{6461}\x{6462}\x{6463}\x{6464}' .
          '\x{6465}\x{6466}\x{6467}\x{6468}\x{6469}\x{646A}\x{646B}\x{646C}\x{646D}' .
          '\x{646E}\x{646F}\x{6470}\x{6471}\x{6472}\x{6473}\x{6474}\x{6475}\x{6476}' .
          '\x{6477}\x{6478}\x{6479}\x{647A}\x{647B}\x{647C}\x{647D}\x{647F}\x{6480}' .
          '\x{6481}\x{6482}\x{6483}\x{6484}\x{6485}\x{6487}\x{6488}\x{6489}\x{648A}' .
          '\x{648B}\x{648C}\x{648D}\x{648E}\x{648F}\x{6490}\x{6491}\x{6492}\x{6493}' .
          '\x{6494}\x{6495}\x{6496}\x{6497}\x{6498}\x{6499}\x{649A}\x{649B}\x{649C}' .
          '\x{649D}\x{649E}\x{649F}\x{64A0}\x{64A2}\x{64A3}\x{64A4}\x{64A5}\x{64A6}' .
          '\x{64A7}\x{64A8}\x{64A9}\x{64AA}\x{64AB}\x{64AC}\x{64AD}\x{64AE}\x{64B0}' .
          '\x{64B1}\x{64B2}\x{64B3}\x{64B4}\x{64B5}\x{64B7}\x{64B8}\x{64B9}\x{64BA}' .
          '\x{64BB}\x{64BC}\x{64BD}\x{64BE}\x{64BF}\x{64C0}\x{64C1}\x{64C2}\x{64C3}' .
          '\x{64C4}\x{64C5}\x{64C6}\x{64C7}\x{64C9}\x{64CA}\x{64CB}\x{64CC}\x{64CD}' .
          '\x{64CE}\x{64CF}\x{64D0}\x{64D1}\x{64D2}\x{64D3}\x{64D4}\x{64D6}\x{64D7}' .
          '\x{64D8}\x{64D9}\x{64DA}\x{64DB}\x{64DC}\x{64DD}\x{64DE}\x{64DF}\x{64E0}' .
          '\x{64E2}\x{64E3}\x{64E4}\x{64E6}\x{64E7}\x{64E8}\x{64E9}\x{64EA}\x{64EB}' .
          '\x{64EC}\x{64ED}\x{64EF}\x{64F0}\x{64F1}\x{64F2}\x{64F3}\x{64F4}\x{64F6}' .
          '\x{64F7}\x{64F8}\x{64FA}\x{64FB}\x{64FC}\x{64FD}\x{64FE}\x{64FF}\x{6500}' .
          '\x{6501}\x{6503}\x{6504}\x{6505}\x{6506}\x{6507}\x{6508}\x{6509}\x{650B}' .
          '\x{650C}\x{650D}\x{650E}\x{650F}\x{6510}\x{6511}\x{6512}\x{6513}\x{6514}' .
          '\x{6515}\x{6516}\x{6517}\x{6518}\x{6519}\x{651A}\x{651B}\x{651C}\x{651D}' .
          '\x{651E}\x{6520}\x{6521}\x{6522}\x{6523}\x{6524}\x{6525}\x{6526}\x{6527}' .
          '\x{6529}\x{652A}\x{652B}\x{652C}\x{652D}\x{652E}\x{652F}\x{6530}\x{6531}' .
          '\x{6532}\x{6533}\x{6534}\x{6535}\x{6536}\x{6537}\x{6538}\x{6539}\x{653A}' .
          '\x{653B}\x{653C}\x{653D}\x{653E}\x{653F}\x{6541}\x{6543}\x{6544}\x{6545}' .
          '\x{6546}\x{6547}\x{6548}\x{6549}\x{654A}\x{654B}\x{654C}\x{654D}\x{654E}' .
          '\x{654F}\x{6550}\x{6551}\x{6552}\x{6553}\x{6554}\x{6555}\x{6556}\x{6557}' .
          '\x{6558}\x{6559}\x{655B}\x{655C}\x{655D}\x{655E}\x{6560}\x{6561}\x{6562}' .
          '\x{6563}\x{6564}\x{6565}\x{6566}\x{6567}\x{6568}\x{6569}\x{656A}\x{656B}' .
          '\x{656C}\x{656E}\x{656F}\x{6570}\x{6571}\x{6572}\x{6573}\x{6574}\x{6575}' .
          '\x{6576}\x{6577}\x{6578}\x{6579}\x{657A}\x{657B}\x{657C}\x{657E}\x{657F}' .
          '\x{6580}\x{6581}\x{6582}\x{6583}\x{6584}\x{6585}\x{6586}\x{6587}\x{6588}' .
          '\x{6589}\x{658B}\x{658C}\x{658D}\x{658E}\x{658F}\x{6590}\x{6591}\x{6592}' .
          '\x{6593}\x{6594}\x{6595}\x{6596}\x{6597}\x{6598}\x{6599}\x{659B}\x{659C}' .
          '\x{659D}\x{659E}\x{659F}\x{65A0}\x{65A1}\x{65A2}\x{65A3}\x{65A4}\x{65A5}' .
          '\x{65A6}\x{65A7}\x{65A8}\x{65A9}\x{65AA}\x{65AB}\x{65AC}\x{65AD}\x{65AE}' .
          '\x{65AF}\x{65B0}\x{65B1}\x{65B2}\x{65B3}\x{65B4}\x{65B6}\x{65B7}\x{65B8}' .
          '\x{65B9}\x{65BA}\x{65BB}\x{65BC}\x{65BD}\x{65BF}\x{65C0}\x{65C1}\x{65C2}' .
          '\x{65C3}\x{65C4}\x{65C5}\x{65C6}\x{65C7}\x{65CA}\x{65CB}\x{65CC}\x{65CD}' .
          '\x{65CE}\x{65CF}\x{65D0}\x{65D2}\x{65D3}\x{65D4}\x{65D5}\x{65D6}\x{65D7}' .
          '\x{65DA}\x{65DB}\x{65DD}\x{65DE}\x{65DF}\x{65E0}\x{65E1}\x{65E2}\x{65E3}' .
          '\x{65E5}\x{65E6}\x{65E7}\x{65E8}\x{65E9}\x{65EB}\x{65EC}\x{65ED}\x{65EE}' .
          '\x{65EF}\x{65F0}\x{65F1}\x{65F2}\x{65F3}\x{65F4}\x{65F5}\x{65F6}\x{65F7}' .
          '\x{65F8}\x{65FA}\x{65FB}\x{65FC}\x{65FD}\x{6600}\x{6601}\x{6602}\x{6603}' .
          '\x{6604}\x{6605}\x{6606}\x{6607}\x{6608}\x{6609}\x{660A}\x{660B}\x{660C}' .
          '\x{660D}\x{660E}\x{660F}\x{6610}\x{6611}\x{6612}\x{6613}\x{6614}\x{6615}' .
          '\x{6616}\x{6618}\x{6619}\x{661A}\x{661B}\x{661C}\x{661D}\x{661F}\x{6620}' .
          '\x{6621}\x{6622}\x{6623}\x{6624}\x{6625}\x{6626}\x{6627}\x{6628}\x{6629}' .
          '\x{662A}\x{662B}\x{662D}\x{662E}\x{662F}\x{6630}\x{6631}\x{6632}\x{6633}' .
          '\x{6634}\x{6635}\x{6636}\x{6639}\x{663A}\x{663C}\x{663D}\x{663E}\x{6640}' .
          '\x{6641}\x{6642}\x{6643}\x{6644}\x{6645}\x{6646}\x{6647}\x{6649}\x{664A}' .
          '\x{664B}\x{664C}\x{664E}\x{664F}\x{6650}\x{6651}\x{6652}\x{6653}\x{6654}' .
          '\x{6655}\x{6656}\x{6657}\x{6658}\x{6659}\x{665A}\x{665B}\x{665C}\x{665D}' .
          '\x{665E}\x{665F}\x{6661}\x{6662}\x{6664}\x{6665}\x{6666}\x{6668}\x{6669}' .
          '\x{666A}\x{666B}\x{666C}\x{666D}\x{666E}\x{666F}\x{6670}\x{6671}\x{6672}' .
          '\x{6673}\x{6674}\x{6675}\x{6676}\x{6677}\x{6678}\x{6679}\x{667A}\x{667B}' .
          '\x{667C}\x{667D}\x{667E}\x{667F}\x{6680}\x{6681}\x{6682}\x{6683}\x{6684}' .
          '\x{6685}\x{6686}\x{6687}\x{6688}\x{6689}\x{668A}\x{668B}\x{668C}\x{668D}' .
          '\x{668E}\x{668F}\x{6690}\x{6691}\x{6693}\x{6694}\x{6695}\x{6696}\x{6697}' .
          '\x{6698}\x{6699}\x{669A}\x{669B}\x{669D}\x{669F}\x{66A0}\x{66A1}\x{66A2}' .
          '\x{66A3}\x{66A4}\x{66A5}\x{66A6}\x{66A7}\x{66A8}\x{66A9}\x{66AA}\x{66AB}' .
          '\x{66AE}\x{66AF}\x{66B0}\x{66B1}\x{66B2}\x{66B3}\x{66B4}\x{66B5}\x{66B6}' .
          '\x{66B7}\x{66B8}\x{66B9}\x{66BA}\x{66BB}\x{66BC}\x{66BD}\x{66BE}\x{66BF}' .
          '\x{66C0}\x{66C1}\x{66C2}\x{66C3}\x{66C4}\x{66C5}\x{66C6}\x{66C7}\x{66C8}' .
          '\x{66C9}\x{66CA}\x{66CB}\x{66CC}\x{66CD}\x{66CE}\x{66CF}\x{66D1}\x{66D2}' .
          '\x{66D4}\x{66D5}\x{66D6}\x{66D8}\x{66D9}\x{66DA}\x{66DB}\x{66DC}\x{66DD}' .
          '\x{66DE}\x{66E0}\x{66E1}\x{66E2}\x{66E3}\x{66E4}\x{66E5}\x{66E6}\x{66E7}' .
          '\x{66E8}\x{66E9}\x{66EA}\x{66EB}\x{66EC}\x{66ED}\x{66EE}\x{66F0}\x{66F1}' .
          '\x{66F2}\x{66F3}\x{66F4}\x{66F5}\x{66F6}\x{66F7}\x{66F8}\x{66F9}\x{66FA}' .
          '\x{66FB}\x{66FC}\x{66FE}\x{66FF}\x{6700}\x{6701}\x{6703}\x{6704}\x{6705}' .
          '\x{6706}\x{6708}\x{6709}\x{670A}\x{670B}\x{670C}\x{670D}\x{670E}\x{670F}' .
          '\x{6710}\x{6711}\x{6712}\x{6713}\x{6714}\x{6715}\x{6716}\x{6717}\x{6718}' .
          '\x{671A}\x{671B}\x{671C}\x{671D}\x{671E}\x{671F}\x{6720}\x{6721}\x{6722}' .
          '\x{6723}\x{6725}\x{6726}\x{6727}\x{6728}\x{672A}\x{672B}\x{672C}\x{672D}' .
          '\x{672E}\x{672F}\x{6730}\x{6731}\x{6732}\x{6733}\x{6734}\x{6735}\x{6736}' .
          '\x{6737}\x{6738}\x{6739}\x{673A}\x{673B}\x{673C}\x{673D}\x{673E}\x{673F}' .
          '\x{6740}\x{6741}\x{6742}\x{6743}\x{6744}\x{6745}\x{6746}\x{6747}\x{6748}' .
          '\x{6749}\x{674A}\x{674B}\x{674C}\x{674D}\x{674E}\x{674F}\x{6750}\x{6751}' .
          '\x{6752}\x{6753}\x{6754}\x{6755}\x{6756}\x{6757}\x{6758}\x{6759}\x{675A}' .
          '\x{675B}\x{675C}\x{675D}\x{675E}\x{675F}\x{6760}\x{6761}\x{6762}\x{6763}' .
          '\x{6764}\x{6765}\x{6766}\x{6768}\x{6769}\x{676A}\x{676B}\x{676C}\x{676D}' .
          '\x{676E}\x{676F}\x{6770}\x{6771}\x{6772}\x{6773}\x{6774}\x{6775}\x{6776}' .
          '\x{6777}\x{6778}\x{6779}\x{677A}\x{677B}\x{677C}\x{677D}\x{677E}\x{677F}' .
          '\x{6780}\x{6781}\x{6782}\x{6783}\x{6784}\x{6785}\x{6786}\x{6787}\x{6789}' .
          '\x{678A}\x{678B}\x{678C}\x{678D}\x{678E}\x{678F}\x{6790}\x{6791}\x{6792}' .
          '\x{6793}\x{6794}\x{6795}\x{6797}\x{6798}\x{6799}\x{679A}\x{679B}\x{679C}' .
          '\x{679D}\x{679E}\x{679F}\x{67A0}\x{67A1}\x{67A2}\x{67A3}\x{67A4}\x{67A5}' .
          '\x{67A6}\x{67A7}\x{67A8}\x{67AA}\x{67AB}\x{67AC}\x{67AD}\x{67AE}\x{67AF}' .
          '\x{67B0}\x{67B1}\x{67B2}\x{67B3}\x{67B4}\x{67B5}\x{67B6}\x{67B7}\x{67B8}' .
          '\x{67B9}\x{67BA}\x{67BB}\x{67BC}\x{67BE}\x{67C0}\x{67C1}\x{67C2}\x{67C3}' .
          '\x{67C4}\x{67C5}\x{67C6}\x{67C7}\x{67C8}\x{67C9}\x{67CA}\x{67CB}\x{67CC}' .
          '\x{67CD}\x{67CE}\x{67CF}\x{67D0}\x{67D1}\x{67D2}\x{67D3}\x{67D4}\x{67D6}' .
          '\x{67D8}\x{67D9}\x{67DA}\x{67DB}\x{67DC}\x{67DD}\x{67DE}\x{67DF}\x{67E0}' .
          '\x{67E1}\x{67E2}\x{67E3}\x{67E4}\x{67E5}\x{67E6}\x{67E7}\x{67E8}\x{67E9}' .
          '\x{67EA}\x{67EB}\x{67EC}\x{67ED}\x{67EE}\x{67EF}\x{67F0}\x{67F1}\x{67F2}' .
          '\x{67F3}\x{67F4}\x{67F5}\x{67F6}\x{67F7}\x{67F8}\x{67FA}\x{67FB}\x{67FC}' .
          '\x{67FD}\x{67FE}\x{67FF}\x{6800}\x{6802}\x{6803}\x{6804}\x{6805}\x{6806}' .
          '\x{6807}\x{6808}\x{6809}\x{680A}\x{680B}\x{680C}\x{680D}\x{680E}\x{680F}' .
          '\x{6810}\x{6811}\x{6812}\x{6813}\x{6814}\x{6816}\x{6817}\x{6818}\x{6819}' .
          '\x{681A}\x{681B}\x{681C}\x{681D}\x{681F}\x{6820}\x{6821}\x{6822}\x{6823}' .
          '\x{6824}\x{6825}\x{6826}\x{6828}\x{6829}\x{682A}\x{682B}\x{682C}\x{682D}' .
          '\x{682E}\x{682F}\x{6831}\x{6832}\x{6833}\x{6834}\x{6835}\x{6836}\x{6837}' .
          '\x{6838}\x{6839}\x{683A}\x{683B}\x{683C}\x{683D}\x{683E}\x{683F}\x{6840}' .
          '\x{6841}\x{6842}\x{6843}\x{6844}\x{6845}\x{6846}\x{6847}\x{6848}\x{6849}' .
          '\x{684A}\x{684B}\x{684C}\x{684D}\x{684E}\x{684F}\x{6850}\x{6851}\x{6852}' .
          '\x{6853}\x{6854}\x{6855}\x{6856}\x{6857}\x{685B}\x{685D}\x{6860}\x{6861}' .
          '\x{6862}\x{6863}\x{6864}\x{6865}\x{6866}\x{6867}\x{6868}\x{6869}\x{686A}' .
          '\x{686B}\x{686C}\x{686D}\x{686E}\x{686F}\x{6870}\x{6871}\x{6872}\x{6873}' .
          '\x{6874}\x{6875}\x{6876}\x{6877}\x{6878}\x{6879}\x{687B}\x{687C}\x{687D}' .
          '\x{687E}\x{687F}\x{6880}\x{6881}\x{6882}\x{6883}\x{6884}\x{6885}\x{6886}' .
          '\x{6887}\x{6888}\x{6889}\x{688A}\x{688B}\x{688C}\x{688D}\x{688E}\x{688F}' .
          '\x{6890}\x{6891}\x{6892}\x{6893}\x{6894}\x{6896}\x{6897}\x{6898}\x{689A}' .
          '\x{689B}\x{689C}\x{689D}\x{689E}\x{689F}\x{68A0}\x{68A1}\x{68A2}\x{68A3}' .
          '\x{68A4}\x{68A6}\x{68A7}\x{68A8}\x{68A9}\x{68AA}\x{68AB}\x{68AC}\x{68AD}' .
          '\x{68AE}\x{68AF}\x{68B0}\x{68B1}\x{68B2}\x{68B3}\x{68B4}\x{68B5}\x{68B6}' .
          '\x{68B7}\x{68B9}\x{68BB}\x{68BC}\x{68BD}\x{68BE}\x{68BF}\x{68C0}\x{68C1}' .
          '\x{68C2}\x{68C4}\x{68C6}\x{68C7}\x{68C8}\x{68C9}\x{68CA}\x{68CB}\x{68CC}' .
          '\x{68CD}\x{68CE}\x{68CF}\x{68D0}\x{68D1}\x{68D2}\x{68D3}\x{68D4}\x{68D5}' .
          '\x{68D6}\x{68D7}\x{68D8}\x{68DA}\x{68DB}\x{68DC}\x{68DD}\x{68DE}\x{68DF}' .
          '\x{68E0}\x{68E1}\x{68E3}\x{68E4}\x{68E6}\x{68E7}\x{68E8}\x{68E9}\x{68EA}' .
          '\x{68EB}\x{68EC}\x{68ED}\x{68EE}\x{68EF}\x{68F0}\x{68F1}\x{68F2}\x{68F3}' .
          '\x{68F4}\x{68F5}\x{68F6}\x{68F7}\x{68F8}\x{68F9}\x{68FA}\x{68FB}\x{68FC}' .
          '\x{68FD}\x{68FE}\x{68FF}\x{6901}\x{6902}\x{6903}\x{6904}\x{6905}\x{6906}' .
          '\x{6907}\x{6908}\x{690A}\x{690B}\x{690C}\x{690D}\x{690E}\x{690F}\x{6910}' .
          '\x{6911}\x{6912}\x{6913}\x{6914}\x{6915}\x{6916}\x{6917}\x{6918}\x{6919}' .
          '\x{691A}\x{691B}\x{691C}\x{691D}\x{691E}\x{691F}\x{6920}\x{6921}\x{6922}' .
          '\x{6923}\x{6924}\x{6925}\x{6926}\x{6927}\x{6928}\x{6929}\x{692A}\x{692B}' .
          '\x{692C}\x{692D}\x{692E}\x{692F}\x{6930}\x{6931}\x{6932}\x{6933}\x{6934}' .
          '\x{6935}\x{6936}\x{6937}\x{6938}\x{6939}\x{693A}\x{693B}\x{693C}\x{693D}' .
          '\x{693F}\x{6940}\x{6941}\x{6942}\x{6943}\x{6944}\x{6945}\x{6946}\x{6947}' .
          '\x{6948}\x{6949}\x{694A}\x{694B}\x{694C}\x{694E}\x{694F}\x{6950}\x{6951}' .
          '\x{6952}\x{6953}\x{6954}\x{6955}\x{6956}\x{6957}\x{6958}\x{6959}\x{695A}' .
          '\x{695B}\x{695C}\x{695D}\x{695E}\x{695F}\x{6960}\x{6961}\x{6962}\x{6963}' .
          '\x{6964}\x{6965}\x{6966}\x{6967}\x{6968}\x{6969}\x{696A}\x{696B}\x{696C}' .
          '\x{696D}\x{696E}\x{696F}\x{6970}\x{6971}\x{6972}\x{6973}\x{6974}\x{6975}' .
          '\x{6976}\x{6977}\x{6978}\x{6979}\x{697A}\x{697B}\x{697C}\x{697D}\x{697E}' .
          '\x{697F}\x{6980}\x{6981}\x{6982}\x{6983}\x{6984}\x{6985}\x{6986}\x{6987}' .
          '\x{6988}\x{6989}\x{698A}\x{698B}\x{698C}\x{698D}\x{698E}\x{698F}\x{6990}' .
          '\x{6991}\x{6992}\x{6993}\x{6994}\x{6995}\x{6996}\x{6997}\x{6998}\x{6999}' .
          '\x{699A}\x{699B}\x{699C}\x{699D}\x{699E}\x{69A0}\x{69A1}\x{69A3}\x{69A4}' .
          '\x{69A5}\x{69A6}\x{69A7}\x{69A8}\x{69A9}\x{69AA}\x{69AB}\x{69AC}\x{69AD}' .
          '\x{69AE}\x{69AF}\x{69B0}\x{69B1}\x{69B2}\x{69B3}\x{69B4}\x{69B5}\x{69B6}' .
          '\x{69B7}\x{69B8}\x{69B9}\x{69BA}\x{69BB}\x{69BC}\x{69BD}\x{69BE}\x{69BF}' .
          '\x{69C1}\x{69C2}\x{69C3}\x{69C4}\x{69C5}\x{69C6}\x{69C7}\x{69C8}\x{69C9}' .
          '\x{69CA}\x{69CB}\x{69CC}\x{69CD}\x{69CE}\x{69CF}\x{69D0}\x{69D3}\x{69D4}' .
          '\x{69D8}\x{69D9}\x{69DA}\x{69DB}\x{69DC}\x{69DD}\x{69DE}\x{69DF}\x{69E0}' .
          '\x{69E1}\x{69E2}\x{69E3}\x{69E4}\x{69E5}\x{69E6}\x{69E7}\x{69E8}\x{69E9}' .
          '\x{69EA}\x{69EB}\x{69EC}\x{69ED}\x{69EE}\x{69EF}\x{69F0}\x{69F1}\x{69F2}' .
          '\x{69F3}\x{69F4}\x{69F5}\x{69F6}\x{69F7}\x{69F8}\x{69FA}\x{69FB}\x{69FC}' .
          '\x{69FD}\x{69FE}\x{69FF}\x{6A00}\x{6A01}\x{6A02}\x{6A04}\x{6A05}\x{6A06}' .
          '\x{6A07}\x{6A08}\x{6A09}\x{6A0A}\x{6A0B}\x{6A0D}\x{6A0E}\x{6A0F}\x{6A10}' .
          '\x{6A11}\x{6A12}\x{6A13}\x{6A14}\x{6A15}\x{6A16}\x{6A17}\x{6A18}\x{6A19}' .
          '\x{6A1A}\x{6A1B}\x{6A1D}\x{6A1E}\x{6A1F}\x{6A20}\x{6A21}\x{6A22}\x{6A23}' .
          '\x{6A25}\x{6A26}\x{6A27}\x{6A28}\x{6A29}\x{6A2A}\x{6A2B}\x{6A2C}\x{6A2D}' .
          '\x{6A2E}\x{6A2F}\x{6A30}\x{6A31}\x{6A32}\x{6A33}\x{6A34}\x{6A35}\x{6A36}' .
          '\x{6A38}\x{6A39}\x{6A3A}\x{6A3B}\x{6A3C}\x{6A3D}\x{6A3E}\x{6A3F}\x{6A40}' .
          '\x{6A41}\x{6A42}\x{6A43}\x{6A44}\x{6A45}\x{6A46}\x{6A47}\x{6A48}\x{6A49}' .
          '\x{6A4B}\x{6A4C}\x{6A4D}\x{6A4E}\x{6A4F}\x{6A50}\x{6A51}\x{6A52}\x{6A54}' .
          '\x{6A55}\x{6A56}\x{6A57}\x{6A58}\x{6A59}\x{6A5A}\x{6A5B}\x{6A5D}\x{6A5E}' .
          '\x{6A5F}\x{6A60}\x{6A61}\x{6A62}\x{6A63}\x{6A64}\x{6A65}\x{6A66}\x{6A67}' .
          '\x{6A68}\x{6A69}\x{6A6A}\x{6A6B}\x{6A6C}\x{6A6D}\x{6A6F}\x{6A71}\x{6A72}' .
          '\x{6A73}\x{6A74}\x{6A75}\x{6A76}\x{6A77}\x{6A78}\x{6A79}\x{6A7A}\x{6A7B}' .
          '\x{6A7C}\x{6A7D}\x{6A7E}\x{6A7F}\x{6A80}\x{6A81}\x{6A82}\x{6A83}\x{6A84}' .
          '\x{6A85}\x{6A87}\x{6A88}\x{6A89}\x{6A8B}\x{6A8C}\x{6A8D}\x{6A8E}\x{6A90}' .
          '\x{6A91}\x{6A92}\x{6A93}\x{6A94}\x{6A95}\x{6A96}\x{6A97}\x{6A98}\x{6A9A}' .
          '\x{6A9B}\x{6A9C}\x{6A9E}\x{6A9F}\x{6AA0}\x{6AA1}\x{6AA2}\x{6AA3}\x{6AA4}' .
          '\x{6AA5}\x{6AA6}\x{6AA7}\x{6AA8}\x{6AA9}\x{6AAB}\x{6AAC}\x{6AAD}\x{6AAE}' .
          '\x{6AAF}\x{6AB0}\x{6AB2}\x{6AB3}\x{6AB4}\x{6AB5}\x{6AB6}\x{6AB7}\x{6AB8}' .
          '\x{6AB9}\x{6ABA}\x{6ABB}\x{6ABC}\x{6ABD}\x{6ABF}\x{6AC1}\x{6AC2}\x{6AC3}' .
          '\x{6AC5}\x{6AC6}\x{6AC7}\x{6ACA}\x{6ACB}\x{6ACC}\x{6ACD}\x{6ACE}\x{6ACF}' .
          '\x{6AD0}\x{6AD1}\x{6AD2}\x{6AD3}\x{6AD4}\x{6AD5}\x{6AD6}\x{6AD7}\x{6AD9}' .
          '\x{6ADA}\x{6ADB}\x{6ADC}\x{6ADD}\x{6ADE}\x{6ADF}\x{6AE0}\x{6AE1}\x{6AE2}' .
          '\x{6AE3}\x{6AE4}\x{6AE5}\x{6AE6}\x{6AE7}\x{6AE8}\x{6AEA}\x{6AEB}\x{6AEC}' .
          '\x{6AED}\x{6AEE}\x{6AEF}\x{6AF0}\x{6AF1}\x{6AF2}\x{6AF3}\x{6AF4}\x{6AF5}' .
          '\x{6AF6}\x{6AF7}\x{6AF8}\x{6AF9}\x{6AFA}\x{6AFB}\x{6AFC}\x{6AFD}\x{6AFE}' .
          '\x{6AFF}\x{6B00}\x{6B01}\x{6B02}\x{6B03}\x{6B04}\x{6B05}\x{6B06}\x{6B07}' .
          '\x{6B08}\x{6B09}\x{6B0A}\x{6B0B}\x{6B0C}\x{6B0D}\x{6B0F}\x{6B10}\x{6B11}' .
          '\x{6B12}\x{6B13}\x{6B14}\x{6B15}\x{6B16}\x{6B17}\x{6B18}\x{6B19}\x{6B1A}' .
          '\x{6B1C}\x{6B1D}\x{6B1E}\x{6B1F}\x{6B20}\x{6B21}\x{6B22}\x{6B23}\x{6B24}' .
          '\x{6B25}\x{6B26}\x{6B27}\x{6B28}\x{6B29}\x{6B2A}\x{6B2B}\x{6B2C}\x{6B2D}' .
          '\x{6B2F}\x{6B30}\x{6B31}\x{6B32}\x{6B33}\x{6B34}\x{6B36}\x{6B37}\x{6B38}' .
          '\x{6B39}\x{6B3A}\x{6B3B}\x{6B3C}\x{6B3D}\x{6B3E}\x{6B3F}\x{6B41}\x{6B42}' .
          '\x{6B43}\x{6B44}\x{6B45}\x{6B46}\x{6B47}\x{6B48}\x{6B49}\x{6B4A}\x{6B4B}' .
          '\x{6B4C}\x{6B4D}\x{6B4E}\x{6B4F}\x{6B50}\x{6B51}\x{6B52}\x{6B53}\x{6B54}' .
          '\x{6B55}\x{6B56}\x{6B59}\x{6B5A}\x{6B5B}\x{6B5C}\x{6B5E}\x{6B5F}\x{6B60}' .
          '\x{6B61}\x{6B62}\x{6B63}\x{6B64}\x{6B65}\x{6B66}\x{6B67}\x{6B69}\x{6B6A}' .
          '\x{6B6B}\x{6B6D}\x{6B6F}\x{6B70}\x{6B72}\x{6B73}\x{6B74}\x{6B76}\x{6B77}' .
          '\x{6B78}\x{6B79}\x{6B7A}\x{6B7B}\x{6B7C}\x{6B7E}\x{6B7F}\x{6B80}\x{6B81}' .
          '\x{6B82}\x{6B83}\x{6B84}\x{6B85}\x{6B86}\x{6B87}\x{6B88}\x{6B89}\x{6B8A}' .
          '\x{6B8B}\x{6B8C}\x{6B8D}\x{6B8E}\x{6B8F}\x{6B90}\x{6B91}\x{6B92}\x{6B93}' .
          '\x{6B94}\x{6B95}\x{6B96}\x{6B97}\x{6B98}\x{6B99}\x{6B9A}\x{6B9B}\x{6B9C}' .
          '\x{6B9D}\x{6B9E}\x{6B9F}\x{6BA0}\x{6BA1}\x{6BA2}\x{6BA3}\x{6BA4}\x{6BA5}' .
          '\x{6BA6}\x{6BA7}\x{6BA8}\x{6BA9}\x{6BAA}\x{6BAB}\x{6BAC}\x{6BAD}\x{6BAE}' .
          '\x{6BAF}\x{6BB0}\x{6BB2}\x{6BB3}\x{6BB4}\x{6BB5}\x{6BB6}\x{6BB7}\x{6BB9}' .
          '\x{6BBA}\x{6BBB}\x{6BBC}\x{6BBD}\x{6BBE}\x{6BBF}\x{6BC0}\x{6BC1}\x{6BC2}' .
          '\x{6BC3}\x{6BC4}\x{6BC5}\x{6BC6}\x{6BC7}\x{6BC8}\x{6BC9}\x{6BCA}\x{6BCB}' .
          '\x{6BCC}\x{6BCD}\x{6BCE}\x{6BCF}\x{6BD0}\x{6BD1}\x{6BD2}\x{6BD3}\x{6BD4}' .
          '\x{6BD5}\x{6BD6}\x{6BD7}\x{6BD8}\x{6BD9}\x{6BDA}\x{6BDB}\x{6BDC}\x{6BDD}' .
          '\x{6BDE}\x{6BDF}\x{6BE0}\x{6BE1}\x{6BE2}\x{6BE3}\x{6BE4}\x{6BE5}\x{6BE6}' .
          '\x{6BE7}\x{6BE8}\x{6BEA}\x{6BEB}\x{6BEC}\x{6BED}\x{6BEE}\x{6BEF}\x{6BF0}' .
          '\x{6BF2}\x{6BF3}\x{6BF5}\x{6BF6}\x{6BF7}\x{6BF8}\x{6BF9}\x{6BFB}\x{6BFC}' .
          '\x{6BFD}\x{6BFE}\x{6BFF}\x{6C00}\x{6C01}\x{6C02}\x{6C03}\x{6C04}\x{6C05}' .
          '\x{6C06}\x{6C07}\x{6C08}\x{6C09}\x{6C0B}\x{6C0C}\x{6C0D}\x{6C0E}\x{6C0F}' .
          '\x{6C10}\x{6C11}\x{6C12}\x{6C13}\x{6C14}\x{6C15}\x{6C16}\x{6C18}\x{6C19}' .
          '\x{6C1A}\x{6C1B}\x{6C1D}\x{6C1E}\x{6C1F}\x{6C20}\x{6C21}\x{6C22}\x{6C23}' .
          '\x{6C24}\x{6C25}\x{6C26}\x{6C27}\x{6C28}\x{6C29}\x{6C2A}\x{6C2B}\x{6C2C}' .
          '\x{6C2E}\x{6C2F}\x{6C30}\x{6C31}\x{6C32}\x{6C33}\x{6C34}\x{6C35}\x{6C36}' .
          '\x{6C37}\x{6C38}\x{6C3A}\x{6C3B}\x{6C3D}\x{6C3E}\x{6C3F}\x{6C40}\x{6C41}' .
          '\x{6C42}\x{6C43}\x{6C44}\x{6C46}\x{6C47}\x{6C48}\x{6C49}\x{6C4A}\x{6C4B}' .
          '\x{6C4C}\x{6C4D}\x{6C4E}\x{6C4F}\x{6C50}\x{6C51}\x{6C52}\x{6C53}\x{6C54}' .
          '\x{6C55}\x{6C56}\x{6C57}\x{6C58}\x{6C59}\x{6C5A}\x{6C5B}\x{6C5C}\x{6C5D}' .
          '\x{6C5E}\x{6C5F}\x{6C60}\x{6C61}\x{6C62}\x{6C63}\x{6C64}\x{6C65}\x{6C66}' .
          '\x{6C67}\x{6C68}\x{6C69}\x{6C6A}\x{6C6B}\x{6C6D}\x{6C6F}\x{6C70}\x{6C71}' .
          '\x{6C72}\x{6C73}\x{6C74}\x{6C75}\x{6C76}\x{6C77}\x{6C78}\x{6C79}\x{6C7A}' .
          '\x{6C7B}\x{6C7C}\x{6C7D}\x{6C7E}\x{6C7F}\x{6C80}\x{6C81}\x{6C82}\x{6C83}' .
          '\x{6C84}\x{6C85}\x{6C86}\x{6C87}\x{6C88}\x{6C89}\x{6C8A}\x{6C8B}\x{6C8C}' .
          '\x{6C8D}\x{6C8E}\x{6C8F}\x{6C90}\x{6C91}\x{6C92}\x{6C93}\x{6C94}\x{6C95}' .
          '\x{6C96}\x{6C97}\x{6C98}\x{6C99}\x{6C9A}\x{6C9B}\x{6C9C}\x{6C9D}\x{6C9E}' .
          '\x{6C9F}\x{6CA1}\x{6CA2}\x{6CA3}\x{6CA4}\x{6CA5}\x{6CA6}\x{6CA7}\x{6CA8}' .
          '\x{6CA9}\x{6CAA}\x{6CAB}\x{6CAC}\x{6CAD}\x{6CAE}\x{6CAF}\x{6CB0}\x{6CB1}' .
          '\x{6CB2}\x{6CB3}\x{6CB4}\x{6CB5}\x{6CB6}\x{6CB7}\x{6CB8}\x{6CB9}\x{6CBA}' .
          '\x{6CBB}\x{6CBC}\x{6CBD}\x{6CBE}\x{6CBF}\x{6CC0}\x{6CC1}\x{6CC2}\x{6CC3}' .
          '\x{6CC4}\x{6CC5}\x{6CC6}\x{6CC7}\x{6CC8}\x{6CC9}\x{6CCA}\x{6CCB}\x{6CCC}' .
          '\x{6CCD}\x{6CCE}\x{6CCF}\x{6CD0}\x{6CD1}\x{6CD2}\x{6CD3}\x{6CD4}\x{6CD5}' .
          '\x{6CD6}\x{6CD7}\x{6CD9}\x{6CDA}\x{6CDB}\x{6CDC}\x{6CDD}\x{6CDE}\x{6CDF}' .
          '\x{6CE0}\x{6CE1}\x{6CE2}\x{6CE3}\x{6CE4}\x{6CE5}\x{6CE6}\x{6CE7}\x{6CE8}' .
          '\x{6CE9}\x{6CEA}\x{6CEB}\x{6CEC}\x{6CED}\x{6CEE}\x{6CEF}\x{6CF0}\x{6CF1}' .
          '\x{6CF2}\x{6CF3}\x{6CF5}\x{6CF6}\x{6CF7}\x{6CF8}\x{6CF9}\x{6CFA}\x{6CFB}' .
          '\x{6CFC}\x{6CFD}\x{6CFE}\x{6CFF}\x{6D00}\x{6D01}\x{6D03}\x{6D04}\x{6D05}' .
          '\x{6D06}\x{6D07}\x{6D08}\x{6D09}\x{6D0A}\x{6D0B}\x{6D0C}\x{6D0D}\x{6D0E}' .
          '\x{6D0F}\x{6D10}\x{6D11}\x{6D12}\x{6D13}\x{6D14}\x{6D15}\x{6D16}\x{6D17}' .
          '\x{6D18}\x{6D19}\x{6D1A}\x{6D1B}\x{6D1D}\x{6D1E}\x{6D1F}\x{6D20}\x{6D21}' .
          '\x{6D22}\x{6D23}\x{6D25}\x{6D26}\x{6D27}\x{6D28}\x{6D29}\x{6D2A}\x{6D2B}' .
          '\x{6D2C}\x{6D2D}\x{6D2E}\x{6D2F}\x{6D30}\x{6D31}\x{6D32}\x{6D33}\x{6D34}' .
          '\x{6D35}\x{6D36}\x{6D37}\x{6D38}\x{6D39}\x{6D3A}\x{6D3B}\x{6D3C}\x{6D3D}' .
          '\x{6D3E}\x{6D3F}\x{6D40}\x{6D41}\x{6D42}\x{6D43}\x{6D44}\x{6D45}\x{6D46}' .
          '\x{6D47}\x{6D48}\x{6D49}\x{6D4A}\x{6D4B}\x{6D4C}\x{6D4D}\x{6D4E}\x{6D4F}' .
          '\x{6D50}\x{6D51}\x{6D52}\x{6D53}\x{6D54}\x{6D55}\x{6D56}\x{6D57}\x{6D58}' .
          '\x{6D59}\x{6D5A}\x{6D5B}\x{6D5C}\x{6D5D}\x{6D5E}\x{6D5F}\x{6D60}\x{6D61}' .
          '\x{6D62}\x{6D63}\x{6D64}\x{6D65}\x{6D66}\x{6D67}\x{6D68}\x{6D69}\x{6D6A}' .
          '\x{6D6B}\x{6D6C}\x{6D6D}\x{6D6E}\x{6D6F}\x{6D70}\x{6D72}\x{6D73}\x{6D74}' .
          '\x{6D75}\x{6D76}\x{6D77}\x{6D78}\x{6D79}\x{6D7A}\x{6D7B}\x{6D7C}\x{6D7D}' .
          '\x{6D7E}\x{6D7F}\x{6D80}\x{6D82}\x{6D83}\x{6D84}\x{6D85}\x{6D86}\x{6D87}' .
          '\x{6D88}\x{6D89}\x{6D8A}\x{6D8B}\x{6D8C}\x{6D8D}\x{6D8E}\x{6D8F}\x{6D90}' .
          '\x{6D91}\x{6D92}\x{6D93}\x{6D94}\x{6D95}\x{6D97}\x{6D98}\x{6D99}\x{6D9A}' .
          '\x{6D9B}\x{6D9D}\x{6D9E}\x{6D9F}\x{6DA0}\x{6DA1}\x{6DA2}\x{6DA3}\x{6DA4}' .
          '\x{6DA5}\x{6DA6}\x{6DA7}\x{6DA8}\x{6DA9}\x{6DAA}\x{6DAB}\x{6DAC}\x{6DAD}' .
          '\x{6DAE}\x{6DAF}\x{6DB2}\x{6DB3}\x{6DB4}\x{6DB5}\x{6DB7}\x{6DB8}\x{6DB9}' .
          '\x{6DBA}\x{6DBB}\x{6DBC}\x{6DBD}\x{6DBE}\x{6DBF}\x{6DC0}\x{6DC1}\x{6DC2}' .
          '\x{6DC3}\x{6DC4}\x{6DC5}\x{6DC6}\x{6DC7}\x{6DC8}\x{6DC9}\x{6DCA}\x{6DCB}' .
          '\x{6DCC}\x{6DCD}\x{6DCE}\x{6DCF}\x{6DD0}\x{6DD1}\x{6DD2}\x{6DD3}\x{6DD4}' .
          '\x{6DD5}\x{6DD6}\x{6DD7}\x{6DD8}\x{6DD9}\x{6DDA}\x{6DDB}\x{6DDC}\x{6DDD}' .
          '\x{6DDE}\x{6DDF}\x{6DE0}\x{6DE1}\x{6DE2}\x{6DE3}\x{6DE4}\x{6DE5}\x{6DE6}' .
          '\x{6DE7}\x{6DE8}\x{6DE9}\x{6DEA}\x{6DEB}\x{6DEC}\x{6DED}\x{6DEE}\x{6DEF}' .
          '\x{6DF0}\x{6DF1}\x{6DF2}\x{6DF3}\x{6DF4}\x{6DF5}\x{6DF6}\x{6DF7}\x{6DF8}' .
          '\x{6DF9}\x{6DFA}\x{6DFB}\x{6DFC}\x{6DFD}\x{6E00}\x{6E03}\x{6E04}\x{6E05}' .
          '\x{6E07}\x{6E08}\x{6E09}\x{6E0A}\x{6E0B}\x{6E0C}\x{6E0D}\x{6E0E}\x{6E0F}' .
          '\x{6E10}\x{6E11}\x{6E14}\x{6E15}\x{6E16}\x{6E17}\x{6E19}\x{6E1A}\x{6E1B}' .
          '\x{6E1C}\x{6E1D}\x{6E1E}\x{6E1F}\x{6E20}\x{6E21}\x{6E22}\x{6E23}\x{6E24}' .
          '\x{6E25}\x{6E26}\x{6E27}\x{6E28}\x{6E29}\x{6E2B}\x{6E2C}\x{6E2D}\x{6E2E}' .
          '\x{6E2F}\x{6E30}\x{6E31}\x{6E32}\x{6E33}\x{6E34}\x{6E35}\x{6E36}\x{6E37}' .
          '\x{6E38}\x{6E39}\x{6E3A}\x{6E3B}\x{6E3C}\x{6E3D}\x{6E3E}\x{6E3F}\x{6E40}' .
          '\x{6E41}\x{6E42}\x{6E43}\x{6E44}\x{6E45}\x{6E46}\x{6E47}\x{6E48}\x{6E49}' .
          '\x{6E4A}\x{6E4B}\x{6E4D}\x{6E4E}\x{6E4F}\x{6E50}\x{6E51}\x{6E52}\x{6E53}' .
          '\x{6E54}\x{6E55}\x{6E56}\x{6E57}\x{6E58}\x{6E59}\x{6E5A}\x{6E5B}\x{6E5C}' .
          '\x{6E5D}\x{6E5E}\x{6E5F}\x{6E60}\x{6E61}\x{6E62}\x{6E63}\x{6E64}\x{6E65}' .
          '\x{6E66}\x{6E67}\x{6E68}\x{6E69}\x{6E6A}\x{6E6B}\x{6E6D}\x{6E6E}\x{6E6F}' .
          '\x{6E70}\x{6E71}\x{6E72}\x{6E73}\x{6E74}\x{6E75}\x{6E77}\x{6E78}\x{6E79}' .
          '\x{6E7E}\x{6E7F}\x{6E80}\x{6E81}\x{6E82}\x{6E83}\x{6E84}\x{6E85}\x{6E86}' .
          '\x{6E87}\x{6E88}\x{6E89}\x{6E8A}\x{6E8D}\x{6E8E}\x{6E8F}\x{6E90}\x{6E91}' .
          '\x{6E92}\x{6E93}\x{6E94}\x{6E96}\x{6E97}\x{6E98}\x{6E99}\x{6E9A}\x{6E9B}' .
          '\x{6E9C}\x{6E9D}\x{6E9E}\x{6E9F}\x{6EA0}\x{6EA1}\x{6EA2}\x{6EA3}\x{6EA4}' .
          '\x{6EA5}\x{6EA6}\x{6EA7}\x{6EA8}\x{6EA9}\x{6EAA}\x{6EAB}\x{6EAC}\x{6EAD}' .
          '\x{6EAE}\x{6EAF}\x{6EB0}\x{6EB1}\x{6EB2}\x{6EB3}\x{6EB4}\x{6EB5}\x{6EB6}' .
          '\x{6EB7}\x{6EB8}\x{6EB9}\x{6EBA}\x{6EBB}\x{6EBC}\x{6EBD}\x{6EBE}\x{6EBF}' .
          '\x{6EC0}\x{6EC1}\x{6EC2}\x{6EC3}\x{6EC4}\x{6EC5}\x{6EC6}\x{6EC7}\x{6EC8}' .
          '\x{6EC9}\x{6ECA}\x{6ECB}\x{6ECC}\x{6ECD}\x{6ECE}\x{6ECF}\x{6ED0}\x{6ED1}' .
          '\x{6ED2}\x{6ED3}\x{6ED4}\x{6ED5}\x{6ED6}\x{6ED7}\x{6ED8}\x{6ED9}\x{6EDA}' .
          '\x{6EDC}\x{6EDE}\x{6EDF}\x{6EE0}\x{6EE1}\x{6EE2}\x{6EE4}\x{6EE5}\x{6EE6}' .
          '\x{6EE7}\x{6EE8}\x{6EE9}\x{6EEA}\x{6EEB}\x{6EEC}\x{6EED}\x{6EEE}\x{6EEF}' .
          '\x{6EF0}\x{6EF1}\x{6EF2}\x{6EF3}\x{6EF4}\x{6EF5}\x{6EF6}\x{6EF7}\x{6EF8}' .
          '\x{6EF9}\x{6EFA}\x{6EFB}\x{6EFC}\x{6EFD}\x{6EFE}\x{6EFF}\x{6F00}\x{6F01}' .
          '\x{6F02}\x{6F03}\x{6F05}\x{6F06}\x{6F07}\x{6F08}\x{6F09}\x{6F0A}\x{6F0C}' .
          '\x{6F0D}\x{6F0E}\x{6F0F}\x{6F10}\x{6F11}\x{6F12}\x{6F13}\x{6F14}\x{6F15}' .
          '\x{6F16}\x{6F17}\x{6F18}\x{6F19}\x{6F1A}\x{6F1B}\x{6F1C}\x{6F1D}\x{6F1E}' .
          '\x{6F1F}\x{6F20}\x{6F21}\x{6F22}\x{6F23}\x{6F24}\x{6F25}\x{6F26}\x{6F27}' .
          '\x{6F28}\x{6F29}\x{6F2A}\x{6F2B}\x{6F2C}\x{6F2D}\x{6F2E}\x{6F2F}\x{6F30}' .
          '\x{6F31}\x{6F32}\x{6F33}\x{6F34}\x{6F35}\x{6F36}\x{6F37}\x{6F38}\x{6F39}' .
          '\x{6F3A}\x{6F3B}\x{6F3C}\x{6F3D}\x{6F3E}\x{6F3F}\x{6F40}\x{6F41}\x{6F43}' .
          '\x{6F44}\x{6F45}\x{6F46}\x{6F47}\x{6F49}\x{6F4B}\x{6F4C}\x{6F4D}\x{6F4E}' .
          '\x{6F4F}\x{6F50}\x{6F51}\x{6F52}\x{6F53}\x{6F54}\x{6F55}\x{6F56}\x{6F57}' .
          '\x{6F58}\x{6F59}\x{6F5A}\x{6F5B}\x{6F5C}\x{6F5D}\x{6F5E}\x{6F5F}\x{6F60}' .
          '\x{6F61}\x{6F62}\x{6F63}\x{6F64}\x{6F65}\x{6F66}\x{6F67}\x{6F68}\x{6F69}' .
          '\x{6F6A}\x{6F6B}\x{6F6C}\x{6F6D}\x{6F6E}\x{6F6F}\x{6F70}\x{6F71}\x{6F72}' .
          '\x{6F73}\x{6F74}\x{6F75}\x{6F76}\x{6F77}\x{6F78}\x{6F7A}\x{6F7B}\x{6F7C}' .
          '\x{6F7D}\x{6F7E}\x{6F7F}\x{6F80}\x{6F81}\x{6F82}\x{6F83}\x{6F84}\x{6F85}' .
          '\x{6F86}\x{6F87}\x{6F88}\x{6F89}\x{6F8A}\x{6F8B}\x{6F8C}\x{6F8D}\x{6F8E}' .
          '\x{6F8F}\x{6F90}\x{6F91}\x{6F92}\x{6F93}\x{6F94}\x{6F95}\x{6F96}\x{6F97}' .
          '\x{6F99}\x{6F9B}\x{6F9C}\x{6F9D}\x{6F9E}\x{6FA0}\x{6FA1}\x{6FA2}\x{6FA3}' .
          '\x{6FA4}\x{6FA5}\x{6FA6}\x{6FA7}\x{6FA8}\x{6FA9}\x{6FAA}\x{6FAB}\x{6FAC}' .
          '\x{6FAD}\x{6FAE}\x{6FAF}\x{6FB0}\x{6FB1}\x{6FB2}\x{6FB3}\x{6FB4}\x{6FB5}' .
          '\x{6FB6}\x{6FB8}\x{6FB9}\x{6FBA}\x{6FBB}\x{6FBC}\x{6FBD}\x{6FBE}\x{6FBF}' .
          '\x{6FC0}\x{6FC1}\x{6FC2}\x{6FC3}\x{6FC4}\x{6FC6}\x{6FC7}\x{6FC8}\x{6FC9}' .
          '\x{6FCA}\x{6FCB}\x{6FCC}\x{6FCD}\x{6FCE}\x{6FCF}\x{6FD1}\x{6FD2}\x{6FD4}' .
          '\x{6FD5}\x{6FD6}\x{6FD7}\x{6FD8}\x{6FD9}\x{6FDA}\x{6FDB}\x{6FDC}\x{6FDD}' .
          '\x{6FDE}\x{6FDF}\x{6FE0}\x{6FE1}\x{6FE2}\x{6FE3}\x{6FE4}\x{6FE5}\x{6FE6}' .
          '\x{6FE7}\x{6FE8}\x{6FE9}\x{6FEA}\x{6FEB}\x{6FEC}\x{6FED}\x{6FEE}\x{6FEF}' .
          '\x{6FF0}\x{6FF1}\x{6FF2}\x{6FF3}\x{6FF4}\x{6FF6}\x{6FF7}\x{6FF8}\x{6FF9}' .
          '\x{6FFA}\x{6FFB}\x{6FFC}\x{6FFE}\x{6FFF}\x{7000}\x{7001}\x{7002}\x{7003}' .
          '\x{7004}\x{7005}\x{7006}\x{7007}\x{7008}\x{7009}\x{700A}\x{700B}\x{700C}' .
          '\x{700D}\x{700E}\x{700F}\x{7011}\x{7012}\x{7014}\x{7015}\x{7016}\x{7017}' .
          '\x{7018}\x{7019}\x{701A}\x{701B}\x{701C}\x{701D}\x{701F}\x{7020}\x{7021}' .
          '\x{7022}\x{7023}\x{7024}\x{7025}\x{7026}\x{7027}\x{7028}\x{7029}\x{702A}' .
          '\x{702B}\x{702C}\x{702D}\x{702E}\x{702F}\x{7030}\x{7031}\x{7032}\x{7033}' .
          '\x{7034}\x{7035}\x{7036}\x{7037}\x{7038}\x{7039}\x{703A}\x{703B}\x{703C}' .
          '\x{703D}\x{703E}\x{703F}\x{7040}\x{7041}\x{7042}\x{7043}\x{7044}\x{7045}' .
          '\x{7046}\x{7048}\x{7049}\x{704A}\x{704C}\x{704D}\x{704F}\x{7050}\x{7051}' .
          '\x{7052}\x{7053}\x{7054}\x{7055}\x{7056}\x{7057}\x{7058}\x{7059}\x{705A}' .
          '\x{705B}\x{705C}\x{705D}\x{705E}\x{705F}\x{7060}\x{7061}\x{7062}\x{7063}' .
          '\x{7064}\x{7065}\x{7066}\x{7067}\x{7068}\x{7069}\x{706A}\x{706B}\x{706C}' .
          '\x{706D}\x{706E}\x{706F}\x{7070}\x{7071}\x{7074}\x{7075}\x{7076}\x{7077}' .
          '\x{7078}\x{7079}\x{707A}\x{707C}\x{707D}\x{707E}\x{707F}\x{7080}\x{7082}' .
          '\x{7083}\x{7084}\x{7085}\x{7086}\x{7087}\x{7088}\x{7089}\x{708A}\x{708B}' .
          '\x{708C}\x{708E}\x{708F}\x{7090}\x{7091}\x{7092}\x{7093}\x{7094}\x{7095}' .
          '\x{7096}\x{7098}\x{7099}\x{709A}\x{709C}\x{709D}\x{709E}\x{709F}\x{70A0}' .
          '\x{70A1}\x{70A2}\x{70A3}\x{70A4}\x{70A5}\x{70A6}\x{70A7}\x{70A8}\x{70A9}' .
          '\x{70AB}\x{70AC}\x{70AD}\x{70AE}\x{70AF}\x{70B0}\x{70B1}\x{70B3}\x{70B4}' .
          '\x{70B5}\x{70B7}\x{70B8}\x{70B9}\x{70BA}\x{70BB}\x{70BC}\x{70BD}\x{70BE}' .
          '\x{70BF}\x{70C0}\x{70C1}\x{70C2}\x{70C3}\x{70C4}\x{70C5}\x{70C6}\x{70C7}' .
          '\x{70C8}\x{70C9}\x{70CA}\x{70CB}\x{70CC}\x{70CD}\x{70CE}\x{70CF}\x{70D0}' .
          '\x{70D1}\x{70D2}\x{70D3}\x{70D4}\x{70D6}\x{70D7}\x{70D8}\x{70D9}\x{70DA}' .
          '\x{70DB}\x{70DC}\x{70DD}\x{70DE}\x{70DF}\x{70E0}\x{70E1}\x{70E2}\x{70E3}' .
          '\x{70E4}\x{70E5}\x{70E6}\x{70E7}\x{70E8}\x{70E9}\x{70EA}\x{70EB}\x{70EC}' .
          '\x{70ED}\x{70EE}\x{70EF}\x{70F0}\x{70F1}\x{70F2}\x{70F3}\x{70F4}\x{70F5}' .
          '\x{70F6}\x{70F7}\x{70F8}\x{70F9}\x{70FA}\x{70FB}\x{70FC}\x{70FD}\x{70FF}' .
          '\x{7100}\x{7101}\x{7102}\x{7103}\x{7104}\x{7105}\x{7106}\x{7107}\x{7109}' .
          '\x{710A}\x{710B}\x{710C}\x{710D}\x{710E}\x{710F}\x{7110}\x{7111}\x{7112}' .
          '\x{7113}\x{7115}\x{7116}\x{7117}\x{7118}\x{7119}\x{711A}\x{711B}\x{711C}' .
          '\x{711D}\x{711E}\x{711F}\x{7120}\x{7121}\x{7122}\x{7123}\x{7125}\x{7126}' .
          '\x{7127}\x{7128}\x{7129}\x{712A}\x{712B}\x{712C}\x{712D}\x{712E}\x{712F}' .
          '\x{7130}\x{7131}\x{7132}\x{7135}\x{7136}\x{7137}\x{7138}\x{7139}\x{713A}' .
          '\x{713B}\x{713D}\x{713E}\x{713F}\x{7140}\x{7141}\x{7142}\x{7143}\x{7144}' .
          '\x{7145}\x{7146}\x{7147}\x{7148}\x{7149}\x{714A}\x{714B}\x{714C}\x{714D}' .
          '\x{714E}\x{714F}\x{7150}\x{7151}\x{7152}\x{7153}\x{7154}\x{7156}\x{7158}' .
          '\x{7159}\x{715A}\x{715B}\x{715C}\x{715D}\x{715E}\x{715F}\x{7160}\x{7161}' .
          '\x{7162}\x{7163}\x{7164}\x{7165}\x{7166}\x{7167}\x{7168}\x{7169}\x{716A}' .
          '\x{716C}\x{716E}\x{716F}\x{7170}\x{7171}\x{7172}\x{7173}\x{7174}\x{7175}' .
          '\x{7176}\x{7177}\x{7178}\x{7179}\x{717A}\x{717B}\x{717C}\x{717D}\x{717E}' .
          '\x{717F}\x{7180}\x{7181}\x{7182}\x{7183}\x{7184}\x{7185}\x{7186}\x{7187}' .
          '\x{7188}\x{7189}\x{718A}\x{718B}\x{718C}\x{718E}\x{718F}\x{7190}\x{7191}' .
          '\x{7192}\x{7193}\x{7194}\x{7195}\x{7197}\x{7198}\x{7199}\x{719A}\x{719B}' .
          '\x{719C}\x{719D}\x{719E}\x{719F}\x{71A0}\x{71A1}\x{71A2}\x{71A3}\x{71A4}' .
          '\x{71A5}\x{71A7}\x{71A8}\x{71A9}\x{71AA}\x{71AC}\x{71AD}\x{71AE}\x{71AF}' .
          '\x{71B0}\x{71B1}\x{71B2}\x{71B3}\x{71B4}\x{71B5}\x{71B7}\x{71B8}\x{71B9}' .
          '\x{71BA}\x{71BB}\x{71BC}\x{71BD}\x{71BE}\x{71BF}\x{71C0}\x{71C1}\x{71C2}' .
          '\x{71C3}\x{71C4}\x{71C5}\x{71C6}\x{71C7}\x{71C8}\x{71C9}\x{71CA}\x{71CB}' .
          '\x{71CD}\x{71CE}\x{71CF}\x{71D0}\x{71D1}\x{71D2}\x{71D4}\x{71D5}\x{71D6}' .
          '\x{71D7}\x{71D8}\x{71D9}\x{71DA}\x{71DB}\x{71DC}\x{71DD}\x{71DE}\x{71DF}' .
          '\x{71E0}\x{71E1}\x{71E2}\x{71E3}\x{71E4}\x{71E5}\x{71E6}\x{71E7}\x{71E8}' .
          '\x{71E9}\x{71EA}\x{71EB}\x{71EC}\x{71ED}\x{71EE}\x{71EF}\x{71F0}\x{71F1}' .
          '\x{71F2}\x{71F4}\x{71F5}\x{71F6}\x{71F7}\x{71F8}\x{71F9}\x{71FB}\x{71FC}' .
          '\x{71FD}\x{71FE}\x{71FF}\x{7201}\x{7202}\x{7203}\x{7204}\x{7205}\x{7206}' .
          '\x{7207}\x{7208}\x{7209}\x{720A}\x{720C}\x{720D}\x{720E}\x{720F}\x{7210}' .
          '\x{7212}\x{7213}\x{7214}\x{7216}\x{7218}\x{7219}\x{721A}\x{721B}\x{721C}' .
          '\x{721D}\x{721E}\x{721F}\x{7221}\x{7222}\x{7223}\x{7226}\x{7227}\x{7228}' .
          '\x{7229}\x{722A}\x{722B}\x{722C}\x{722D}\x{722E}\x{7230}\x{7231}\x{7232}' .
          '\x{7233}\x{7235}\x{7236}\x{7237}\x{7238}\x{7239}\x{723A}\x{723B}\x{723C}' .
          '\x{723D}\x{723E}\x{723F}\x{7240}\x{7241}\x{7242}\x{7243}\x{7244}\x{7246}' .
          '\x{7247}\x{7248}\x{7249}\x{724A}\x{724B}\x{724C}\x{724D}\x{724F}\x{7251}' .
          '\x{7252}\x{7253}\x{7254}\x{7256}\x{7257}\x{7258}\x{7259}\x{725A}\x{725B}' .
          '\x{725C}\x{725D}\x{725E}\x{725F}\x{7260}\x{7261}\x{7262}\x{7263}\x{7264}' .
          '\x{7265}\x{7266}\x{7267}\x{7268}\x{7269}\x{726A}\x{726B}\x{726C}\x{726D}' .
          '\x{726E}\x{726F}\x{7270}\x{7271}\x{7272}\x{7273}\x{7274}\x{7275}\x{7276}' .
          '\x{7277}\x{7278}\x{7279}\x{727A}\x{727B}\x{727C}\x{727D}\x{727E}\x{727F}' .
          '\x{7280}\x{7281}\x{7282}\x{7283}\x{7284}\x{7285}\x{7286}\x{7287}\x{7288}' .
          '\x{7289}\x{728A}\x{728B}\x{728C}\x{728D}\x{728E}\x{728F}\x{7290}\x{7291}' .
          '\x{7292}\x{7293}\x{7294}\x{7295}\x{7296}\x{7297}\x{7298}\x{7299}\x{729A}' .
          '\x{729B}\x{729C}\x{729D}\x{729E}\x{729F}\x{72A1}\x{72A2}\x{72A3}\x{72A4}' .
          '\x{72A5}\x{72A6}\x{72A7}\x{72A8}\x{72A9}\x{72AA}\x{72AC}\x{72AD}\x{72AE}' .
          '\x{72AF}\x{72B0}\x{72B1}\x{72B2}\x{72B3}\x{72B4}\x{72B5}\x{72B6}\x{72B7}' .
          '\x{72B8}\x{72B9}\x{72BA}\x{72BB}\x{72BC}\x{72BD}\x{72BF}\x{72C0}\x{72C1}' .
          '\x{72C2}\x{72C3}\x{72C4}\x{72C5}\x{72C6}\x{72C7}\x{72C8}\x{72C9}\x{72CA}' .
          '\x{72CB}\x{72CC}\x{72CD}\x{72CE}\x{72CF}\x{72D0}\x{72D1}\x{72D2}\x{72D3}' .
          '\x{72D4}\x{72D5}\x{72D6}\x{72D7}\x{72D8}\x{72D9}\x{72DA}\x{72DB}\x{72DC}' .
          '\x{72DD}\x{72DE}\x{72DF}\x{72E0}\x{72E1}\x{72E2}\x{72E3}\x{72E4}\x{72E5}' .
          '\x{72E6}\x{72E7}\x{72E8}\x{72E9}\x{72EA}\x{72EB}\x{72EC}\x{72ED}\x{72EE}' .
          '\x{72EF}\x{72F0}\x{72F1}\x{72F2}\x{72F3}\x{72F4}\x{72F5}\x{72F6}\x{72F7}' .
          '\x{72F8}\x{72F9}\x{72FA}\x{72FB}\x{72FC}\x{72FD}\x{72FE}\x{72FF}\x{7300}' .
          '\x{7301}\x{7303}\x{7304}\x{7305}\x{7306}\x{7307}\x{7308}\x{7309}\x{730A}' .
          '\x{730B}\x{730C}\x{730D}\x{730E}\x{730F}\x{7311}\x{7312}\x{7313}\x{7314}' .
          '\x{7315}\x{7316}\x{7317}\x{7318}\x{7319}\x{731A}\x{731B}\x{731C}\x{731D}' .
          '\x{731E}\x{7320}\x{7321}\x{7322}\x{7323}\x{7324}\x{7325}\x{7326}\x{7327}' .
          '\x{7329}\x{732A}\x{732B}\x{732C}\x{732D}\x{732E}\x{7330}\x{7331}\x{7332}' .
          '\x{7333}\x{7334}\x{7335}\x{7336}\x{7337}\x{7338}\x{7339}\x{733A}\x{733B}' .
          '\x{733C}\x{733D}\x{733E}\x{733F}\x{7340}\x{7341}\x{7342}\x{7343}\x{7344}' .
          '\x{7345}\x{7346}\x{7347}\x{7348}\x{7349}\x{734A}\x{734B}\x{734C}\x{734D}' .
          '\x{734E}\x{7350}\x{7351}\x{7352}\x{7354}\x{7355}\x{7356}\x{7357}\x{7358}' .
          '\x{7359}\x{735A}\x{735B}\x{735C}\x{735D}\x{735E}\x{735F}\x{7360}\x{7361}' .
          '\x{7362}\x{7364}\x{7365}\x{7366}\x{7367}\x{7368}\x{7369}\x{736A}\x{736B}' .
          '\x{736C}\x{736D}\x{736E}\x{736F}\x{7370}\x{7371}\x{7372}\x{7373}\x{7374}' .
          '\x{7375}\x{7376}\x{7377}\x{7378}\x{7379}\x{737A}\x{737B}\x{737C}\x{737D}' .
          '\x{737E}\x{737F}\x{7380}\x{7381}\x{7382}\x{7383}\x{7384}\x{7385}\x{7386}' .
          '\x{7387}\x{7388}\x{7389}\x{738A}\x{738B}\x{738C}\x{738D}\x{738E}\x{738F}' .
          '\x{7390}\x{7391}\x{7392}\x{7393}\x{7394}\x{7395}\x{7396}\x{7397}\x{7398}' .
          '\x{7399}\x{739A}\x{739B}\x{739D}\x{739E}\x{739F}\x{73A0}\x{73A1}\x{73A2}' .
          '\x{73A3}\x{73A4}\x{73A5}\x{73A6}\x{73A7}\x{73A8}\x{73A9}\x{73AA}\x{73AB}' .
          '\x{73AC}\x{73AD}\x{73AE}\x{73AF}\x{73B0}\x{73B1}\x{73B2}\x{73B3}\x{73B4}' .
          '\x{73B5}\x{73B6}\x{73B7}\x{73B8}\x{73B9}\x{73BA}\x{73BB}\x{73BC}\x{73BD}' .
          '\x{73BE}\x{73BF}\x{73C0}\x{73C2}\x{73C3}\x{73C4}\x{73C5}\x{73C6}\x{73C7}' .
          '\x{73C8}\x{73C9}\x{73CA}\x{73CB}\x{73CC}\x{73CD}\x{73CE}\x{73CF}\x{73D0}' .
          '\x{73D1}\x{73D2}\x{73D3}\x{73D4}\x{73D5}\x{73D6}\x{73D7}\x{73D8}\x{73D9}' .
          '\x{73DA}\x{73DB}\x{73DC}\x{73DD}\x{73DE}\x{73DF}\x{73E0}\x{73E2}\x{73E3}' .
          '\x{73E5}\x{73E6}\x{73E7}\x{73E8}\x{73E9}\x{73EA}\x{73EB}\x{73EC}\x{73ED}' .
          '\x{73EE}\x{73EF}\x{73F0}\x{73F1}\x{73F2}\x{73F4}\x{73F5}\x{73F6}\x{73F7}' .
          '\x{73F8}\x{73F9}\x{73FA}\x{73FC}\x{73FD}\x{73FE}\x{73FF}\x{7400}\x{7401}' .
          '\x{7402}\x{7403}\x{7404}\x{7405}\x{7406}\x{7407}\x{7408}\x{7409}\x{740A}' .
          '\x{740B}\x{740C}\x{740D}\x{740E}\x{740F}\x{7410}\x{7411}\x{7412}\x{7413}' .
          '\x{7414}\x{7415}\x{7416}\x{7417}\x{7419}\x{741A}\x{741B}\x{741C}\x{741D}' .
          '\x{741E}\x{741F}\x{7420}\x{7421}\x{7422}\x{7423}\x{7424}\x{7425}\x{7426}' .
          '\x{7427}\x{7428}\x{7429}\x{742A}\x{742B}\x{742C}\x{742D}\x{742E}\x{742F}' .
          '\x{7430}\x{7431}\x{7432}\x{7433}\x{7434}\x{7435}\x{7436}\x{7437}\x{7438}' .
          '\x{743A}\x{743B}\x{743C}\x{743D}\x{743F}\x{7440}\x{7441}\x{7442}\x{7443}' .
          '\x{7444}\x{7445}\x{7446}\x{7448}\x{744A}\x{744B}\x{744C}\x{744D}\x{744E}' .
          '\x{744F}\x{7450}\x{7451}\x{7452}\x{7453}\x{7454}\x{7455}\x{7456}\x{7457}' .
          '\x{7459}\x{745A}\x{745B}\x{745C}\x{745D}\x{745E}\x{745F}\x{7461}\x{7462}' .
          '\x{7463}\x{7464}\x{7465}\x{7466}\x{7467}\x{7468}\x{7469}\x{746A}\x{746B}' .
          '\x{746C}\x{746D}\x{746E}\x{746F}\x{7470}\x{7471}\x{7472}\x{7473}\x{7474}' .
          '\x{7475}\x{7476}\x{7477}\x{7478}\x{7479}\x{747A}\x{747C}\x{747D}\x{747E}' .
          '\x{747F}\x{7480}\x{7481}\x{7482}\x{7483}\x{7485}\x{7486}\x{7487}\x{7488}' .
          '\x{7489}\x{748A}\x{748B}\x{748C}\x{748D}\x{748E}\x{748F}\x{7490}\x{7491}' .
          '\x{7492}\x{7493}\x{7494}\x{7495}\x{7497}\x{7498}\x{7499}\x{749A}\x{749B}' .
          '\x{749C}\x{749E}\x{749F}\x{74A0}\x{74A1}\x{74A3}\x{74A4}\x{74A5}\x{74A6}' .
          '\x{74A7}\x{74A8}\x{74A9}\x{74AA}\x{74AB}\x{74AC}\x{74AD}\x{74AE}\x{74AF}' .
          '\x{74B0}\x{74B1}\x{74B2}\x{74B3}\x{74B4}\x{74B5}\x{74B6}\x{74B7}\x{74B8}' .
          '\x{74B9}\x{74BA}\x{74BB}\x{74BC}\x{74BD}\x{74BE}\x{74BF}\x{74C0}\x{74C1}' .
          '\x{74C2}\x{74C3}\x{74C4}\x{74C5}\x{74C6}\x{74CA}\x{74CB}\x{74CD}\x{74CE}' .
          '\x{74CF}\x{74D0}\x{74D1}\x{74D2}\x{74D3}\x{74D4}\x{74D5}\x{74D6}\x{74D7}' .
          '\x{74D8}\x{74D9}\x{74DA}\x{74DB}\x{74DC}\x{74DD}\x{74DE}\x{74DF}\x{74E0}' .
          '\x{74E1}\x{74E2}\x{74E3}\x{74E4}\x{74E5}\x{74E6}\x{74E7}\x{74E8}\x{74E9}' .
          '\x{74EA}\x{74EC}\x{74ED}\x{74EE}\x{74EF}\x{74F0}\x{74F1}\x{74F2}\x{74F3}' .
          '\x{74F4}\x{74F5}\x{74F6}\x{74F7}\x{74F8}\x{74F9}\x{74FA}\x{74FB}\x{74FC}' .
          '\x{74FD}\x{74FE}\x{74FF}\x{7500}\x{7501}\x{7502}\x{7503}\x{7504}\x{7505}' .
          '\x{7506}\x{7507}\x{7508}\x{7509}\x{750A}\x{750B}\x{750C}\x{750D}\x{750F}' .
          '\x{7510}\x{7511}\x{7512}\x{7513}\x{7514}\x{7515}\x{7516}\x{7517}\x{7518}' .
          '\x{7519}\x{751A}\x{751B}\x{751C}\x{751D}\x{751E}\x{751F}\x{7521}\x{7522}' .
          '\x{7523}\x{7524}\x{7525}\x{7526}\x{7527}\x{7528}\x{7529}\x{752A}\x{752B}' .
          '\x{752C}\x{752D}\x{752E}\x{752F}\x{7530}\x{7531}\x{7532}\x{7533}\x{7535}' .
          '\x{7536}\x{7537}\x{7538}\x{7539}\x{753A}\x{753B}\x{753C}\x{753D}\x{753E}' .
          '\x{753F}\x{7540}\x{7542}\x{7543}\x{7544}\x{7545}\x{7546}\x{7547}\x{7548}' .
          '\x{7549}\x{754B}\x{754C}\x{754D}\x{754E}\x{754F}\x{7550}\x{7551}\x{7553}' .
          '\x{7554}\x{7556}\x{7557}\x{7558}\x{7559}\x{755A}\x{755B}\x{755C}\x{755D}' .
          '\x{755F}\x{7560}\x{7562}\x{7563}\x{7564}\x{7565}\x{7566}\x{7567}\x{7568}' .
          '\x{7569}\x{756A}\x{756B}\x{756C}\x{756D}\x{756E}\x{756F}\x{7570}\x{7572}' .
          '\x{7574}\x{7575}\x{7576}\x{7577}\x{7578}\x{7579}\x{757C}\x{757D}\x{757E}' .
          '\x{757F}\x{7580}\x{7581}\x{7582}\x{7583}\x{7584}\x{7586}\x{7587}\x{7588}' .
          '\x{7589}\x{758A}\x{758B}\x{758C}\x{758D}\x{758F}\x{7590}\x{7591}\x{7592}' .
          '\x{7593}\x{7594}\x{7595}\x{7596}\x{7597}\x{7598}\x{7599}\x{759A}\x{759B}' .
          '\x{759C}\x{759D}\x{759E}\x{759F}\x{75A0}\x{75A1}\x{75A2}\x{75A3}\x{75A4}' .
          '\x{75A5}\x{75A6}\x{75A7}\x{75A8}\x{75AA}\x{75AB}\x{75AC}\x{75AD}\x{75AE}' .
          '\x{75AF}\x{75B0}\x{75B1}\x{75B2}\x{75B3}\x{75B4}\x{75B5}\x{75B6}\x{75B8}' .
          '\x{75B9}\x{75BA}\x{75BB}\x{75BC}\x{75BD}\x{75BE}\x{75BF}\x{75C0}\x{75C1}' .
          '\x{75C2}\x{75C3}\x{75C4}\x{75C5}\x{75C6}\x{75C7}\x{75C8}\x{75C9}\x{75CA}' .
          '\x{75CB}\x{75CC}\x{75CD}\x{75CE}\x{75CF}\x{75D0}\x{75D1}\x{75D2}\x{75D3}' .
          '\x{75D4}\x{75D5}\x{75D6}\x{75D7}\x{75D8}\x{75D9}\x{75DA}\x{75DB}\x{75DD}' .
          '\x{75DE}\x{75DF}\x{75E0}\x{75E1}\x{75E2}\x{75E3}\x{75E4}\x{75E5}\x{75E6}' .
          '\x{75E7}\x{75E8}\x{75EA}\x{75EB}\x{75EC}\x{75ED}\x{75EF}\x{75F0}\x{75F1}' .
          '\x{75F2}\x{75F3}\x{75F4}\x{75F5}\x{75F6}\x{75F7}\x{75F8}\x{75F9}\x{75FA}' .
          '\x{75FB}\x{75FC}\x{75FD}\x{75FE}\x{75FF}\x{7600}\x{7601}\x{7602}\x{7603}' .
          '\x{7604}\x{7605}\x{7606}\x{7607}\x{7608}\x{7609}\x{760A}\x{760B}\x{760C}' .
          '\x{760D}\x{760E}\x{760F}\x{7610}\x{7611}\x{7612}\x{7613}\x{7614}\x{7615}' .
          '\x{7616}\x{7617}\x{7618}\x{7619}\x{761A}\x{761B}\x{761C}\x{761D}\x{761E}' .
          '\x{761F}\x{7620}\x{7621}\x{7622}\x{7623}\x{7624}\x{7625}\x{7626}\x{7627}' .
          '\x{7628}\x{7629}\x{762A}\x{762B}\x{762D}\x{762E}\x{762F}\x{7630}\x{7631}' .
          '\x{7632}\x{7633}\x{7634}\x{7635}\x{7636}\x{7637}\x{7638}\x{7639}\x{763A}' .
          '\x{763B}\x{763C}\x{763D}\x{763E}\x{763F}\x{7640}\x{7641}\x{7642}\x{7643}' .
          '\x{7646}\x{7647}\x{7648}\x{7649}\x{764A}\x{764B}\x{764C}\x{764D}\x{764F}' .
          '\x{7650}\x{7652}\x{7653}\x{7654}\x{7656}\x{7657}\x{7658}\x{7659}\x{765A}' .
          '\x{765B}\x{765C}\x{765D}\x{765E}\x{765F}\x{7660}\x{7661}\x{7662}\x{7663}' .
          '\x{7664}\x{7665}\x{7666}\x{7667}\x{7668}\x{7669}\x{766A}\x{766B}\x{766C}' .
          '\x{766D}\x{766E}\x{766F}\x{7670}\x{7671}\x{7672}\x{7674}\x{7675}\x{7676}' .
          '\x{7677}\x{7678}\x{7679}\x{767B}\x{767C}\x{767D}\x{767E}\x{767F}\x{7680}' .
          '\x{7681}\x{7682}\x{7683}\x{7684}\x{7685}\x{7686}\x{7687}\x{7688}\x{7689}' .
          '\x{768A}\x{768B}\x{768C}\x{768E}\x{768F}\x{7690}\x{7691}\x{7692}\x{7693}' .
          '\x{7694}\x{7695}\x{7696}\x{7697}\x{7698}\x{7699}\x{769A}\x{769B}\x{769C}' .
          '\x{769D}\x{769E}\x{769F}\x{76A0}\x{76A3}\x{76A4}\x{76A6}\x{76A7}\x{76A9}' .
          '\x{76AA}\x{76AB}\x{76AC}\x{76AD}\x{76AE}\x{76AF}\x{76B0}\x{76B1}\x{76B2}' .
          '\x{76B4}\x{76B5}\x{76B7}\x{76B8}\x{76BA}\x{76BB}\x{76BC}\x{76BD}\x{76BE}' .
          '\x{76BF}\x{76C0}\x{76C2}\x{76C3}\x{76C4}\x{76C5}\x{76C6}\x{76C7}\x{76C8}' .
          '\x{76C9}\x{76CA}\x{76CD}\x{76CE}\x{76CF}\x{76D0}\x{76D1}\x{76D2}\x{76D3}' .
          '\x{76D4}\x{76D5}\x{76D6}\x{76D7}\x{76D8}\x{76DA}\x{76DB}\x{76DC}\x{76DD}' .
          '\x{76DE}\x{76DF}\x{76E0}\x{76E1}\x{76E2}\x{76E3}\x{76E4}\x{76E5}\x{76E6}' .
          '\x{76E7}\x{76E8}\x{76E9}\x{76EA}\x{76EC}\x{76ED}\x{76EE}\x{76EF}\x{76F0}' .
          '\x{76F1}\x{76F2}\x{76F3}\x{76F4}\x{76F5}\x{76F6}\x{76F7}\x{76F8}\x{76F9}' .
          '\x{76FA}\x{76FB}\x{76FC}\x{76FD}\x{76FE}\x{76FF}\x{7701}\x{7703}\x{7704}' .
          '\x{7705}\x{7706}\x{7707}\x{7708}\x{7709}\x{770A}\x{770B}\x{770C}\x{770D}' .
          '\x{770F}\x{7710}\x{7711}\x{7712}\x{7713}\x{7714}\x{7715}\x{7716}\x{7717}' .
          '\x{7718}\x{7719}\x{771A}\x{771B}\x{771C}\x{771D}\x{771E}\x{771F}\x{7720}' .
          '\x{7722}\x{7723}\x{7725}\x{7726}\x{7727}\x{7728}\x{7729}\x{772A}\x{772C}' .
          '\x{772D}\x{772E}\x{772F}\x{7730}\x{7731}\x{7732}\x{7733}\x{7734}\x{7735}' .
          '\x{7736}\x{7737}\x{7738}\x{7739}\x{773A}\x{773B}\x{773C}\x{773D}\x{773E}' .
          '\x{7740}\x{7741}\x{7743}\x{7744}\x{7745}\x{7746}\x{7747}\x{7748}\x{7749}' .
          '\x{774A}\x{774B}\x{774C}\x{774D}\x{774E}\x{774F}\x{7750}\x{7751}\x{7752}' .
          '\x{7753}\x{7754}\x{7755}\x{7756}\x{7757}\x{7758}\x{7759}\x{775A}\x{775B}' .
          '\x{775C}\x{775D}\x{775E}\x{775F}\x{7760}\x{7761}\x{7762}\x{7763}\x{7765}' .
          '\x{7766}\x{7767}\x{7768}\x{7769}\x{776A}\x{776B}\x{776C}\x{776D}\x{776E}' .
          '\x{776F}\x{7770}\x{7771}\x{7772}\x{7773}\x{7774}\x{7775}\x{7776}\x{7777}' .
          '\x{7778}\x{7779}\x{777A}\x{777B}\x{777C}\x{777D}\x{777E}\x{777F}\x{7780}' .
          '\x{7781}\x{7782}\x{7783}\x{7784}\x{7785}\x{7786}\x{7787}\x{7788}\x{7789}' .
          '\x{778A}\x{778B}\x{778C}\x{778D}\x{778E}\x{778F}\x{7790}\x{7791}\x{7792}' .
          '\x{7793}\x{7794}\x{7795}\x{7797}\x{7798}\x{7799}\x{779A}\x{779B}\x{779C}' .
          '\x{779D}\x{779E}\x{779F}\x{77A0}\x{77A1}\x{77A2}\x{77A3}\x{77A5}\x{77A6}' .
          '\x{77A7}\x{77A8}\x{77A9}\x{77AA}\x{77AB}\x{77AC}\x{77AD}\x{77AE}\x{77AF}' .
          '\x{77B0}\x{77B1}\x{77B2}\x{77B3}\x{77B4}\x{77B5}\x{77B6}\x{77B7}\x{77B8}' .
          '\x{77B9}\x{77BA}\x{77BB}\x{77BC}\x{77BD}\x{77BF}\x{77C0}\x{77C2}\x{77C3}' .
          '\x{77C4}\x{77C5}\x{77C6}\x{77C7}\x{77C8}\x{77C9}\x{77CA}\x{77CB}\x{77CC}' .
          '\x{77CD}\x{77CE}\x{77CF}\x{77D0}\x{77D1}\x{77D3}\x{77D4}\x{77D5}\x{77D6}' .
          '\x{77D7}\x{77D8}\x{77D9}\x{77DA}\x{77DB}\x{77DC}\x{77DE}\x{77DF}\x{77E0}' .
          '\x{77E1}\x{77E2}\x{77E3}\x{77E5}\x{77E7}\x{77E8}\x{77E9}\x{77EA}\x{77EB}' .
          '\x{77EC}\x{77ED}\x{77EE}\x{77EF}\x{77F0}\x{77F1}\x{77F2}\x{77F3}\x{77F6}' .
          '\x{77F7}\x{77F8}\x{77F9}\x{77FA}\x{77FB}\x{77FC}\x{77FD}\x{77FE}\x{77FF}' .
          '\x{7800}\x{7801}\x{7802}\x{7803}\x{7804}\x{7805}\x{7806}\x{7808}\x{7809}' .
          '\x{780A}\x{780B}\x{780C}\x{780D}\x{780E}\x{780F}\x{7810}\x{7811}\x{7812}' .
          '\x{7813}\x{7814}\x{7815}\x{7816}\x{7817}\x{7818}\x{7819}\x{781A}\x{781B}' .
          '\x{781C}\x{781D}\x{781E}\x{781F}\x{7820}\x{7821}\x{7822}\x{7823}\x{7825}' .
          '\x{7826}\x{7827}\x{7828}\x{7829}\x{782A}\x{782B}\x{782C}\x{782D}\x{782E}' .
          '\x{782F}\x{7830}\x{7831}\x{7832}\x{7833}\x{7834}\x{7835}\x{7837}\x{7838}' .
          '\x{7839}\x{783A}\x{783B}\x{783C}\x{783D}\x{783E}\x{7840}\x{7841}\x{7843}' .
          '\x{7844}\x{7845}\x{7847}\x{7848}\x{7849}\x{784A}\x{784C}\x{784D}\x{784E}' .
          '\x{7850}\x{7851}\x{7852}\x{7853}\x{7854}\x{7855}\x{7856}\x{7857}\x{7858}' .
          '\x{7859}\x{785A}\x{785B}\x{785C}\x{785D}\x{785E}\x{785F}\x{7860}\x{7861}' .
          '\x{7862}\x{7863}\x{7864}\x{7865}\x{7866}\x{7867}\x{7868}\x{7869}\x{786A}' .
          '\x{786B}\x{786C}\x{786D}\x{786E}\x{786F}\x{7870}\x{7871}\x{7872}\x{7873}' .
          '\x{7874}\x{7875}\x{7877}\x{7878}\x{7879}\x{787A}\x{787B}\x{787C}\x{787D}' .
          '\x{787E}\x{787F}\x{7880}\x{7881}\x{7882}\x{7883}\x{7884}\x{7885}\x{7886}' .
          '\x{7887}\x{7889}\x{788A}\x{788B}\x{788C}\x{788D}\x{788E}\x{788F}\x{7890}' .
          '\x{7891}\x{7892}\x{7893}\x{7894}\x{7895}\x{7896}\x{7897}\x{7898}\x{7899}' .
          '\x{789A}\x{789B}\x{789C}\x{789D}\x{789E}\x{789F}\x{78A0}\x{78A1}\x{78A2}' .
          '\x{78A3}\x{78A4}\x{78A5}\x{78A6}\x{78A7}\x{78A8}\x{78A9}\x{78AA}\x{78AB}' .
          '\x{78AC}\x{78AD}\x{78AE}\x{78AF}\x{78B0}\x{78B1}\x{78B2}\x{78B3}\x{78B4}' .
          '\x{78B5}\x{78B6}\x{78B7}\x{78B8}\x{78B9}\x{78BA}\x{78BB}\x{78BC}\x{78BD}' .
          '\x{78BE}\x{78BF}\x{78C0}\x{78C1}\x{78C3}\x{78C4}\x{78C5}\x{78C6}\x{78C8}' .
          '\x{78C9}\x{78CA}\x{78CB}\x{78CC}\x{78CD}\x{78CE}\x{78CF}\x{78D0}\x{78D1}' .
          '\x{78D3}\x{78D4}\x{78D5}\x{78D6}\x{78D7}\x{78D8}\x{78D9}\x{78DA}\x{78DB}' .
          '\x{78DC}\x{78DD}\x{78DE}\x{78DF}\x{78E0}\x{78E1}\x{78E2}\x{78E3}\x{78E4}' .
          '\x{78E5}\x{78E6}\x{78E7}\x{78E8}\x{78E9}\x{78EA}\x{78EB}\x{78EC}\x{78ED}' .
          '\x{78EE}\x{78EF}\x{78F1}\x{78F2}\x{78F3}\x{78F4}\x{78F5}\x{78F6}\x{78F7}' .
          '\x{78F9}\x{78FA}\x{78FB}\x{78FC}\x{78FD}\x{78FE}\x{78FF}\x{7901}\x{7902}' .
          '\x{7903}\x{7904}\x{7905}\x{7906}\x{7907}\x{7909}\x{790A}\x{790B}\x{790C}' .
          '\x{790E}\x{790F}\x{7910}\x{7911}\x{7912}\x{7913}\x{7914}\x{7916}\x{7917}' .
          '\x{7918}\x{7919}\x{791A}\x{791B}\x{791C}\x{791D}\x{791E}\x{7921}\x{7922}' .
          '\x{7923}\x{7924}\x{7925}\x{7926}\x{7927}\x{7928}\x{7929}\x{792A}\x{792B}' .
          '\x{792C}\x{792D}\x{792E}\x{792F}\x{7930}\x{7931}\x{7933}\x{7934}\x{7935}' .
          '\x{7937}\x{7938}\x{7939}\x{793A}\x{793B}\x{793C}\x{793D}\x{793E}\x{793F}' .
          '\x{7940}\x{7941}\x{7942}\x{7943}\x{7944}\x{7945}\x{7946}\x{7947}\x{7948}' .
          '\x{7949}\x{794A}\x{794B}\x{794C}\x{794D}\x{794E}\x{794F}\x{7950}\x{7951}' .
          '\x{7952}\x{7953}\x{7954}\x{7955}\x{7956}\x{7957}\x{7958}\x{795A}\x{795B}' .
          '\x{795C}\x{795D}\x{795E}\x{795F}\x{7960}\x{7961}\x{7962}\x{7963}\x{7964}' .
          '\x{7965}\x{7966}\x{7967}\x{7968}\x{7969}\x{796A}\x{796B}\x{796D}\x{796F}' .
          '\x{7970}\x{7971}\x{7972}\x{7973}\x{7974}\x{7977}\x{7978}\x{7979}\x{797A}' .
          '\x{797B}\x{797C}\x{797D}\x{797E}\x{797F}\x{7980}\x{7981}\x{7982}\x{7983}' .
          '\x{7984}\x{7985}\x{7988}\x{7989}\x{798A}\x{798B}\x{798C}\x{798D}\x{798E}' .
          '\x{798F}\x{7990}\x{7991}\x{7992}\x{7993}\x{7994}\x{7995}\x{7996}\x{7997}' .
          '\x{7998}\x{7999}\x{799A}\x{799B}\x{799C}\x{799F}\x{79A0}\x{79A1}\x{79A2}' .
          '\x{79A3}\x{79A4}\x{79A5}\x{79A6}\x{79A7}\x{79A8}\x{79AA}\x{79AB}\x{79AC}' .
          '\x{79AD}\x{79AE}\x{79AF}\x{79B0}\x{79B1}\x{79B2}\x{79B3}\x{79B4}\x{79B5}' .
          '\x{79B6}\x{79B7}\x{79B8}\x{79B9}\x{79BA}\x{79BB}\x{79BD}\x{79BE}\x{79BF}' .
          '\x{79C0}\x{79C1}\x{79C2}\x{79C3}\x{79C5}\x{79C6}\x{79C8}\x{79C9}\x{79CA}' .
          '\x{79CB}\x{79CD}\x{79CE}\x{79CF}\x{79D0}\x{79D1}\x{79D2}\x{79D3}\x{79D5}' .
          '\x{79D6}\x{79D8}\x{79D9}\x{79DA}\x{79DB}\x{79DC}\x{79DD}\x{79DE}\x{79DF}' .
          '\x{79E0}\x{79E1}\x{79E2}\x{79E3}\x{79E4}\x{79E5}\x{79E6}\x{79E7}\x{79E8}' .
          '\x{79E9}\x{79EA}\x{79EB}\x{79EC}\x{79ED}\x{79EE}\x{79EF}\x{79F0}\x{79F1}' .
          '\x{79F2}\x{79F3}\x{79F4}\x{79F5}\x{79F6}\x{79F7}\x{79F8}\x{79F9}\x{79FA}' .
          '\x{79FB}\x{79FC}\x{79FD}\x{79FE}\x{79FF}\x{7A00}\x{7A02}\x{7A03}\x{7A04}' .
          '\x{7A05}\x{7A06}\x{7A08}\x{7A0A}\x{7A0B}\x{7A0C}\x{7A0D}\x{7A0E}\x{7A0F}' .
          '\x{7A10}\x{7A11}\x{7A12}\x{7A13}\x{7A14}\x{7A15}\x{7A16}\x{7A17}\x{7A18}' .
          '\x{7A19}\x{7A1A}\x{7A1B}\x{7A1C}\x{7A1D}\x{7A1E}\x{7A1F}\x{7A20}\x{7A21}' .
          '\x{7A22}\x{7A23}\x{7A24}\x{7A25}\x{7A26}\x{7A27}\x{7A28}\x{7A29}\x{7A2A}' .
          '\x{7A2B}\x{7A2D}\x{7A2E}\x{7A2F}\x{7A30}\x{7A31}\x{7A32}\x{7A33}\x{7A34}' .
          '\x{7A35}\x{7A37}\x{7A39}\x{7A3B}\x{7A3C}\x{7A3D}\x{7A3E}\x{7A3F}\x{7A40}' .
          '\x{7A41}\x{7A42}\x{7A43}\x{7A44}\x{7A45}\x{7A46}\x{7A47}\x{7A48}\x{7A49}' .
          '\x{7A4A}\x{7A4B}\x{7A4C}\x{7A4D}\x{7A4E}\x{7A50}\x{7A51}\x{7A52}\x{7A53}' .
          '\x{7A54}\x{7A55}\x{7A56}\x{7A57}\x{7A58}\x{7A59}\x{7A5A}\x{7A5B}\x{7A5C}' .
          '\x{7A5D}\x{7A5E}\x{7A5F}\x{7A60}\x{7A61}\x{7A62}\x{7A65}\x{7A66}\x{7A67}' .
          '\x{7A68}\x{7A69}\x{7A6B}\x{7A6C}\x{7A6D}\x{7A6E}\x{7A70}\x{7A71}\x{7A72}' .
          '\x{7A73}\x{7A74}\x{7A75}\x{7A76}\x{7A77}\x{7A78}\x{7A79}\x{7A7A}\x{7A7B}' .
          '\x{7A7C}\x{7A7D}\x{7A7E}\x{7A7F}\x{7A80}\x{7A81}\x{7A83}\x{7A84}\x{7A85}' .
          '\x{7A86}\x{7A87}\x{7A88}\x{7A89}\x{7A8A}\x{7A8B}\x{7A8C}\x{7A8D}\x{7A8E}' .
          '\x{7A8F}\x{7A90}\x{7A91}\x{7A92}\x{7A93}\x{7A94}\x{7A95}\x{7A96}\x{7A97}' .
          '\x{7A98}\x{7A99}\x{7A9C}\x{7A9D}\x{7A9E}\x{7A9F}\x{7AA0}\x{7AA1}\x{7AA2}' .
          '\x{7AA3}\x{7AA4}\x{7AA5}\x{7AA6}\x{7AA7}\x{7AA8}\x{7AA9}\x{7AAA}\x{7AAB}' .
          '\x{7AAC}\x{7AAD}\x{7AAE}\x{7AAF}\x{7AB0}\x{7AB1}\x{7AB2}\x{7AB3}\x{7AB4}' .
          '\x{7AB5}\x{7AB6}\x{7AB7}\x{7AB8}\x{7ABA}\x{7ABE}\x{7ABF}\x{7AC0}\x{7AC1}' .
          '\x{7AC4}\x{7AC5}\x{7AC7}\x{7AC8}\x{7AC9}\x{7ACA}\x{7ACB}\x{7ACC}\x{7ACD}' .
          '\x{7ACE}\x{7ACF}\x{7AD0}\x{7AD1}\x{7AD2}\x{7AD3}\x{7AD4}\x{7AD5}\x{7AD6}' .
          '\x{7AD8}\x{7AD9}\x{7ADB}\x{7ADC}\x{7ADD}\x{7ADE}\x{7ADF}\x{7AE0}\x{7AE1}' .
          '\x{7AE2}\x{7AE3}\x{7AE4}\x{7AE5}\x{7AE6}\x{7AE7}\x{7AE8}\x{7AEA}\x{7AEB}' .
          '\x{7AEC}\x{7AED}\x{7AEE}\x{7AEF}\x{7AF0}\x{7AF1}\x{7AF2}\x{7AF3}\x{7AF4}' .
          '\x{7AF6}\x{7AF7}\x{7AF8}\x{7AF9}\x{7AFA}\x{7AFB}\x{7AFD}\x{7AFE}\x{7AFF}' .
          '\x{7B00}\x{7B01}\x{7B02}\x{7B03}\x{7B04}\x{7B05}\x{7B06}\x{7B08}\x{7B09}' .
          '\x{7B0A}\x{7B0B}\x{7B0C}\x{7B0D}\x{7B0E}\x{7B0F}\x{7B10}\x{7B11}\x{7B12}' .
          '\x{7B13}\x{7B14}\x{7B15}\x{7B16}\x{7B17}\x{7B18}\x{7B19}\x{7B1A}\x{7B1B}' .
          '\x{7B1C}\x{7B1D}\x{7B1E}\x{7B20}\x{7B21}\x{7B22}\x{7B23}\x{7B24}\x{7B25}' .
          '\x{7B26}\x{7B28}\x{7B2A}\x{7B2B}\x{7B2C}\x{7B2D}\x{7B2E}\x{7B2F}\x{7B30}' .
          '\x{7B31}\x{7B32}\x{7B33}\x{7B34}\x{7B35}\x{7B36}\x{7B37}\x{7B38}\x{7B39}' .
          '\x{7B3A}\x{7B3B}\x{7B3C}\x{7B3D}\x{7B3E}\x{7B3F}\x{7B40}\x{7B41}\x{7B43}' .
          '\x{7B44}\x{7B45}\x{7B46}\x{7B47}\x{7B48}\x{7B49}\x{7B4A}\x{7B4B}\x{7B4C}' .
          '\x{7B4D}\x{7B4E}\x{7B4F}\x{7B50}\x{7B51}\x{7B52}\x{7B54}\x{7B55}\x{7B56}' .
          '\x{7B57}\x{7B58}\x{7B59}\x{7B5A}\x{7B5B}\x{7B5C}\x{7B5D}\x{7B5E}\x{7B5F}' .
          '\x{7B60}\x{7B61}\x{7B62}\x{7B63}\x{7B64}\x{7B65}\x{7B66}\x{7B67}\x{7B68}' .
          '\x{7B69}\x{7B6A}\x{7B6B}\x{7B6C}\x{7B6D}\x{7B6E}\x{7B70}\x{7B71}\x{7B72}' .
          '\x{7B73}\x{7B74}\x{7B75}\x{7B76}\x{7B77}\x{7B78}\x{7B79}\x{7B7B}\x{7B7C}' .
          '\x{7B7D}\x{7B7E}\x{7B7F}\x{7B80}\x{7B81}\x{7B82}\x{7B83}\x{7B84}\x{7B85}' .
          '\x{7B87}\x{7B88}\x{7B89}\x{7B8A}\x{7B8B}\x{7B8C}\x{7B8D}\x{7B8E}\x{7B8F}' .
          '\x{7B90}\x{7B91}\x{7B93}\x{7B94}\x{7B95}\x{7B96}\x{7B97}\x{7B98}\x{7B99}' .
          '\x{7B9A}\x{7B9B}\x{7B9C}\x{7B9D}\x{7B9E}\x{7B9F}\x{7BA0}\x{7BA1}\x{7BA2}' .
          '\x{7BA4}\x{7BA6}\x{7BA7}\x{7BA8}\x{7BA9}\x{7BAA}\x{7BAB}\x{7BAC}\x{7BAD}' .
          '\x{7BAE}\x{7BAF}\x{7BB1}\x{7BB3}\x{7BB4}\x{7BB5}\x{7BB6}\x{7BB7}\x{7BB8}' .
          '\x{7BB9}\x{7BBA}\x{7BBB}\x{7BBC}\x{7BBD}\x{7BBE}\x{7BBF}\x{7BC0}\x{7BC1}' .
          '\x{7BC2}\x{7BC3}\x{7BC4}\x{7BC5}\x{7BC6}\x{7BC7}\x{7BC8}\x{7BC9}\x{7BCA}' .
          '\x{7BCB}\x{7BCC}\x{7BCD}\x{7BCE}\x{7BD0}\x{7BD1}\x{7BD2}\x{7BD3}\x{7BD4}' .
          '\x{7BD5}\x{7BD6}\x{7BD7}\x{7BD8}\x{7BD9}\x{7BDA}\x{7BDB}\x{7BDC}\x{7BDD}' .
          '\x{7BDE}\x{7BDF}\x{7BE0}\x{7BE1}\x{7BE2}\x{7BE3}\x{7BE4}\x{7BE5}\x{7BE6}' .
          '\x{7BE7}\x{7BE8}\x{7BE9}\x{7BEA}\x{7BEB}\x{7BEC}\x{7BED}\x{7BEE}\x{7BEF}' .
          '\x{7BF0}\x{7BF1}\x{7BF2}\x{7BF3}\x{7BF4}\x{7BF5}\x{7BF6}\x{7BF7}\x{7BF8}' .
          '\x{7BF9}\x{7BFB}\x{7BFC}\x{7BFD}\x{7BFE}\x{7BFF}\x{7C00}\x{7C01}\x{7C02}' .
          '\x{7C03}\x{7C04}\x{7C05}\x{7C06}\x{7C07}\x{7C08}\x{7C09}\x{7C0A}\x{7C0B}' .
          '\x{7C0C}\x{7C0D}\x{7C0E}\x{7C0F}\x{7C10}\x{7C11}\x{7C12}\x{7C13}\x{7C15}' .
          '\x{7C16}\x{7C17}\x{7C18}\x{7C19}\x{7C1A}\x{7C1C}\x{7C1D}\x{7C1E}\x{7C1F}' .
          '\x{7C20}\x{7C21}\x{7C22}\x{7C23}\x{7C24}\x{7C25}\x{7C26}\x{7C27}\x{7C28}' .
          '\x{7C29}\x{7C2A}\x{7C2B}\x{7C2C}\x{7C2D}\x{7C30}\x{7C31}\x{7C32}\x{7C33}' .
          '\x{7C34}\x{7C35}\x{7C36}\x{7C37}\x{7C38}\x{7C39}\x{7C3A}\x{7C3B}\x{7C3C}' .
          '\x{7C3D}\x{7C3E}\x{7C3F}\x{7C40}\x{7C41}\x{7C42}\x{7C43}\x{7C44}\x{7C45}' .
          '\x{7C46}\x{7C47}\x{7C48}\x{7C49}\x{7C4A}\x{7C4B}\x{7C4C}\x{7C4D}\x{7C4E}' .
          '\x{7C50}\x{7C51}\x{7C53}\x{7C54}\x{7C56}\x{7C57}\x{7C58}\x{7C59}\x{7C5A}' .
          '\x{7C5B}\x{7C5C}\x{7C5E}\x{7C5F}\x{7C60}\x{7C61}\x{7C62}\x{7C63}\x{7C64}' .
          '\x{7C65}\x{7C66}\x{7C67}\x{7C68}\x{7C69}\x{7C6A}\x{7C6B}\x{7C6C}\x{7C6D}' .
          '\x{7C6E}\x{7C6F}\x{7C70}\x{7C71}\x{7C72}\x{7C73}\x{7C74}\x{7C75}\x{7C77}' .
          '\x{7C78}\x{7C79}\x{7C7A}\x{7C7B}\x{7C7C}\x{7C7D}\x{7C7E}\x{7C7F}\x{7C80}' .
          '\x{7C81}\x{7C82}\x{7C84}\x{7C85}\x{7C86}\x{7C88}\x{7C89}\x{7C8A}\x{7C8B}' .
          '\x{7C8C}\x{7C8D}\x{7C8E}\x{7C8F}\x{7C90}\x{7C91}\x{7C92}\x{7C94}\x{7C95}' .
          '\x{7C96}\x{7C97}\x{7C98}\x{7C99}\x{7C9B}\x{7C9C}\x{7C9D}\x{7C9E}\x{7C9F}' .
          '\x{7CA0}\x{7CA1}\x{7CA2}\x{7CA3}\x{7CA4}\x{7CA5}\x{7CA6}\x{7CA7}\x{7CA8}' .
          '\x{7CA9}\x{7CAA}\x{7CAD}\x{7CAE}\x{7CAF}\x{7CB0}\x{7CB1}\x{7CB2}\x{7CB3}' .
          '\x{7CB4}\x{7CB5}\x{7CB6}\x{7CB7}\x{7CB8}\x{7CB9}\x{7CBA}\x{7CBB}\x{7CBC}' .
          '\x{7CBD}\x{7CBE}\x{7CBF}\x{7CC0}\x{7CC1}\x{7CC2}\x{7CC3}\x{7CC4}\x{7CC5}' .
          '\x{7CC6}\x{7CC7}\x{7CC8}\x{7CC9}\x{7CCA}\x{7CCB}\x{7CCC}\x{7CCD}\x{7CCE}' .
          '\x{7CCF}\x{7CD0}\x{7CD1}\x{7CD2}\x{7CD4}\x{7CD5}\x{7CD6}\x{7CD7}\x{7CD8}' .
          '\x{7CD9}\x{7CDC}\x{7CDD}\x{7CDE}\x{7CDF}\x{7CE0}\x{7CE2}\x{7CE4}\x{7CE7}' .
          '\x{7CE8}\x{7CE9}\x{7CEA}\x{7CEB}\x{7CEC}\x{7CED}\x{7CEE}\x{7CEF}\x{7CF0}' .
          '\x{7CF1}\x{7CF2}\x{7CF3}\x{7CF4}\x{7CF5}\x{7CF6}\x{7CF7}\x{7CF8}\x{7CF9}' .
          '\x{7CFA}\x{7CFB}\x{7CFD}\x{7CFE}\x{7D00}\x{7D01}\x{7D02}\x{7D03}\x{7D04}' .
          '\x{7D05}\x{7D06}\x{7D07}\x{7D08}\x{7D09}\x{7D0A}\x{7D0B}\x{7D0C}\x{7D0D}' .
          '\x{7D0E}\x{7D0F}\x{7D10}\x{7D11}\x{7D12}\x{7D13}\x{7D14}\x{7D15}\x{7D16}' .
          '\x{7D17}\x{7D18}\x{7D19}\x{7D1A}\x{7D1B}\x{7D1C}\x{7D1D}\x{7D1E}\x{7D1F}' .
          '\x{7D20}\x{7D21}\x{7D22}\x{7D24}\x{7D25}\x{7D26}\x{7D27}\x{7D28}\x{7D29}' .
          '\x{7D2B}\x{7D2C}\x{7D2E}\x{7D2F}\x{7D30}\x{7D31}\x{7D32}\x{7D33}\x{7D34}' .
          '\x{7D35}\x{7D36}\x{7D37}\x{7D38}\x{7D39}\x{7D3A}\x{7D3B}\x{7D3C}\x{7D3D}' .
          '\x{7D3E}\x{7D3F}\x{7D40}\x{7D41}\x{7D42}\x{7D43}\x{7D44}\x{7D45}\x{7D46}' .
          '\x{7D47}\x{7D49}\x{7D4A}\x{7D4B}\x{7D4C}\x{7D4E}\x{7D4F}\x{7D50}\x{7D51}' .
          '\x{7D52}\x{7D53}\x{7D54}\x{7D55}\x{7D56}\x{7D57}\x{7D58}\x{7D59}\x{7D5B}' .
          '\x{7D5C}\x{7D5D}\x{7D5E}\x{7D5F}\x{7D60}\x{7D61}\x{7D62}\x{7D63}\x{7D65}' .
          '\x{7D66}\x{7D67}\x{7D68}\x{7D69}\x{7D6A}\x{7D6B}\x{7D6C}\x{7D6D}\x{7D6E}' .
          '\x{7D6F}\x{7D70}\x{7D71}\x{7D72}\x{7D73}\x{7D74}\x{7D75}\x{7D76}\x{7D77}' .
          '\x{7D79}\x{7D7A}\x{7D7B}\x{7D7C}\x{7D7D}\x{7D7E}\x{7D7F}\x{7D80}\x{7D81}' .
          '\x{7D83}\x{7D84}\x{7D85}\x{7D86}\x{7D87}\x{7D88}\x{7D89}\x{7D8A}\x{7D8B}' .
          '\x{7D8C}\x{7D8D}\x{7D8E}\x{7D8F}\x{7D90}\x{7D91}\x{7D92}\x{7D93}\x{7D94}' .
          '\x{7D96}\x{7D97}\x{7D99}\x{7D9B}\x{7D9C}\x{7D9D}\x{7D9E}\x{7D9F}\x{7DA0}' .
          '\x{7DA1}\x{7DA2}\x{7DA3}\x{7DA5}\x{7DA6}\x{7DA7}\x{7DA9}\x{7DAA}\x{7DAB}' .
          '\x{7DAC}\x{7DAD}\x{7DAE}\x{7DAF}\x{7DB0}\x{7DB1}\x{7DB2}\x{7DB3}\x{7DB4}' .
          '\x{7DB5}\x{7DB6}\x{7DB7}\x{7DB8}\x{7DB9}\x{7DBA}\x{7DBB}\x{7DBC}\x{7DBD}' .
          '\x{7DBE}\x{7DBF}\x{7DC0}\x{7DC1}\x{7DC2}\x{7DC3}\x{7DC4}\x{7DC5}\x{7DC6}' .
          '\x{7DC7}\x{7DC8}\x{7DC9}\x{7DCA}\x{7DCB}\x{7DCC}\x{7DCE}\x{7DCF}\x{7DD0}' .
          '\x{7DD1}\x{7DD2}\x{7DD4}\x{7DD5}\x{7DD6}\x{7DD7}\x{7DD8}\x{7DD9}\x{7DDA}' .
          '\x{7DDB}\x{7DDD}\x{7DDE}\x{7DDF}\x{7DE0}\x{7DE1}\x{7DE2}\x{7DE3}\x{7DE6}' .
          '\x{7DE7}\x{7DE8}\x{7DE9}\x{7DEA}\x{7DEC}\x{7DED}\x{7DEE}\x{7DEF}\x{7DF0}' .
          '\x{7DF1}\x{7DF2}\x{7DF3}\x{7DF4}\x{7DF5}\x{7DF6}\x{7DF7}\x{7DF8}\x{7DF9}' .
          '\x{7DFA}\x{7DFB}\x{7DFC}\x{7E00}\x{7E01}\x{7E02}\x{7E03}\x{7E04}\x{7E05}' .
          '\x{7E06}\x{7E07}\x{7E08}\x{7E09}\x{7E0A}\x{7E0B}\x{7E0C}\x{7E0D}\x{7E0E}' .
          '\x{7E0F}\x{7E10}\x{7E11}\x{7E12}\x{7E13}\x{7E14}\x{7E15}\x{7E16}\x{7E17}' .
          '\x{7E19}\x{7E1A}\x{7E1B}\x{7E1C}\x{7E1D}\x{7E1E}\x{7E1F}\x{7E20}\x{7E21}' .
          '\x{7E22}\x{7E23}\x{7E24}\x{7E25}\x{7E26}\x{7E27}\x{7E28}\x{7E29}\x{7E2A}' .
          '\x{7E2B}\x{7E2C}\x{7E2D}\x{7E2E}\x{7E2F}\x{7E30}\x{7E31}\x{7E32}\x{7E33}' .
          '\x{7E34}\x{7E35}\x{7E36}\x{7E37}\x{7E38}\x{7E39}\x{7E3A}\x{7E3B}\x{7E3C}' .
          '\x{7E3D}\x{7E3E}\x{7E3F}\x{7E40}\x{7E41}\x{7E42}\x{7E43}\x{7E44}\x{7E45}' .
          '\x{7E46}\x{7E47}\x{7E48}\x{7E49}\x{7E4C}\x{7E4D}\x{7E4E}\x{7E4F}\x{7E50}' .
          '\x{7E51}\x{7E52}\x{7E53}\x{7E54}\x{7E55}\x{7E56}\x{7E57}\x{7E58}\x{7E59}' .
          '\x{7E5A}\x{7E5C}\x{7E5D}\x{7E5E}\x{7E5F}\x{7E60}\x{7E61}\x{7E62}\x{7E63}' .
          '\x{7E65}\x{7E66}\x{7E67}\x{7E68}\x{7E69}\x{7E6A}\x{7E6B}\x{7E6C}\x{7E6D}' .
          '\x{7E6E}\x{7E6F}\x{7E70}\x{7E71}\x{7E72}\x{7E73}\x{7E74}\x{7E75}\x{7E76}' .
          '\x{7E77}\x{7E78}\x{7E79}\x{7E7A}\x{7E7B}\x{7E7C}\x{7E7D}\x{7E7E}\x{7E7F}' .
          '\x{7E80}\x{7E81}\x{7E82}\x{7E83}\x{7E84}\x{7E85}\x{7E86}\x{7E87}\x{7E88}' .
          '\x{7E89}\x{7E8A}\x{7E8B}\x{7E8C}\x{7E8D}\x{7E8E}\x{7E8F}\x{7E90}\x{7E91}' .
          '\x{7E92}\x{7E93}\x{7E94}\x{7E95}\x{7E96}\x{7E97}\x{7E98}\x{7E99}\x{7E9A}' .
          '\x{7E9B}\x{7E9C}\x{7E9E}\x{7E9F}\x{7EA0}\x{7EA1}\x{7EA2}\x{7EA3}\x{7EA4}' .
          '\x{7EA5}\x{7EA6}\x{7EA7}\x{7EA8}\x{7EA9}\x{7EAA}\x{7EAB}\x{7EAC}\x{7EAD}' .
          '\x{7EAE}\x{7EAF}\x{7EB0}\x{7EB1}\x{7EB2}\x{7EB3}\x{7EB4}\x{7EB5}\x{7EB6}' .
          '\x{7EB7}\x{7EB8}\x{7EB9}\x{7EBA}\x{7EBB}\x{7EBC}\x{7EBD}\x{7EBE}\x{7EBF}' .
          '\x{7EC0}\x{7EC1}\x{7EC2}\x{7EC3}\x{7EC4}\x{7EC5}\x{7EC6}\x{7EC7}\x{7EC8}' .
          '\x{7EC9}\x{7ECA}\x{7ECB}\x{7ECC}\x{7ECD}\x{7ECE}\x{7ECF}\x{7ED0}\x{7ED1}' .
          '\x{7ED2}\x{7ED3}\x{7ED4}\x{7ED5}\x{7ED6}\x{7ED7}\x{7ED8}\x{7ED9}\x{7EDA}' .
          '\x{7EDB}\x{7EDC}\x{7EDD}\x{7EDE}\x{7EDF}\x{7EE0}\x{7EE1}\x{7EE2}\x{7EE3}' .
          '\x{7EE4}\x{7EE5}\x{7EE6}\x{7EE7}\x{7EE8}\x{7EE9}\x{7EEA}\x{7EEB}\x{7EEC}' .
          '\x{7EED}\x{7EEE}\x{7EEF}\x{7EF0}\x{7EF1}\x{7EF2}\x{7EF3}\x{7EF4}\x{7EF5}' .
          '\x{7EF6}\x{7EF7}\x{7EF8}\x{7EF9}\x{7EFA}\x{7EFB}\x{7EFC}\x{7EFD}\x{7EFE}' .
          '\x{7EFF}\x{7F00}\x{7F01}\x{7F02}\x{7F03}\x{7F04}\x{7F05}\x{7F06}\x{7F07}' .
          '\x{7F08}\x{7F09}\x{7F0A}\x{7F0B}\x{7F0C}\x{7F0D}\x{7F0E}\x{7F0F}\x{7F10}' .
          '\x{7F11}\x{7F12}\x{7F13}\x{7F14}\x{7F15}\x{7F16}\x{7F17}\x{7F18}\x{7F19}' .
          '\x{7F1A}\x{7F1B}\x{7F1C}\x{7F1D}\x{7F1E}\x{7F1F}\x{7F20}\x{7F21}\x{7F22}' .
          '\x{7F23}\x{7F24}\x{7F25}\x{7F26}\x{7F27}\x{7F28}\x{7F29}\x{7F2A}\x{7F2B}' .
          '\x{7F2C}\x{7F2D}\x{7F2E}\x{7F2F}\x{7F30}\x{7F31}\x{7F32}\x{7F33}\x{7F34}' .
          '\x{7F35}\x{7F36}\x{7F37}\x{7F38}\x{7F39}\x{7F3A}\x{7F3D}\x{7F3E}\x{7F3F}' .
          '\x{7F40}\x{7F42}\x{7F43}\x{7F44}\x{7F45}\x{7F47}\x{7F48}\x{7F49}\x{7F4A}' .
          '\x{7F4B}\x{7F4C}\x{7F4D}\x{7F4E}\x{7F4F}\x{7F50}\x{7F51}\x{7F52}\x{7F53}' .
          '\x{7F54}\x{7F55}\x{7F56}\x{7F57}\x{7F58}\x{7F5A}\x{7F5B}\x{7F5C}\x{7F5D}' .
          '\x{7F5E}\x{7F5F}\x{7F60}\x{7F61}\x{7F62}\x{7F63}\x{7F64}\x{7F65}\x{7F66}' .
          '\x{7F67}\x{7F68}\x{7F69}\x{7F6A}\x{7F6B}\x{7F6C}\x{7F6D}\x{7F6E}\x{7F6F}' .
          '\x{7F70}\x{7F71}\x{7F72}\x{7F73}\x{7F74}\x{7F75}\x{7F76}\x{7F77}\x{7F78}' .
          '\x{7F79}\x{7F7A}\x{7F7B}\x{7F7C}\x{7F7D}\x{7F7E}\x{7F7F}\x{7F80}\x{7F81}' .
          '\x{7F82}\x{7F83}\x{7F85}\x{7F86}\x{7F87}\x{7F88}\x{7F89}\x{7F8A}\x{7F8B}' .
          '\x{7F8C}\x{7F8D}\x{7F8E}\x{7F8F}\x{7F91}\x{7F92}\x{7F93}\x{7F94}\x{7F95}' .
          '\x{7F96}\x{7F98}\x{7F9A}\x{7F9B}\x{7F9C}\x{7F9D}\x{7F9E}\x{7F9F}\x{7FA0}' .
          '\x{7FA1}\x{7FA2}\x{7FA3}\x{7FA4}\x{7FA5}\x{7FA6}\x{7FA7}\x{7FA8}\x{7FA9}' .
          '\x{7FAA}\x{7FAB}\x{7FAC}\x{7FAD}\x{7FAE}\x{7FAF}\x{7FB0}\x{7FB1}\x{7FB2}' .
          '\x{7FB3}\x{7FB5}\x{7FB6}\x{7FB7}\x{7FB8}\x{7FB9}\x{7FBA}\x{7FBB}\x{7FBC}' .
          '\x{7FBD}\x{7FBE}\x{7FBF}\x{7FC0}\x{7FC1}\x{7FC2}\x{7FC3}\x{7FC4}\x{7FC5}' .
          '\x{7FC6}\x{7FC7}\x{7FC8}\x{7FC9}\x{7FCA}\x{7FCB}\x{7FCC}\x{7FCD}\x{7FCE}' .
          '\x{7FCF}\x{7FD0}\x{7FD1}\x{7FD2}\x{7FD3}\x{7FD4}\x{7FD5}\x{7FD7}\x{7FD8}' .
          '\x{7FD9}\x{7FDA}\x{7FDB}\x{7FDC}\x{7FDE}\x{7FDF}\x{7FE0}\x{7FE1}\x{7FE2}' .
          '\x{7FE3}\x{7FE5}\x{7FE6}\x{7FE7}\x{7FE8}\x{7FE9}\x{7FEA}\x{7FEB}\x{7FEC}' .
          '\x{7FED}\x{7FEE}\x{7FEF}\x{7FF0}\x{7FF1}\x{7FF2}\x{7FF3}\x{7FF4}\x{7FF5}' .
          '\x{7FF6}\x{7FF7}\x{7FF8}\x{7FF9}\x{7FFA}\x{7FFB}\x{7FFC}\x{7FFD}\x{7FFE}' .
          '\x{7FFF}\x{8000}\x{8001}\x{8002}\x{8003}\x{8004}\x{8005}\x{8006}\x{8007}' .
          '\x{8008}\x{8009}\x{800B}\x{800C}\x{800D}\x{800E}\x{800F}\x{8010}\x{8011}' .
          '\x{8012}\x{8013}\x{8014}\x{8015}\x{8016}\x{8017}\x{8018}\x{8019}\x{801A}' .
          '\x{801B}\x{801C}\x{801D}\x{801E}\x{801F}\x{8020}\x{8021}\x{8022}\x{8023}' .
          '\x{8024}\x{8025}\x{8026}\x{8027}\x{8028}\x{8029}\x{802A}\x{802B}\x{802C}' .
          '\x{802D}\x{802E}\x{8030}\x{8031}\x{8032}\x{8033}\x{8034}\x{8035}\x{8036}' .
          '\x{8037}\x{8038}\x{8039}\x{803A}\x{803B}\x{803D}\x{803E}\x{803F}\x{8041}' .
          '\x{8042}\x{8043}\x{8044}\x{8045}\x{8046}\x{8047}\x{8048}\x{8049}\x{804A}' .
          '\x{804B}\x{804C}\x{804D}\x{804E}\x{804F}\x{8050}\x{8051}\x{8052}\x{8053}' .
          '\x{8054}\x{8055}\x{8056}\x{8057}\x{8058}\x{8059}\x{805A}\x{805B}\x{805C}' .
          '\x{805D}\x{805E}\x{805F}\x{8060}\x{8061}\x{8062}\x{8063}\x{8064}\x{8065}' .
          '\x{8067}\x{8068}\x{8069}\x{806A}\x{806B}\x{806C}\x{806D}\x{806E}\x{806F}' .
          '\x{8070}\x{8071}\x{8072}\x{8073}\x{8074}\x{8075}\x{8076}\x{8077}\x{8078}' .
          '\x{8079}\x{807A}\x{807B}\x{807C}\x{807D}\x{807E}\x{807F}\x{8080}\x{8081}' .
          '\x{8082}\x{8083}\x{8084}\x{8085}\x{8086}\x{8087}\x{8089}\x{808A}\x{808B}' .
          '\x{808C}\x{808D}\x{808F}\x{8090}\x{8091}\x{8092}\x{8093}\x{8095}\x{8096}' .
          '\x{8097}\x{8098}\x{8099}\x{809A}\x{809B}\x{809C}\x{809D}\x{809E}\x{809F}' .
          '\x{80A0}\x{80A1}\x{80A2}\x{80A3}\x{80A4}\x{80A5}\x{80A9}\x{80AA}\x{80AB}' .
          '\x{80AD}\x{80AE}\x{80AF}\x{80B0}\x{80B1}\x{80B2}\x{80B4}\x{80B5}\x{80B6}' .
          '\x{80B7}\x{80B8}\x{80BA}\x{80BB}\x{80BC}\x{80BD}\x{80BE}\x{80BF}\x{80C0}' .
          '\x{80C1}\x{80C2}\x{80C3}\x{80C4}\x{80C5}\x{80C6}\x{80C7}\x{80C8}\x{80C9}' .
          '\x{80CA}\x{80CB}\x{80CC}\x{80CD}\x{80CE}\x{80CF}\x{80D0}\x{80D1}\x{80D2}' .
          '\x{80D3}\x{80D4}\x{80D5}\x{80D6}\x{80D7}\x{80D8}\x{80D9}\x{80DA}\x{80DB}' .
          '\x{80DC}\x{80DD}\x{80DE}\x{80E0}\x{80E1}\x{80E2}\x{80E3}\x{80E4}\x{80E5}' .
          '\x{80E6}\x{80E7}\x{80E8}\x{80E9}\x{80EA}\x{80EB}\x{80EC}\x{80ED}\x{80EE}' .
          '\x{80EF}\x{80F0}\x{80F1}\x{80F2}\x{80F3}\x{80F4}\x{80F5}\x{80F6}\x{80F7}' .
          '\x{80F8}\x{80F9}\x{80FA}\x{80FB}\x{80FC}\x{80FD}\x{80FE}\x{80FF}\x{8100}' .
          '\x{8101}\x{8102}\x{8105}\x{8106}\x{8107}\x{8108}\x{8109}\x{810A}\x{810B}' .
          '\x{810C}\x{810D}\x{810E}\x{810F}\x{8110}\x{8111}\x{8112}\x{8113}\x{8114}' .
          '\x{8115}\x{8116}\x{8118}\x{8119}\x{811A}\x{811B}\x{811C}\x{811D}\x{811E}' .
          '\x{811F}\x{8120}\x{8121}\x{8122}\x{8123}\x{8124}\x{8125}\x{8126}\x{8127}' .
          '\x{8128}\x{8129}\x{812A}\x{812B}\x{812C}\x{812D}\x{812E}\x{812F}\x{8130}' .
          '\x{8131}\x{8132}\x{8136}\x{8137}\x{8138}\x{8139}\x{813A}\x{813B}\x{813C}' .
          '\x{813D}\x{813E}\x{813F}\x{8140}\x{8141}\x{8142}\x{8143}\x{8144}\x{8145}' .
          '\x{8146}\x{8147}\x{8148}\x{8149}\x{814A}\x{814B}\x{814C}\x{814D}\x{814E}' .
          '\x{814F}\x{8150}\x{8151}\x{8152}\x{8153}\x{8154}\x{8155}\x{8156}\x{8157}' .
          '\x{8158}\x{8159}\x{815A}\x{815B}\x{815C}\x{815D}\x{815E}\x{8160}\x{8161}' .
          '\x{8162}\x{8163}\x{8164}\x{8165}\x{8166}\x{8167}\x{8168}\x{8169}\x{816A}' .
          '\x{816B}\x{816C}\x{816D}\x{816E}\x{816F}\x{8170}\x{8171}\x{8172}\x{8173}' .
          '\x{8174}\x{8175}\x{8176}\x{8177}\x{8178}\x{8179}\x{817A}\x{817B}\x{817C}' .
          '\x{817D}\x{817E}\x{817F}\x{8180}\x{8181}\x{8182}\x{8183}\x{8185}\x{8186}' .
          '\x{8187}\x{8188}\x{8189}\x{818A}\x{818B}\x{818C}\x{818D}\x{818E}\x{818F}' .
          '\x{8191}\x{8192}\x{8193}\x{8194}\x{8195}\x{8197}\x{8198}\x{8199}\x{819A}' .
          '\x{819B}\x{819C}\x{819D}\x{819E}\x{819F}\x{81A0}\x{81A1}\x{81A2}\x{81A3}' .
          '\x{81A4}\x{81A5}\x{81A6}\x{81A7}\x{81A8}\x{81A9}\x{81AA}\x{81AB}\x{81AC}' .
          '\x{81AD}\x{81AE}\x{81AF}\x{81B0}\x{81B1}\x{81B2}\x{81B3}\x{81B4}\x{81B5}' .
          '\x{81B6}\x{81B7}\x{81B8}\x{81B9}\x{81BA}\x{81BB}\x{81BC}\x{81BD}\x{81BE}' .
          '\x{81BF}\x{81C0}\x{81C1}\x{81C2}\x{81C3}\x{81C4}\x{81C5}\x{81C6}\x{81C7}' .
          '\x{81C8}\x{81C9}\x{81CA}\x{81CC}\x{81CD}\x{81CE}\x{81CF}\x{81D0}\x{81D1}' .
          '\x{81D2}\x{81D4}\x{81D5}\x{81D6}\x{81D7}\x{81D8}\x{81D9}\x{81DA}\x{81DB}' .
          '\x{81DC}\x{81DD}\x{81DE}\x{81DF}\x{81E0}\x{81E1}\x{81E2}\x{81E3}\x{81E5}' .
          '\x{81E6}\x{81E7}\x{81E8}\x{81E9}\x{81EA}\x{81EB}\x{81EC}\x{81ED}\x{81EE}' .
          '\x{81F1}\x{81F2}\x{81F3}\x{81F4}\x{81F5}\x{81F6}\x{81F7}\x{81F8}\x{81F9}' .
          '\x{81FA}\x{81FB}\x{81FC}\x{81FD}\x{81FE}\x{81FF}\x{8200}\x{8201}\x{8202}' .
          '\x{8203}\x{8204}\x{8205}\x{8206}\x{8207}\x{8208}\x{8209}\x{820A}\x{820B}' .
          '\x{820C}\x{820D}\x{820E}\x{820F}\x{8210}\x{8211}\x{8212}\x{8214}\x{8215}' .
          '\x{8216}\x{8218}\x{8219}\x{821A}\x{821B}\x{821C}\x{821D}\x{821E}\x{821F}' .
          '\x{8220}\x{8221}\x{8222}\x{8223}\x{8225}\x{8226}\x{8227}\x{8228}\x{8229}' .
          '\x{822A}\x{822B}\x{822C}\x{822D}\x{822F}\x{8230}\x{8231}\x{8232}\x{8233}' .
          '\x{8234}\x{8235}\x{8236}\x{8237}\x{8238}\x{8239}\x{823A}\x{823B}\x{823C}' .
          '\x{823D}\x{823E}\x{823F}\x{8240}\x{8242}\x{8243}\x{8244}\x{8245}\x{8246}' .
          '\x{8247}\x{8248}\x{8249}\x{824A}\x{824B}\x{824C}\x{824D}\x{824E}\x{824F}' .
          '\x{8250}\x{8251}\x{8252}\x{8253}\x{8254}\x{8255}\x{8256}\x{8257}\x{8258}' .
          '\x{8259}\x{825A}\x{825B}\x{825C}\x{825D}\x{825E}\x{825F}\x{8260}\x{8261}' .
          '\x{8263}\x{8264}\x{8266}\x{8267}\x{8268}\x{8269}\x{826A}\x{826B}\x{826C}' .
          '\x{826D}\x{826E}\x{826F}\x{8270}\x{8271}\x{8272}\x{8273}\x{8274}\x{8275}' .
          '\x{8276}\x{8277}\x{8278}\x{8279}\x{827A}\x{827B}\x{827C}\x{827D}\x{827E}' .
          '\x{827F}\x{8280}\x{8281}\x{8282}\x{8283}\x{8284}\x{8285}\x{8286}\x{8287}' .
          '\x{8288}\x{8289}\x{828A}\x{828B}\x{828D}\x{828E}\x{828F}\x{8290}\x{8291}' .
          '\x{8292}\x{8293}\x{8294}\x{8295}\x{8296}\x{8297}\x{8298}\x{8299}\x{829A}' .
          '\x{829B}\x{829C}\x{829D}\x{829E}\x{829F}\x{82A0}\x{82A1}\x{82A2}\x{82A3}' .
          '\x{82A4}\x{82A5}\x{82A6}\x{82A7}\x{82A8}\x{82A9}\x{82AA}\x{82AB}\x{82AC}' .
          '\x{82AD}\x{82AE}\x{82AF}\x{82B0}\x{82B1}\x{82B3}\x{82B4}\x{82B5}\x{82B6}' .
          '\x{82B7}\x{82B8}\x{82B9}\x{82BA}\x{82BB}\x{82BC}\x{82BD}\x{82BE}\x{82BF}' .
          '\x{82C0}\x{82C1}\x{82C2}\x{82C3}\x{82C4}\x{82C5}\x{82C6}\x{82C7}\x{82C8}' .
          '\x{82C9}\x{82CA}\x{82CB}\x{82CC}\x{82CD}\x{82CE}\x{82CF}\x{82D0}\x{82D1}' .
          '\x{82D2}\x{82D3}\x{82D4}\x{82D5}\x{82D6}\x{82D7}\x{82D8}\x{82D9}\x{82DA}' .
          '\x{82DB}\x{82DC}\x{82DD}\x{82DE}\x{82DF}\x{82E0}\x{82E1}\x{82E3}\x{82E4}' .
          '\x{82E5}\x{82E6}\x{82E7}\x{82E8}\x{82E9}\x{82EA}\x{82EB}\x{82EC}\x{82ED}' .
          '\x{82EE}\x{82EF}\x{82F0}\x{82F1}\x{82F2}\x{82F3}\x{82F4}\x{82F5}\x{82F6}' .
          '\x{82F7}\x{82F8}\x{82F9}\x{82FA}\x{82FB}\x{82FD}\x{82FE}\x{82FF}\x{8300}' .
          '\x{8301}\x{8302}\x{8303}\x{8304}\x{8305}\x{8306}\x{8307}\x{8308}\x{8309}' .
          '\x{830B}\x{830C}\x{830D}\x{830E}\x{830F}\x{8311}\x{8312}\x{8313}\x{8314}' .
          '\x{8315}\x{8316}\x{8317}\x{8318}\x{8319}\x{831A}\x{831B}\x{831C}\x{831D}' .
          '\x{831E}\x{831F}\x{8320}\x{8321}\x{8322}\x{8323}\x{8324}\x{8325}\x{8326}' .
          '\x{8327}\x{8328}\x{8329}\x{832A}\x{832B}\x{832C}\x{832D}\x{832E}\x{832F}' .
          '\x{8331}\x{8332}\x{8333}\x{8334}\x{8335}\x{8336}\x{8337}\x{8338}\x{8339}' .
          '\x{833A}\x{833B}\x{833C}\x{833D}\x{833E}\x{833F}\x{8340}\x{8341}\x{8342}' .
          '\x{8343}\x{8344}\x{8345}\x{8346}\x{8347}\x{8348}\x{8349}\x{834A}\x{834B}' .
          '\x{834C}\x{834D}\x{834E}\x{834F}\x{8350}\x{8351}\x{8352}\x{8353}\x{8354}' .
          '\x{8356}\x{8357}\x{8358}\x{8359}\x{835A}\x{835B}\x{835C}\x{835D}\x{835E}' .
          '\x{835F}\x{8360}\x{8361}\x{8362}\x{8363}\x{8364}\x{8365}\x{8366}\x{8367}' .
          '\x{8368}\x{8369}\x{836A}\x{836B}\x{836C}\x{836D}\x{836E}\x{836F}\x{8370}' .
          '\x{8371}\x{8372}\x{8373}\x{8374}\x{8375}\x{8376}\x{8377}\x{8378}\x{8379}' .
          '\x{837A}\x{837B}\x{837C}\x{837D}\x{837E}\x{837F}\x{8380}\x{8381}\x{8382}' .
          '\x{8383}\x{8384}\x{8385}\x{8386}\x{8387}\x{8388}\x{8389}\x{838A}\x{838B}' .
          '\x{838C}\x{838D}\x{838E}\x{838F}\x{8390}\x{8391}\x{8392}\x{8393}\x{8394}' .
          '\x{8395}\x{8396}\x{8397}\x{8398}\x{8399}\x{839A}\x{839B}\x{839C}\x{839D}' .
          '\x{839E}\x{83A0}\x{83A1}\x{83A2}\x{83A3}\x{83A4}\x{83A5}\x{83A6}\x{83A7}' .
          '\x{83A8}\x{83A9}\x{83AA}\x{83AB}\x{83AC}\x{83AD}\x{83AE}\x{83AF}\x{83B0}' .
          '\x{83B1}\x{83B2}\x{83B3}\x{83B4}\x{83B6}\x{83B7}\x{83B8}\x{83B9}\x{83BA}' .
          '\x{83BB}\x{83BC}\x{83BD}\x{83BF}\x{83C0}\x{83C1}\x{83C2}\x{83C3}\x{83C4}' .
          '\x{83C5}\x{83C6}\x{83C7}\x{83C8}\x{83C9}\x{83CA}\x{83CB}\x{83CC}\x{83CD}' .
          '\x{83CE}\x{83CF}\x{83D0}\x{83D1}\x{83D2}\x{83D3}\x{83D4}\x{83D5}\x{83D6}' .
          '\x{83D7}\x{83D8}\x{83D9}\x{83DA}\x{83DB}\x{83DC}\x{83DD}\x{83DE}\x{83DF}' .
          '\x{83E0}\x{83E1}\x{83E2}\x{83E3}\x{83E4}\x{83E5}\x{83E7}\x{83E8}\x{83E9}' .
          '\x{83EA}\x{83EB}\x{83EC}\x{83EE}\x{83EF}\x{83F0}\x{83F1}\x{83F2}\x{83F3}' .
          '\x{83F4}\x{83F5}\x{83F6}\x{83F7}\x{83F8}\x{83F9}\x{83FA}\x{83FB}\x{83FC}' .
          '\x{83FD}\x{83FE}\x{83FF}\x{8400}\x{8401}\x{8402}\x{8403}\x{8404}\x{8405}' .
          '\x{8406}\x{8407}\x{8408}\x{8409}\x{840A}\x{840B}\x{840C}\x{840D}\x{840E}' .
          '\x{840F}\x{8410}\x{8411}\x{8412}\x{8413}\x{8415}\x{8418}\x{8419}\x{841A}' .
          '\x{841B}\x{841C}\x{841D}\x{841E}\x{8421}\x{8422}\x{8423}\x{8424}\x{8425}' .
          '\x{8426}\x{8427}\x{8428}\x{8429}\x{842A}\x{842B}\x{842C}\x{842D}\x{842E}' .
          '\x{842F}\x{8430}\x{8431}\x{8432}\x{8433}\x{8434}\x{8435}\x{8436}\x{8437}' .
          '\x{8438}\x{8439}\x{843A}\x{843B}\x{843C}\x{843D}\x{843E}\x{843F}\x{8440}' .
          '\x{8441}\x{8442}\x{8443}\x{8444}\x{8445}\x{8446}\x{8447}\x{8448}\x{8449}' .
          '\x{844A}\x{844B}\x{844C}\x{844D}\x{844E}\x{844F}\x{8450}\x{8451}\x{8452}' .
          '\x{8453}\x{8454}\x{8455}\x{8456}\x{8457}\x{8459}\x{845A}\x{845B}\x{845C}' .
          '\x{845D}\x{845E}\x{845F}\x{8460}\x{8461}\x{8462}\x{8463}\x{8464}\x{8465}' .
          '\x{8466}\x{8467}\x{8468}\x{8469}\x{846A}\x{846B}\x{846C}\x{846D}\x{846E}' .
          '\x{846F}\x{8470}\x{8471}\x{8472}\x{8473}\x{8474}\x{8475}\x{8476}\x{8477}' .
          '\x{8478}\x{8479}\x{847A}\x{847B}\x{847C}\x{847D}\x{847E}\x{847F}\x{8480}' .
          '\x{8481}\x{8482}\x{8484}\x{8485}\x{8486}\x{8487}\x{8488}\x{8489}\x{848A}' .
          '\x{848B}\x{848C}\x{848D}\x{848E}\x{848F}\x{8490}\x{8491}\x{8492}\x{8493}' .
          '\x{8494}\x{8496}\x{8497}\x{8498}\x{8499}\x{849A}\x{849B}\x{849C}\x{849D}' .
          '\x{849E}\x{849F}\x{84A0}\x{84A1}\x{84A2}\x{84A3}\x{84A4}\x{84A5}\x{84A6}' .
          '\x{84A7}\x{84A8}\x{84A9}\x{84AA}\x{84AB}\x{84AC}\x{84AE}\x{84AF}\x{84B0}' .
          '\x{84B1}\x{84B2}\x{84B3}\x{84B4}\x{84B5}\x{84B6}\x{84B8}\x{84B9}\x{84BA}' .
          '\x{84BB}\x{84BC}\x{84BD}\x{84BE}\x{84BF}\x{84C0}\x{84C1}\x{84C2}\x{84C4}' .
          '\x{84C5}\x{84C6}\x{84C7}\x{84C8}\x{84C9}\x{84CA}\x{84CB}\x{84CC}\x{84CD}' .
          '\x{84CE}\x{84CF}\x{84D0}\x{84D1}\x{84D2}\x{84D3}\x{84D4}\x{84D5}\x{84D6}' .
          '\x{84D7}\x{84D8}\x{84D9}\x{84DB}\x{84DC}\x{84DD}\x{84DE}\x{84DF}\x{84E0}' .
          '\x{84E1}\x{84E2}\x{84E3}\x{84E4}\x{84E5}\x{84E6}\x{84E7}\x{84E8}\x{84E9}' .
          '\x{84EA}\x{84EB}\x{84EC}\x{84EE}\x{84EF}\x{84F0}\x{84F1}\x{84F2}\x{84F3}' .
          '\x{84F4}\x{84F5}\x{84F6}\x{84F7}\x{84F8}\x{84F9}\x{84FA}\x{84FB}\x{84FC}' .
          '\x{84FD}\x{84FE}\x{84FF}\x{8500}\x{8501}\x{8502}\x{8503}\x{8504}\x{8506}' .
          '\x{8507}\x{8508}\x{8509}\x{850A}\x{850B}\x{850C}\x{850D}\x{850E}\x{850F}' .
          '\x{8511}\x{8512}\x{8513}\x{8514}\x{8515}\x{8516}\x{8517}\x{8518}\x{8519}' .
          '\x{851A}\x{851B}\x{851C}\x{851D}\x{851E}\x{851F}\x{8520}\x{8521}\x{8522}' .
          '\x{8523}\x{8524}\x{8525}\x{8526}\x{8527}\x{8528}\x{8529}\x{852A}\x{852B}' .
          '\x{852C}\x{852D}\x{852E}\x{852F}\x{8530}\x{8531}\x{8534}\x{8535}\x{8536}' .
          '\x{8537}\x{8538}\x{8539}\x{853A}\x{853B}\x{853C}\x{853D}\x{853E}\x{853F}' .
          '\x{8540}\x{8541}\x{8542}\x{8543}\x{8544}\x{8545}\x{8546}\x{8547}\x{8548}' .
          '\x{8549}\x{854A}\x{854B}\x{854D}\x{854E}\x{854F}\x{8551}\x{8552}\x{8553}' .
          '\x{8554}\x{8555}\x{8556}\x{8557}\x{8558}\x{8559}\x{855A}\x{855B}\x{855C}' .
          '\x{855D}\x{855E}\x{855F}\x{8560}\x{8561}\x{8562}\x{8563}\x{8564}\x{8565}' .
          '\x{8566}\x{8567}\x{8568}\x{8569}\x{856A}\x{856B}\x{856C}\x{856D}\x{856E}' .
          '\x{856F}\x{8570}\x{8571}\x{8572}\x{8573}\x{8574}\x{8575}\x{8576}\x{8577}' .
          '\x{8578}\x{8579}\x{857A}\x{857B}\x{857C}\x{857D}\x{857E}\x{8580}\x{8581}' .
          '\x{8582}\x{8583}\x{8584}\x{8585}\x{8586}\x{8587}\x{8588}\x{8589}\x{858A}' .
          '\x{858B}\x{858C}\x{858D}\x{858E}\x{858F}\x{8590}\x{8591}\x{8592}\x{8594}' .
          '\x{8595}\x{8596}\x{8598}\x{8599}\x{859A}\x{859B}\x{859C}\x{859D}\x{859E}' .
          '\x{859F}\x{85A0}\x{85A1}\x{85A2}\x{85A3}\x{85A4}\x{85A5}\x{85A6}\x{85A7}' .
          '\x{85A8}\x{85A9}\x{85AA}\x{85AB}\x{85AC}\x{85AD}\x{85AE}\x{85AF}\x{85B0}' .
          '\x{85B1}\x{85B3}\x{85B4}\x{85B5}\x{85B6}\x{85B7}\x{85B8}\x{85B9}\x{85BA}' .
          '\x{85BC}\x{85BD}\x{85BE}\x{85BF}\x{85C0}\x{85C1}\x{85C2}\x{85C3}\x{85C4}' .
          '\x{85C5}\x{85C6}\x{85C7}\x{85C8}\x{85C9}\x{85CA}\x{85CB}\x{85CD}\x{85CE}' .
          '\x{85CF}\x{85D0}\x{85D1}\x{85D2}\x{85D3}\x{85D4}\x{85D5}\x{85D6}\x{85D7}' .
          '\x{85D8}\x{85D9}\x{85DA}\x{85DB}\x{85DC}\x{85DD}\x{85DE}\x{85DF}\x{85E0}' .
          '\x{85E1}\x{85E2}\x{85E3}\x{85E4}\x{85E5}\x{85E6}\x{85E7}\x{85E8}\x{85E9}' .
          '\x{85EA}\x{85EB}\x{85EC}\x{85ED}\x{85EF}\x{85F0}\x{85F1}\x{85F2}\x{85F4}' .
          '\x{85F5}\x{85F6}\x{85F7}\x{85F8}\x{85F9}\x{85FA}\x{85FB}\x{85FD}\x{85FE}' .
          '\x{85FF}\x{8600}\x{8601}\x{8602}\x{8604}\x{8605}\x{8606}\x{8607}\x{8608}' .
          '\x{8609}\x{860A}\x{860B}\x{860C}\x{860F}\x{8611}\x{8612}\x{8613}\x{8614}' .
          '\x{8616}\x{8617}\x{8618}\x{8619}\x{861A}\x{861B}\x{861C}\x{861E}\x{861F}' .
          '\x{8620}\x{8621}\x{8622}\x{8623}\x{8624}\x{8625}\x{8626}\x{8627}\x{8628}' .
          '\x{8629}\x{862A}\x{862B}\x{862C}\x{862D}\x{862E}\x{862F}\x{8630}\x{8631}' .
          '\x{8632}\x{8633}\x{8634}\x{8635}\x{8636}\x{8638}\x{8639}\x{863A}\x{863B}' .
          '\x{863C}\x{863D}\x{863E}\x{863F}\x{8640}\x{8641}\x{8642}\x{8643}\x{8644}' .
          '\x{8645}\x{8646}\x{8647}\x{8648}\x{8649}\x{864A}\x{864B}\x{864C}\x{864D}' .
          '\x{864E}\x{864F}\x{8650}\x{8651}\x{8652}\x{8653}\x{8654}\x{8655}\x{8656}' .
          '\x{8658}\x{8659}\x{865A}\x{865B}\x{865C}\x{865D}\x{865E}\x{865F}\x{8660}' .
          '\x{8661}\x{8662}\x{8663}\x{8664}\x{8665}\x{8666}\x{8667}\x{8668}\x{8669}' .
          '\x{866A}\x{866B}\x{866C}\x{866D}\x{866E}\x{866F}\x{8670}\x{8671}\x{8672}' .
          '\x{8673}\x{8674}\x{8676}\x{8677}\x{8678}\x{8679}\x{867A}\x{867B}\x{867C}' .
          '\x{867D}\x{867E}\x{867F}\x{8680}\x{8681}\x{8682}\x{8683}\x{8684}\x{8685}' .
          '\x{8686}\x{8687}\x{8688}\x{868A}\x{868B}\x{868C}\x{868D}\x{868E}\x{868F}' .
          '\x{8690}\x{8691}\x{8693}\x{8694}\x{8695}\x{8696}\x{8697}\x{8698}\x{8699}' .
          '\x{869A}\x{869B}\x{869C}\x{869D}\x{869E}\x{869F}\x{86A1}\x{86A2}\x{86A3}' .
          '\x{86A4}\x{86A5}\x{86A7}\x{86A8}\x{86A9}\x{86AA}\x{86AB}\x{86AC}\x{86AD}' .
          '\x{86AE}\x{86AF}\x{86B0}\x{86B1}\x{86B2}\x{86B3}\x{86B4}\x{86B5}\x{86B6}' .
          '\x{86B7}\x{86B8}\x{86B9}\x{86BA}\x{86BB}\x{86BC}\x{86BD}\x{86BE}\x{86BF}' .
          '\x{86C0}\x{86C1}\x{86C2}\x{86C3}\x{86C4}\x{86C5}\x{86C6}\x{86C7}\x{86C8}' .
          '\x{86C9}\x{86CA}\x{86CB}\x{86CC}\x{86CE}\x{86CF}\x{86D0}\x{86D1}\x{86D2}' .
          '\x{86D3}\x{86D4}\x{86D6}\x{86D7}\x{86D8}\x{86D9}\x{86DA}\x{86DB}\x{86DC}' .
          '\x{86DD}\x{86DE}\x{86DF}\x{86E1}\x{86E2}\x{86E3}\x{86E4}\x{86E5}\x{86E6}' .
          '\x{86E8}\x{86E9}\x{86EA}\x{86EB}\x{86EC}\x{86ED}\x{86EE}\x{86EF}\x{86F0}' .
          '\x{86F1}\x{86F2}\x{86F3}\x{86F4}\x{86F5}\x{86F6}\x{86F7}\x{86F8}\x{86F9}' .
          '\x{86FA}\x{86FB}\x{86FC}\x{86FE}\x{86FF}\x{8700}\x{8701}\x{8702}\x{8703}' .
          '\x{8704}\x{8705}\x{8706}\x{8707}\x{8708}\x{8709}\x{870A}\x{870B}\x{870C}' .
          '\x{870D}\x{870E}\x{870F}\x{8710}\x{8711}\x{8712}\x{8713}\x{8714}\x{8715}' .
          '\x{8716}\x{8717}\x{8718}\x{8719}\x{871A}\x{871B}\x{871C}\x{871E}\x{871F}' .
          '\x{8720}\x{8721}\x{8722}\x{8723}\x{8724}\x{8725}\x{8726}\x{8727}\x{8728}' .
          '\x{8729}\x{872A}\x{872B}\x{872C}\x{872D}\x{872E}\x{8730}\x{8731}\x{8732}' .
          '\x{8733}\x{8734}\x{8735}\x{8736}\x{8737}\x{8738}\x{8739}\x{873A}\x{873B}' .
          '\x{873C}\x{873E}\x{873F}\x{8740}\x{8741}\x{8742}\x{8743}\x{8744}\x{8746}' .
          '\x{8747}\x{8748}\x{8749}\x{874A}\x{874C}\x{874D}\x{874E}\x{874F}\x{8750}' .
          '\x{8751}\x{8752}\x{8753}\x{8754}\x{8755}\x{8756}\x{8757}\x{8758}\x{8759}' .
          '\x{875A}\x{875B}\x{875C}\x{875D}\x{875E}\x{875F}\x{8760}\x{8761}\x{8762}' .
          '\x{8763}\x{8764}\x{8765}\x{8766}\x{8767}\x{8768}\x{8769}\x{876A}\x{876B}' .
          '\x{876C}\x{876D}\x{876E}\x{876F}\x{8770}\x{8772}\x{8773}\x{8774}\x{8775}' .
          '\x{8776}\x{8777}\x{8778}\x{8779}\x{877A}\x{877B}\x{877C}\x{877D}\x{877E}' .
          '\x{8780}\x{8781}\x{8782}\x{8783}\x{8784}\x{8785}\x{8786}\x{8787}\x{8788}' .
          '\x{8789}\x{878A}\x{878B}\x{878C}\x{878D}\x{878F}\x{8790}\x{8791}\x{8792}' .
          '\x{8793}\x{8794}\x{8795}\x{8796}\x{8797}\x{8798}\x{879A}\x{879B}\x{879C}' .
          '\x{879D}\x{879E}\x{879F}\x{87A0}\x{87A1}\x{87A2}\x{87A3}\x{87A4}\x{87A5}' .
          '\x{87A6}\x{87A7}\x{87A8}\x{87A9}\x{87AA}\x{87AB}\x{87AC}\x{87AD}\x{87AE}' .
          '\x{87AF}\x{87B0}\x{87B1}\x{87B2}\x{87B3}\x{87B4}\x{87B5}\x{87B6}\x{87B7}' .
          '\x{87B8}\x{87B9}\x{87BA}\x{87BB}\x{87BC}\x{87BD}\x{87BE}\x{87BF}\x{87C0}' .
          '\x{87C1}\x{87C2}\x{87C3}\x{87C4}\x{87C5}\x{87C6}\x{87C7}\x{87C8}\x{87C9}' .
          '\x{87CA}\x{87CB}\x{87CC}\x{87CD}\x{87CE}\x{87CF}\x{87D0}\x{87D1}\x{87D2}' .
          '\x{87D3}\x{87D4}\x{87D5}\x{87D6}\x{87D7}\x{87D8}\x{87D9}\x{87DB}\x{87DC}' .
          '\x{87DD}\x{87DE}\x{87DF}\x{87E0}\x{87E1}\x{87E2}\x{87E3}\x{87E4}\x{87E5}' .
          '\x{87E6}\x{87E7}\x{87E8}\x{87E9}\x{87EA}\x{87EB}\x{87EC}\x{87ED}\x{87EE}' .
          '\x{87EF}\x{87F1}\x{87F2}\x{87F3}\x{87F4}\x{87F5}\x{87F6}\x{87F7}\x{87F8}' .
          '\x{87F9}\x{87FA}\x{87FB}\x{87FC}\x{87FD}\x{87FE}\x{87FF}\x{8800}\x{8801}' .
          '\x{8802}\x{8803}\x{8804}\x{8805}\x{8806}\x{8808}\x{8809}\x{880A}\x{880B}' .
          '\x{880C}\x{880D}\x{880E}\x{880F}\x{8810}\x{8811}\x{8813}\x{8814}\x{8815}' .
          '\x{8816}\x{8817}\x{8818}\x{8819}\x{881A}\x{881B}\x{881C}\x{881D}\x{881E}' .
          '\x{881F}\x{8820}\x{8821}\x{8822}\x{8823}\x{8824}\x{8825}\x{8826}\x{8827}' .
          '\x{8828}\x{8829}\x{882A}\x{882B}\x{882C}\x{882E}\x{882F}\x{8830}\x{8831}' .
          '\x{8832}\x{8833}\x{8834}\x{8835}\x{8836}\x{8837}\x{8838}\x{8839}\x{883B}' .
          '\x{883C}\x{883D}\x{883E}\x{883F}\x{8840}\x{8841}\x{8842}\x{8843}\x{8844}' .
          '\x{8845}\x{8846}\x{8848}\x{8849}\x{884A}\x{884B}\x{884C}\x{884D}\x{884E}' .
          '\x{884F}\x{8850}\x{8851}\x{8852}\x{8853}\x{8854}\x{8855}\x{8856}\x{8857}' .
          '\x{8859}\x{885A}\x{885B}\x{885D}\x{885E}\x{8860}\x{8861}\x{8862}\x{8863}' .
          '\x{8864}\x{8865}\x{8866}\x{8867}\x{8868}\x{8869}\x{886A}\x{886B}\x{886C}' .
          '\x{886D}\x{886E}\x{886F}\x{8870}\x{8871}\x{8872}\x{8873}\x{8874}\x{8875}' .
          '\x{8876}\x{8877}\x{8878}\x{8879}\x{887B}\x{887C}\x{887D}\x{887E}\x{887F}' .
          '\x{8880}\x{8881}\x{8882}\x{8883}\x{8884}\x{8885}\x{8886}\x{8887}\x{8888}' .
          '\x{8889}\x{888A}\x{888B}\x{888C}\x{888D}\x{888E}\x{888F}\x{8890}\x{8891}' .
          '\x{8892}\x{8893}\x{8894}\x{8895}\x{8896}\x{8897}\x{8898}\x{8899}\x{889A}' .
          '\x{889B}\x{889C}\x{889D}\x{889E}\x{889F}\x{88A0}\x{88A1}\x{88A2}\x{88A3}' .
          '\x{88A4}\x{88A5}\x{88A6}\x{88A7}\x{88A8}\x{88A9}\x{88AA}\x{88AB}\x{88AC}' .
          '\x{88AD}\x{88AE}\x{88AF}\x{88B0}\x{88B1}\x{88B2}\x{88B3}\x{88B4}\x{88B6}' .
          '\x{88B7}\x{88B8}\x{88B9}\x{88BA}\x{88BB}\x{88BC}\x{88BD}\x{88BE}\x{88BF}' .
          '\x{88C0}\x{88C1}\x{88C2}\x{88C3}\x{88C4}\x{88C5}\x{88C6}\x{88C7}\x{88C8}' .
          '\x{88C9}\x{88CA}\x{88CB}\x{88CC}\x{88CD}\x{88CE}\x{88CF}\x{88D0}\x{88D1}' .
          '\x{88D2}\x{88D3}\x{88D4}\x{88D5}\x{88D6}\x{88D7}\x{88D8}\x{88D9}\x{88DA}' .
          '\x{88DB}\x{88DC}\x{88DD}\x{88DE}\x{88DF}\x{88E0}\x{88E1}\x{88E2}\x{88E3}' .
          '\x{88E4}\x{88E5}\x{88E7}\x{88E8}\x{88EA}\x{88EB}\x{88EC}\x{88EE}\x{88EF}' .
          '\x{88F0}\x{88F1}\x{88F2}\x{88F3}\x{88F4}\x{88F5}\x{88F6}\x{88F7}\x{88F8}' .
          '\x{88F9}\x{88FA}\x{88FB}\x{88FC}\x{88FD}\x{88FE}\x{88FF}\x{8900}\x{8901}' .
          '\x{8902}\x{8904}\x{8905}\x{8906}\x{8907}\x{8908}\x{8909}\x{890A}\x{890B}' .
          '\x{890C}\x{890D}\x{890E}\x{8910}\x{8911}\x{8912}\x{8913}\x{8914}\x{8915}' .
          '\x{8916}\x{8917}\x{8918}\x{8919}\x{891A}\x{891B}\x{891C}\x{891D}\x{891E}' .
          '\x{891F}\x{8920}\x{8921}\x{8922}\x{8923}\x{8925}\x{8926}\x{8927}\x{8928}' .
          '\x{8929}\x{892A}\x{892B}\x{892C}\x{892D}\x{892E}\x{892F}\x{8930}\x{8931}' .
          '\x{8932}\x{8933}\x{8934}\x{8935}\x{8936}\x{8937}\x{8938}\x{8939}\x{893A}' .
          '\x{893B}\x{893C}\x{893D}\x{893E}\x{893F}\x{8940}\x{8941}\x{8942}\x{8943}' .
          '\x{8944}\x{8945}\x{8946}\x{8947}\x{8948}\x{8949}\x{894A}\x{894B}\x{894C}' .
          '\x{894E}\x{894F}\x{8950}\x{8951}\x{8952}\x{8953}\x{8954}\x{8955}\x{8956}' .
          '\x{8957}\x{8958}\x{8959}\x{895A}\x{895B}\x{895C}\x{895D}\x{895E}\x{895F}' .
          '\x{8960}\x{8961}\x{8962}\x{8963}\x{8964}\x{8966}\x{8967}\x{8968}\x{8969}' .
          '\x{896A}\x{896B}\x{896C}\x{896D}\x{896E}\x{896F}\x{8970}\x{8971}\x{8972}' .
          '\x{8973}\x{8974}\x{8976}\x{8977}\x{8978}\x{8979}\x{897A}\x{897B}\x{897C}' .
          '\x{897E}\x{897F}\x{8980}\x{8981}\x{8982}\x{8983}\x{8984}\x{8985}\x{8986}' .
          '\x{8987}\x{8988}\x{8989}\x{898A}\x{898B}\x{898C}\x{898E}\x{898F}\x{8991}' .
          '\x{8992}\x{8993}\x{8995}\x{8996}\x{8997}\x{8998}\x{899A}\x{899B}\x{899C}' .
          '\x{899D}\x{899E}\x{899F}\x{89A0}\x{89A1}\x{89A2}\x{89A3}\x{89A4}\x{89A5}' .
          '\x{89A6}\x{89A7}\x{89A8}\x{89AA}\x{89AB}\x{89AC}\x{89AD}\x{89AE}\x{89AF}' .
          '\x{89B1}\x{89B2}\x{89B3}\x{89B5}\x{89B6}\x{89B7}\x{89B8}\x{89B9}\x{89BA}' .
          '\x{89BD}\x{89BE}\x{89BF}\x{89C0}\x{89C1}\x{89C2}\x{89C3}\x{89C4}\x{89C5}' .
          '\x{89C6}\x{89C7}\x{89C8}\x{89C9}\x{89CA}\x{89CB}\x{89CC}\x{89CD}\x{89CE}' .
          '\x{89CF}\x{89D0}\x{89D1}\x{89D2}\x{89D3}\x{89D4}\x{89D5}\x{89D6}\x{89D7}' .
          '\x{89D8}\x{89D9}\x{89DA}\x{89DB}\x{89DC}\x{89DD}\x{89DE}\x{89DF}\x{89E0}' .
          '\x{89E1}\x{89E2}\x{89E3}\x{89E4}\x{89E5}\x{89E6}\x{89E7}\x{89E8}\x{89E9}' .
          '\x{89EA}\x{89EB}\x{89EC}\x{89ED}\x{89EF}\x{89F0}\x{89F1}\x{89F2}\x{89F3}' .
          '\x{89F4}\x{89F6}\x{89F7}\x{89F8}\x{89FA}\x{89FB}\x{89FC}\x{89FE}\x{89FF}' .
          '\x{8A00}\x{8A01}\x{8A02}\x{8A03}\x{8A04}\x{8A07}\x{8A08}\x{8A09}\x{8A0A}' .
          '\x{8A0B}\x{8A0C}\x{8A0D}\x{8A0E}\x{8A0F}\x{8A10}\x{8A11}\x{8A12}\x{8A13}' .
          '\x{8A15}\x{8A16}\x{8A17}\x{8A18}\x{8A1A}\x{8A1B}\x{8A1C}\x{8A1D}\x{8A1E}' .
          '\x{8A1F}\x{8A22}\x{8A23}\x{8A24}\x{8A25}\x{8A26}\x{8A27}\x{8A28}\x{8A29}' .
          '\x{8A2A}\x{8A2C}\x{8A2D}\x{8A2E}\x{8A2F}\x{8A30}\x{8A31}\x{8A32}\x{8A34}' .
          '\x{8A35}\x{8A36}\x{8A37}\x{8A38}\x{8A39}\x{8A3A}\x{8A3B}\x{8A3C}\x{8A3E}' .
          '\x{8A3F}\x{8A40}\x{8A41}\x{8A42}\x{8A43}\x{8A44}\x{8A45}\x{8A46}\x{8A47}' .
          '\x{8A48}\x{8A49}\x{8A4A}\x{8A4C}\x{8A4D}\x{8A4E}\x{8A4F}\x{8A50}\x{8A51}' .
          '\x{8A52}\x{8A53}\x{8A54}\x{8A55}\x{8A56}\x{8A57}\x{8A58}\x{8A59}\x{8A5A}' .
          '\x{8A5B}\x{8A5C}\x{8A5D}\x{8A5E}\x{8A5F}\x{8A60}\x{8A61}\x{8A62}\x{8A63}' .
          '\x{8A65}\x{8A66}\x{8A67}\x{8A68}\x{8A69}\x{8A6A}\x{8A6B}\x{8A6C}\x{8A6D}' .
          '\x{8A6E}\x{8A6F}\x{8A70}\x{8A71}\x{8A72}\x{8A73}\x{8A74}\x{8A75}\x{8A76}' .
          '\x{8A77}\x{8A79}\x{8A7A}\x{8A7B}\x{8A7C}\x{8A7E}\x{8A7F}\x{8A80}\x{8A81}' .
          '\x{8A82}\x{8A83}\x{8A84}\x{8A85}\x{8A86}\x{8A87}\x{8A89}\x{8A8A}\x{8A8B}' .
          '\x{8A8C}\x{8A8D}\x{8A8E}\x{8A8F}\x{8A90}\x{8A91}\x{8A92}\x{8A93}\x{8A94}' .
          '\x{8A95}\x{8A96}\x{8A97}\x{8A98}\x{8A99}\x{8A9A}\x{8A9B}\x{8A9C}\x{8A9D}' .
          '\x{8A9E}\x{8AA0}\x{8AA1}\x{8AA2}\x{8AA3}\x{8AA4}\x{8AA5}\x{8AA6}\x{8AA7}' .
          '\x{8AA8}\x{8AA9}\x{8AAA}\x{8AAB}\x{8AAC}\x{8AAE}\x{8AB0}\x{8AB1}\x{8AB2}' .
          '\x{8AB3}\x{8AB4}\x{8AB5}\x{8AB6}\x{8AB8}\x{8AB9}\x{8ABA}\x{8ABB}\x{8ABC}' .
          '\x{8ABD}\x{8ABE}\x{8ABF}\x{8AC0}\x{8AC1}\x{8AC2}\x{8AC3}\x{8AC4}\x{8AC5}' .
          '\x{8AC6}\x{8AC7}\x{8AC8}\x{8AC9}\x{8ACA}\x{8ACB}\x{8ACC}\x{8ACD}\x{8ACE}' .
          '\x{8ACF}\x{8AD1}\x{8AD2}\x{8AD3}\x{8AD4}\x{8AD5}\x{8AD6}\x{8AD7}\x{8AD8}' .
          '\x{8AD9}\x{8ADA}\x{8ADB}\x{8ADC}\x{8ADD}\x{8ADE}\x{8ADF}\x{8AE0}\x{8AE1}' .
          '\x{8AE2}\x{8AE3}\x{8AE4}\x{8AE5}\x{8AE6}\x{8AE7}\x{8AE8}\x{8AE9}\x{8AEA}' .
          '\x{8AEB}\x{8AED}\x{8AEE}\x{8AEF}\x{8AF0}\x{8AF1}\x{8AF2}\x{8AF3}\x{8AF4}' .
          '\x{8AF5}\x{8AF6}\x{8AF7}\x{8AF8}\x{8AF9}\x{8AFA}\x{8AFB}\x{8AFC}\x{8AFD}' .
          '\x{8AFE}\x{8AFF}\x{8B00}\x{8B01}\x{8B02}\x{8B03}\x{8B04}\x{8B05}\x{8B06}' .
          '\x{8B07}\x{8B08}\x{8B09}\x{8B0A}\x{8B0B}\x{8B0D}\x{8B0E}\x{8B0F}\x{8B10}' .
          '\x{8B11}\x{8B12}\x{8B13}\x{8B14}\x{8B15}\x{8B16}\x{8B17}\x{8B18}\x{8B19}' .
          '\x{8B1A}\x{8B1B}\x{8B1C}\x{8B1D}\x{8B1E}\x{8B1F}\x{8B20}\x{8B21}\x{8B22}' .
          '\x{8B23}\x{8B24}\x{8B25}\x{8B26}\x{8B27}\x{8B28}\x{8B2A}\x{8B2B}\x{8B2C}' .
          '\x{8B2D}\x{8B2E}\x{8B2F}\x{8B30}\x{8B31}\x{8B33}\x{8B34}\x{8B35}\x{8B36}' .
          '\x{8B37}\x{8B39}\x{8B3A}\x{8B3B}\x{8B3C}\x{8B3D}\x{8B3E}\x{8B40}\x{8B41}' .
          '\x{8B42}\x{8B43}\x{8B44}\x{8B45}\x{8B46}\x{8B47}\x{8B48}\x{8B49}\x{8B4A}' .
          '\x{8B4B}\x{8B4C}\x{8B4D}\x{8B4E}\x{8B4F}\x{8B50}\x{8B51}\x{8B52}\x{8B53}' .
          '\x{8B54}\x{8B55}\x{8B56}\x{8B57}\x{8B58}\x{8B59}\x{8B5A}\x{8B5B}\x{8B5C}' .
          '\x{8B5D}\x{8B5E}\x{8B5F}\x{8B60}\x{8B63}\x{8B64}\x{8B65}\x{8B66}\x{8B67}' .
          '\x{8B68}\x{8B6A}\x{8B6B}\x{8B6C}\x{8B6D}\x{8B6E}\x{8B6F}\x{8B70}\x{8B71}' .
          '\x{8B73}\x{8B74}\x{8B76}\x{8B77}\x{8B78}\x{8B79}\x{8B7A}\x{8B7B}\x{8B7D}' .
          '\x{8B7E}\x{8B7F}\x{8B80}\x{8B82}\x{8B83}\x{8B84}\x{8B85}\x{8B86}\x{8B88}' .
          '\x{8B89}\x{8B8A}\x{8B8B}\x{8B8C}\x{8B8E}\x{8B90}\x{8B91}\x{8B92}\x{8B93}' .
          '\x{8B94}\x{8B95}\x{8B96}\x{8B97}\x{8B98}\x{8B99}\x{8B9A}\x{8B9C}\x{8B9D}' .
          '\x{8B9E}\x{8B9F}\x{8BA0}\x{8BA1}\x{8BA2}\x{8BA3}\x{8BA4}\x{8BA5}\x{8BA6}' .
          '\x{8BA7}\x{8BA8}\x{8BA9}\x{8BAA}\x{8BAB}\x{8BAC}\x{8BAD}\x{8BAE}\x{8BAF}' .
          '\x{8BB0}\x{8BB1}\x{8BB2}\x{8BB3}\x{8BB4}\x{8BB5}\x{8BB6}\x{8BB7}\x{8BB8}' .
          '\x{8BB9}\x{8BBA}\x{8BBB}\x{8BBC}\x{8BBD}\x{8BBE}\x{8BBF}\x{8BC0}\x{8BC1}' .
          '\x{8BC2}\x{8BC3}\x{8BC4}\x{8BC5}\x{8BC6}\x{8BC7}\x{8BC8}\x{8BC9}\x{8BCA}' .
          '\x{8BCB}\x{8BCC}\x{8BCD}\x{8BCE}\x{8BCF}\x{8BD0}\x{8BD1}\x{8BD2}\x{8BD3}' .
          '\x{8BD4}\x{8BD5}\x{8BD6}\x{8BD7}\x{8BD8}\x{8BD9}\x{8BDA}\x{8BDB}\x{8BDC}' .
          '\x{8BDD}\x{8BDE}\x{8BDF}\x{8BE0}\x{8BE1}\x{8BE2}\x{8BE3}\x{8BE4}\x{8BE5}' .
          '\x{8BE6}\x{8BE7}\x{8BE8}\x{8BE9}\x{8BEA}\x{8BEB}\x{8BEC}\x{8BED}\x{8BEE}' .
          '\x{8BEF}\x{8BF0}\x{8BF1}\x{8BF2}\x{8BF3}\x{8BF4}\x{8BF5}\x{8BF6}\x{8BF7}' .
          '\x{8BF8}\x{8BF9}\x{8BFA}\x{8BFB}\x{8BFC}\x{8BFD}\x{8BFE}\x{8BFF}\x{8C00}' .
          '\x{8C01}\x{8C02}\x{8C03}\x{8C04}\x{8C05}\x{8C06}\x{8C07}\x{8C08}\x{8C09}' .
          '\x{8C0A}\x{8C0B}\x{8C0C}\x{8C0D}\x{8C0E}\x{8C0F}\x{8C10}\x{8C11}\x{8C12}' .
          '\x{8C13}\x{8C14}\x{8C15}\x{8C16}\x{8C17}\x{8C18}\x{8C19}\x{8C1A}\x{8C1B}' .
          '\x{8C1C}\x{8C1D}\x{8C1E}\x{8C1F}\x{8C20}\x{8C21}\x{8C22}\x{8C23}\x{8C24}' .
          '\x{8C25}\x{8C26}\x{8C27}\x{8C28}\x{8C29}\x{8C2A}\x{8C2B}\x{8C2C}\x{8C2D}' .
          '\x{8C2E}\x{8C2F}\x{8C30}\x{8C31}\x{8C32}\x{8C33}\x{8C34}\x{8C35}\x{8C36}' .
          '\x{8C37}\x{8C39}\x{8C3A}\x{8C3B}\x{8C3C}\x{8C3D}\x{8C3E}\x{8C3F}\x{8C41}' .
          '\x{8C42}\x{8C43}\x{8C45}\x{8C46}\x{8C47}\x{8C48}\x{8C49}\x{8C4A}\x{8C4B}' .
          '\x{8C4C}\x{8C4D}\x{8C4E}\x{8C4F}\x{8C50}\x{8C54}\x{8C55}\x{8C56}\x{8C57}' .
          '\x{8C59}\x{8C5A}\x{8C5B}\x{8C5C}\x{8C5D}\x{8C5E}\x{8C5F}\x{8C60}\x{8C61}' .
          '\x{8C62}\x{8C63}\x{8C64}\x{8C65}\x{8C66}\x{8C67}\x{8C68}\x{8C69}\x{8C6A}' .
          '\x{8C6B}\x{8C6C}\x{8C6D}\x{8C6E}\x{8C6F}\x{8C70}\x{8C71}\x{8C72}\x{8C73}' .
          '\x{8C75}\x{8C76}\x{8C77}\x{8C78}\x{8C79}\x{8C7A}\x{8C7B}\x{8C7D}\x{8C7E}' .
          '\x{8C80}\x{8C81}\x{8C82}\x{8C84}\x{8C85}\x{8C86}\x{8C88}\x{8C89}\x{8C8A}' .
          '\x{8C8C}\x{8C8D}\x{8C8F}\x{8C90}\x{8C91}\x{8C92}\x{8C93}\x{8C94}\x{8C95}' .
          '\x{8C96}\x{8C97}\x{8C98}\x{8C99}\x{8C9A}\x{8C9C}\x{8C9D}\x{8C9E}\x{8C9F}' .
          '\x{8CA0}\x{8CA1}\x{8CA2}\x{8CA3}\x{8CA4}\x{8CA5}\x{8CA7}\x{8CA8}\x{8CA9}' .
          '\x{8CAA}\x{8CAB}\x{8CAC}\x{8CAD}\x{8CAE}\x{8CAF}\x{8CB0}\x{8CB1}\x{8CB2}' .
          '\x{8CB3}\x{8CB4}\x{8CB5}\x{8CB6}\x{8CB7}\x{8CB8}\x{8CB9}\x{8CBA}\x{8CBB}' .
          '\x{8CBC}\x{8CBD}\x{8CBE}\x{8CBF}\x{8CC0}\x{8CC1}\x{8CC2}\x{8CC3}\x{8CC4}' .
          '\x{8CC5}\x{8CC6}\x{8CC7}\x{8CC8}\x{8CC9}\x{8CCA}\x{8CCC}\x{8CCE}\x{8CCF}' .
          '\x{8CD0}\x{8CD1}\x{8CD2}\x{8CD3}\x{8CD4}\x{8CD5}\x{8CD7}\x{8CD9}\x{8CDA}' .
          '\x{8CDB}\x{8CDC}\x{8CDD}\x{8CDE}\x{8CDF}\x{8CE0}\x{8CE1}\x{8CE2}\x{8CE3}' .
          '\x{8CE4}\x{8CE5}\x{8CE6}\x{8CE7}\x{8CE8}\x{8CEA}\x{8CEB}\x{8CEC}\x{8CED}' .
          '\x{8CEE}\x{8CEF}\x{8CF0}\x{8CF1}\x{8CF2}\x{8CF3}\x{8CF4}\x{8CF5}\x{8CF6}' .
          '\x{8CF8}\x{8CF9}\x{8CFA}\x{8CFB}\x{8CFC}\x{8CFD}\x{8CFE}\x{8CFF}\x{8D00}' .
          '\x{8D02}\x{8D03}\x{8D04}\x{8D05}\x{8D06}\x{8D07}\x{8D08}\x{8D09}\x{8D0A}' .
          '\x{8D0B}\x{8D0C}\x{8D0D}\x{8D0E}\x{8D0F}\x{8D10}\x{8D13}\x{8D14}\x{8D15}' .
          '\x{8D16}\x{8D17}\x{8D18}\x{8D19}\x{8D1A}\x{8D1B}\x{8D1C}\x{8D1D}\x{8D1E}' .
          '\x{8D1F}\x{8D20}\x{8D21}\x{8D22}\x{8D23}\x{8D24}\x{8D25}\x{8D26}\x{8D27}' .
          '\x{8D28}\x{8D29}\x{8D2A}\x{8D2B}\x{8D2C}\x{8D2D}\x{8D2E}\x{8D2F}\x{8D30}' .
          '\x{8D31}\x{8D32}\x{8D33}\x{8D34}\x{8D35}\x{8D36}\x{8D37}\x{8D38}\x{8D39}' .
          '\x{8D3A}\x{8D3B}\x{8D3C}\x{8D3D}\x{8D3E}\x{8D3F}\x{8D40}\x{8D41}\x{8D42}' .
          '\x{8D43}\x{8D44}\x{8D45}\x{8D46}\x{8D47}\x{8D48}\x{8D49}\x{8D4A}\x{8D4B}' .
          '\x{8D4C}\x{8D4D}\x{8D4E}\x{8D4F}\x{8D50}\x{8D51}\x{8D52}\x{8D53}\x{8D54}' .
          '\x{8D55}\x{8D56}\x{8D57}\x{8D58}\x{8D59}\x{8D5A}\x{8D5B}\x{8D5C}\x{8D5D}' .
          '\x{8D5E}\x{8D5F}\x{8D60}\x{8D61}\x{8D62}\x{8D63}\x{8D64}\x{8D65}\x{8D66}' .
          '\x{8D67}\x{8D68}\x{8D69}\x{8D6A}\x{8D6B}\x{8D6C}\x{8D6D}\x{8D6E}\x{8D6F}' .
          '\x{8D70}\x{8D71}\x{8D72}\x{8D73}\x{8D74}\x{8D75}\x{8D76}\x{8D77}\x{8D78}' .
          '\x{8D79}\x{8D7A}\x{8D7B}\x{8D7D}\x{8D7E}\x{8D7F}\x{8D80}\x{8D81}\x{8D82}' .
          '\x{8D83}\x{8D84}\x{8D85}\x{8D86}\x{8D87}\x{8D88}\x{8D89}\x{8D8A}\x{8D8B}' .
          '\x{8D8C}\x{8D8D}\x{8D8E}\x{8D8F}\x{8D90}\x{8D91}\x{8D92}\x{8D93}\x{8D94}' .
          '\x{8D95}\x{8D96}\x{8D97}\x{8D98}\x{8D99}\x{8D9A}\x{8D9B}\x{8D9C}\x{8D9D}' .
          '\x{8D9E}\x{8D9F}\x{8DA0}\x{8DA1}\x{8DA2}\x{8DA3}\x{8DA4}\x{8DA5}\x{8DA7}' .
          '\x{8DA8}\x{8DA9}\x{8DAA}\x{8DAB}\x{8DAC}\x{8DAD}\x{8DAE}\x{8DAF}\x{8DB0}' .
          '\x{8DB1}\x{8DB2}\x{8DB3}\x{8DB4}\x{8DB5}\x{8DB6}\x{8DB7}\x{8DB8}\x{8DB9}' .
          '\x{8DBA}\x{8DBB}\x{8DBC}\x{8DBD}\x{8DBE}\x{8DBF}\x{8DC1}\x{8DC2}\x{8DC3}' .
          '\x{8DC4}\x{8DC5}\x{8DC6}\x{8DC7}\x{8DC8}\x{8DC9}\x{8DCA}\x{8DCB}\x{8DCC}' .
          '\x{8DCD}\x{8DCE}\x{8DCF}\x{8DD0}\x{8DD1}\x{8DD2}\x{8DD3}\x{8DD4}\x{8DD5}' .
          '\x{8DD6}\x{8DD7}\x{8DD8}\x{8DD9}\x{8DDA}\x{8DDB}\x{8DDC}\x{8DDD}\x{8DDE}' .
          '\x{8DDF}\x{8DE0}\x{8DE1}\x{8DE2}\x{8DE3}\x{8DE4}\x{8DE6}\x{8DE7}\x{8DE8}' .
          '\x{8DE9}\x{8DEA}\x{8DEB}\x{8DEC}\x{8DED}\x{8DEE}\x{8DEF}\x{8DF0}\x{8DF1}' .
          '\x{8DF2}\x{8DF3}\x{8DF4}\x{8DF5}\x{8DF6}\x{8DF7}\x{8DF8}\x{8DF9}\x{8DFA}' .
          '\x{8DFB}\x{8DFC}\x{8DFD}\x{8DFE}\x{8DFF}\x{8E00}\x{8E02}\x{8E03}\x{8E04}' .
          '\x{8E05}\x{8E06}\x{8E07}\x{8E08}\x{8E09}\x{8E0A}\x{8E0C}\x{8E0D}\x{8E0E}' .
          '\x{8E0F}\x{8E10}\x{8E11}\x{8E12}\x{8E13}\x{8E14}\x{8E15}\x{8E16}\x{8E17}' .
          '\x{8E18}\x{8E19}\x{8E1A}\x{8E1B}\x{8E1C}\x{8E1D}\x{8E1E}\x{8E1F}\x{8E20}' .
          '\x{8E21}\x{8E22}\x{8E23}\x{8E24}\x{8E25}\x{8E26}\x{8E27}\x{8E28}\x{8E29}' .
          '\x{8E2A}\x{8E2B}\x{8E2C}\x{8E2D}\x{8E2E}\x{8E2F}\x{8E30}\x{8E31}\x{8E33}' .
          '\x{8E34}\x{8E35}\x{8E36}\x{8E37}\x{8E38}\x{8E39}\x{8E3A}\x{8E3B}\x{8E3C}' .
          '\x{8E3D}\x{8E3E}\x{8E3F}\x{8E40}\x{8E41}\x{8E42}\x{8E43}\x{8E44}\x{8E45}' .
          '\x{8E47}\x{8E48}\x{8E49}\x{8E4A}\x{8E4B}\x{8E4C}\x{8E4D}\x{8E4E}\x{8E50}' .
          '\x{8E51}\x{8E52}\x{8E53}\x{8E54}\x{8E55}\x{8E56}\x{8E57}\x{8E58}\x{8E59}' .
          '\x{8E5A}\x{8E5B}\x{8E5C}\x{8E5D}\x{8E5E}\x{8E5F}\x{8E60}\x{8E61}\x{8E62}' .
          '\x{8E63}\x{8E64}\x{8E65}\x{8E66}\x{8E67}\x{8E68}\x{8E69}\x{8E6A}\x{8E6B}' .
          '\x{8E6C}\x{8E6D}\x{8E6F}\x{8E70}\x{8E71}\x{8E72}\x{8E73}\x{8E74}\x{8E76}' .
          '\x{8E78}\x{8E7A}\x{8E7B}\x{8E7C}\x{8E7D}\x{8E7E}\x{8E7F}\x{8E80}\x{8E81}' .
          '\x{8E82}\x{8E83}\x{8E84}\x{8E85}\x{8E86}\x{8E87}\x{8E88}\x{8E89}\x{8E8A}' .
          '\x{8E8B}\x{8E8C}\x{8E8D}\x{8E8E}\x{8E8F}\x{8E90}\x{8E91}\x{8E92}\x{8E93}' .
          '\x{8E94}\x{8E95}\x{8E96}\x{8E97}\x{8E98}\x{8E9A}\x{8E9C}\x{8E9D}\x{8E9E}' .
          '\x{8E9F}\x{8EA0}\x{8EA1}\x{8EA3}\x{8EA4}\x{8EA5}\x{8EA6}\x{8EA7}\x{8EA8}' .
          '\x{8EA9}\x{8EAA}\x{8EAB}\x{8EAC}\x{8EAD}\x{8EAE}\x{8EAF}\x{8EB0}\x{8EB1}' .
          '\x{8EB2}\x{8EB4}\x{8EB5}\x{8EB8}\x{8EB9}\x{8EBA}\x{8EBB}\x{8EBC}\x{8EBD}' .
          '\x{8EBE}\x{8EBF}\x{8EC0}\x{8EC2}\x{8EC3}\x{8EC5}\x{8EC6}\x{8EC7}\x{8EC8}' .
          '\x{8EC9}\x{8ECA}\x{8ECB}\x{8ECC}\x{8ECD}\x{8ECE}\x{8ECF}\x{8ED0}\x{8ED1}' .
          '\x{8ED2}\x{8ED3}\x{8ED4}\x{8ED5}\x{8ED6}\x{8ED7}\x{8ED8}\x{8EDA}\x{8EDB}' .
          '\x{8EDC}\x{8EDD}\x{8EDE}\x{8EDF}\x{8EE0}\x{8EE1}\x{8EE4}\x{8EE5}\x{8EE6}' .
          '\x{8EE7}\x{8EE8}\x{8EE9}\x{8EEA}\x{8EEB}\x{8EEC}\x{8EED}\x{8EEE}\x{8EEF}' .
          '\x{8EF1}\x{8EF2}\x{8EF3}\x{8EF4}\x{8EF5}\x{8EF6}\x{8EF7}\x{8EF8}\x{8EF9}' .
          '\x{8EFA}\x{8EFB}\x{8EFC}\x{8EFD}\x{8EFE}\x{8EFF}\x{8F00}\x{8F01}\x{8F02}' .
          '\x{8F03}\x{8F04}\x{8F05}\x{8F06}\x{8F07}\x{8F08}\x{8F09}\x{8F0A}\x{8F0B}' .
          '\x{8F0D}\x{8F0E}\x{8F10}\x{8F11}\x{8F12}\x{8F13}\x{8F14}\x{8F15}\x{8F16}' .
          '\x{8F17}\x{8F18}\x{8F1A}\x{8F1B}\x{8F1C}\x{8F1D}\x{8F1E}\x{8F1F}\x{8F20}' .
          '\x{8F21}\x{8F22}\x{8F23}\x{8F24}\x{8F25}\x{8F26}\x{8F27}\x{8F28}\x{8F29}' .
          '\x{8F2A}\x{8F2B}\x{8F2C}\x{8F2E}\x{8F2F}\x{8F30}\x{8F31}\x{8F32}\x{8F33}' .
          '\x{8F34}\x{8F35}\x{8F36}\x{8F37}\x{8F38}\x{8F39}\x{8F3B}\x{8F3C}\x{8F3D}' .
          '\x{8F3E}\x{8F3F}\x{8F40}\x{8F42}\x{8F43}\x{8F44}\x{8F45}\x{8F46}\x{8F47}' .
          '\x{8F48}\x{8F49}\x{8F4A}\x{8F4B}\x{8F4C}\x{8F4D}\x{8F4E}\x{8F4F}\x{8F50}' .
          '\x{8F51}\x{8F52}\x{8F53}\x{8F54}\x{8F55}\x{8F56}\x{8F57}\x{8F58}\x{8F59}' .
          '\x{8F5A}\x{8F5B}\x{8F5D}\x{8F5E}\x{8F5F}\x{8F60}\x{8F61}\x{8F62}\x{8F63}' .
          '\x{8F64}\x{8F65}\x{8F66}\x{8F67}\x{8F68}\x{8F69}\x{8F6A}\x{8F6B}\x{8F6C}' .
          '\x{8F6D}\x{8F6E}\x{8F6F}\x{8F70}\x{8F71}\x{8F72}\x{8F73}\x{8F74}\x{8F75}' .
          '\x{8F76}\x{8F77}\x{8F78}\x{8F79}\x{8F7A}\x{8F7B}\x{8F7C}\x{8F7D}\x{8F7E}' .
          '\x{8F7F}\x{8F80}\x{8F81}\x{8F82}\x{8F83}\x{8F84}\x{8F85}\x{8F86}\x{8F87}' .
          '\x{8F88}\x{8F89}\x{8F8A}\x{8F8B}\x{8F8C}\x{8F8D}\x{8F8E}\x{8F8F}\x{8F90}' .
          '\x{8F91}\x{8F92}\x{8F93}\x{8F94}\x{8F95}\x{8F96}\x{8F97}\x{8F98}\x{8F99}' .
          '\x{8F9A}\x{8F9B}\x{8F9C}\x{8F9E}\x{8F9F}\x{8FA0}\x{8FA1}\x{8FA2}\x{8FA3}' .
          '\x{8FA5}\x{8FA6}\x{8FA7}\x{8FA8}\x{8FA9}\x{8FAA}\x{8FAB}\x{8FAC}\x{8FAD}' .
          '\x{8FAE}\x{8FAF}\x{8FB0}\x{8FB1}\x{8FB2}\x{8FB4}\x{8FB5}\x{8FB6}\x{8FB7}' .
          '\x{8FB8}\x{8FB9}\x{8FBB}\x{8FBC}\x{8FBD}\x{8FBE}\x{8FBF}\x{8FC0}\x{8FC1}' .
          '\x{8FC2}\x{8FC4}\x{8FC5}\x{8FC6}\x{8FC7}\x{8FC8}\x{8FC9}\x{8FCB}\x{8FCC}' .
          '\x{8FCD}\x{8FCE}\x{8FCF}\x{8FD0}\x{8FD1}\x{8FD2}\x{8FD3}\x{8FD4}\x{8FD5}' .
          '\x{8FD6}\x{8FD7}\x{8FD8}\x{8FD9}\x{8FDA}\x{8FDB}\x{8FDC}\x{8FDD}\x{8FDE}' .
          '\x{8FDF}\x{8FE0}\x{8FE1}\x{8FE2}\x{8FE3}\x{8FE4}\x{8FE5}\x{8FE6}\x{8FE8}' .
          '\x{8FE9}\x{8FEA}\x{8FEB}\x{8FEC}\x{8FED}\x{8FEE}\x{8FEF}\x{8FF0}\x{8FF1}' .
          '\x{8FF2}\x{8FF3}\x{8FF4}\x{8FF5}\x{8FF6}\x{8FF7}\x{8FF8}\x{8FF9}\x{8FFA}' .
          '\x{8FFB}\x{8FFC}\x{8FFD}\x{8FFE}\x{8FFF}\x{9000}\x{9001}\x{9002}\x{9003}' .
          '\x{9004}\x{9005}\x{9006}\x{9007}\x{9008}\x{9009}\x{900A}\x{900B}\x{900C}' .
          '\x{900D}\x{900F}\x{9010}\x{9011}\x{9012}\x{9013}\x{9014}\x{9015}\x{9016}' .
          '\x{9017}\x{9018}\x{9019}\x{901A}\x{901B}\x{901C}\x{901D}\x{901E}\x{901F}' .
          '\x{9020}\x{9021}\x{9022}\x{9023}\x{9024}\x{9025}\x{9026}\x{9027}\x{9028}' .
          '\x{9029}\x{902B}\x{902D}\x{902E}\x{902F}\x{9030}\x{9031}\x{9032}\x{9033}' .
          '\x{9034}\x{9035}\x{9036}\x{9038}\x{903A}\x{903B}\x{903C}\x{903D}\x{903E}' .
          '\x{903F}\x{9041}\x{9042}\x{9043}\x{9044}\x{9045}\x{9047}\x{9048}\x{9049}' .
          '\x{904A}\x{904B}\x{904C}\x{904D}\x{904E}\x{904F}\x{9050}\x{9051}\x{9052}' .
          '\x{9053}\x{9054}\x{9055}\x{9056}\x{9057}\x{9058}\x{9059}\x{905A}\x{905B}' .
          '\x{905C}\x{905D}\x{905E}\x{905F}\x{9060}\x{9061}\x{9062}\x{9063}\x{9064}' .
          '\x{9065}\x{9066}\x{9067}\x{9068}\x{9069}\x{906A}\x{906B}\x{906C}\x{906D}' .
          '\x{906E}\x{906F}\x{9070}\x{9071}\x{9072}\x{9073}\x{9074}\x{9075}\x{9076}' .
          '\x{9077}\x{9078}\x{9079}\x{907A}\x{907B}\x{907C}\x{907D}\x{907E}\x{907F}' .
          '\x{9080}\x{9081}\x{9082}\x{9083}\x{9084}\x{9085}\x{9086}\x{9087}\x{9088}' .
          '\x{9089}\x{908A}\x{908B}\x{908C}\x{908D}\x{908E}\x{908F}\x{9090}\x{9091}' .
          '\x{9092}\x{9093}\x{9094}\x{9095}\x{9096}\x{9097}\x{9098}\x{9099}\x{909A}' .
          '\x{909B}\x{909C}\x{909D}\x{909E}\x{909F}\x{90A0}\x{90A1}\x{90A2}\x{90A3}' .
          '\x{90A4}\x{90A5}\x{90A6}\x{90A7}\x{90A8}\x{90A9}\x{90AA}\x{90AC}\x{90AD}' .
          '\x{90AE}\x{90AF}\x{90B0}\x{90B1}\x{90B2}\x{90B3}\x{90B4}\x{90B5}\x{90B6}' .
          '\x{90B7}\x{90B8}\x{90B9}\x{90BA}\x{90BB}\x{90BC}\x{90BD}\x{90BE}\x{90BF}' .
          '\x{90C0}\x{90C1}\x{90C2}\x{90C3}\x{90C4}\x{90C5}\x{90C6}\x{90C7}\x{90C8}' .
          '\x{90C9}\x{90CA}\x{90CB}\x{90CE}\x{90CF}\x{90D0}\x{90D1}\x{90D3}\x{90D4}' .
          '\x{90D5}\x{90D6}\x{90D7}\x{90D8}\x{90D9}\x{90DA}\x{90DB}\x{90DC}\x{90DD}' .
          '\x{90DE}\x{90DF}\x{90E0}\x{90E1}\x{90E2}\x{90E3}\x{90E4}\x{90E5}\x{90E6}' .
          '\x{90E7}\x{90E8}\x{90E9}\x{90EA}\x{90EB}\x{90EC}\x{90ED}\x{90EE}\x{90EF}' .
          '\x{90F0}\x{90F1}\x{90F2}\x{90F3}\x{90F4}\x{90F5}\x{90F7}\x{90F8}\x{90F9}' .
          '\x{90FA}\x{90FB}\x{90FC}\x{90FD}\x{90FE}\x{90FF}\x{9100}\x{9101}\x{9102}' .
          '\x{9103}\x{9104}\x{9105}\x{9106}\x{9107}\x{9108}\x{9109}\x{910B}\x{910C}' .
          '\x{910D}\x{910E}\x{910F}\x{9110}\x{9111}\x{9112}\x{9113}\x{9114}\x{9115}' .
          '\x{9116}\x{9117}\x{9118}\x{9119}\x{911A}\x{911B}\x{911C}\x{911D}\x{911E}' .
          '\x{911F}\x{9120}\x{9121}\x{9122}\x{9123}\x{9124}\x{9125}\x{9126}\x{9127}' .
          '\x{9128}\x{9129}\x{912A}\x{912B}\x{912C}\x{912D}\x{912E}\x{912F}\x{9130}' .
          '\x{9131}\x{9132}\x{9133}\x{9134}\x{9135}\x{9136}\x{9137}\x{9138}\x{9139}' .
          '\x{913A}\x{913B}\x{913E}\x{913F}\x{9140}\x{9141}\x{9142}\x{9143}\x{9144}' .
          '\x{9145}\x{9146}\x{9147}\x{9148}\x{9149}\x{914A}\x{914B}\x{914C}\x{914D}' .
          '\x{914E}\x{914F}\x{9150}\x{9151}\x{9152}\x{9153}\x{9154}\x{9155}\x{9156}' .
          '\x{9157}\x{9158}\x{915A}\x{915B}\x{915C}\x{915D}\x{915E}\x{915F}\x{9160}' .
          '\x{9161}\x{9162}\x{9163}\x{9164}\x{9165}\x{9166}\x{9167}\x{9168}\x{9169}' .
          '\x{916A}\x{916B}\x{916C}\x{916D}\x{916E}\x{916F}\x{9170}\x{9171}\x{9172}' .
          '\x{9173}\x{9174}\x{9175}\x{9176}\x{9177}\x{9178}\x{9179}\x{917A}\x{917C}' .
          '\x{917D}\x{917E}\x{917F}\x{9180}\x{9181}\x{9182}\x{9183}\x{9184}\x{9185}' .
          '\x{9186}\x{9187}\x{9188}\x{9189}\x{918A}\x{918B}\x{918C}\x{918D}\x{918E}' .
          '\x{918F}\x{9190}\x{9191}\x{9192}\x{9193}\x{9194}\x{9196}\x{9199}\x{919A}' .
          '\x{919B}\x{919C}\x{919D}\x{919E}\x{919F}\x{91A0}\x{91A1}\x{91A2}\x{91A3}' .
          '\x{91A5}\x{91A6}\x{91A7}\x{91A8}\x{91AA}\x{91AB}\x{91AC}\x{91AD}\x{91AE}' .
          '\x{91AF}\x{91B0}\x{91B1}\x{91B2}\x{91B3}\x{91B4}\x{91B5}\x{91B6}\x{91B7}' .
          '\x{91B9}\x{91BA}\x{91BB}\x{91BC}\x{91BD}\x{91BE}\x{91C0}\x{91C1}\x{91C2}' .
          '\x{91C3}\x{91C5}\x{91C6}\x{91C7}\x{91C9}\x{91CA}\x{91CB}\x{91CC}\x{91CD}' .
          '\x{91CE}\x{91CF}\x{91D0}\x{91D1}\x{91D2}\x{91D3}\x{91D4}\x{91D5}\x{91D7}' .
          '\x{91D8}\x{91D9}\x{91DA}\x{91DB}\x{91DC}\x{91DD}\x{91DE}\x{91DF}\x{91E2}' .
          '\x{91E3}\x{91E4}\x{91E5}\x{91E6}\x{91E7}\x{91E8}\x{91E9}\x{91EA}\x{91EB}' .
          '\x{91EC}\x{91ED}\x{91EE}\x{91F0}\x{91F1}\x{91F2}\x{91F3}\x{91F4}\x{91F5}' .
          '\x{91F7}\x{91F8}\x{91F9}\x{91FA}\x{91FB}\x{91FD}\x{91FE}\x{91FF}\x{9200}' .
          '\x{9201}\x{9202}\x{9203}\x{9204}\x{9205}\x{9206}\x{9207}\x{9208}\x{9209}' .
          '\x{920A}\x{920B}\x{920C}\x{920D}\x{920E}\x{920F}\x{9210}\x{9211}\x{9212}' .
          '\x{9214}\x{9215}\x{9216}\x{9217}\x{9218}\x{9219}\x{921A}\x{921B}\x{921C}' .
          '\x{921D}\x{921E}\x{9220}\x{9221}\x{9223}\x{9224}\x{9225}\x{9226}\x{9227}' .
          '\x{9228}\x{9229}\x{922A}\x{922B}\x{922D}\x{922E}\x{922F}\x{9230}\x{9231}' .
          '\x{9232}\x{9233}\x{9234}\x{9235}\x{9236}\x{9237}\x{9238}\x{9239}\x{923A}' .
          '\x{923B}\x{923C}\x{923D}\x{923E}\x{923F}\x{9240}\x{9241}\x{9242}\x{9245}' .
          '\x{9246}\x{9247}\x{9248}\x{9249}\x{924A}\x{924B}\x{924C}\x{924D}\x{924E}' .
          '\x{924F}\x{9250}\x{9251}\x{9252}\x{9253}\x{9254}\x{9255}\x{9256}\x{9257}' .
          '\x{9258}\x{9259}\x{925A}\x{925B}\x{925C}\x{925D}\x{925E}\x{925F}\x{9260}' .
          '\x{9261}\x{9262}\x{9263}\x{9264}\x{9265}\x{9266}\x{9267}\x{9268}\x{926B}' .
          '\x{926C}\x{926D}\x{926E}\x{926F}\x{9270}\x{9272}\x{9273}\x{9274}\x{9275}' .
          '\x{9276}\x{9277}\x{9278}\x{9279}\x{927A}\x{927B}\x{927C}\x{927D}\x{927E}' .
          '\x{927F}\x{9280}\x{9282}\x{9283}\x{9285}\x{9286}\x{9287}\x{9288}\x{9289}' .
          '\x{928A}\x{928B}\x{928C}\x{928D}\x{928E}\x{928F}\x{9290}\x{9291}\x{9292}' .
          '\x{9293}\x{9294}\x{9295}\x{9296}\x{9297}\x{9298}\x{9299}\x{929A}\x{929B}' .
          '\x{929C}\x{929D}\x{929F}\x{92A0}\x{92A1}\x{92A2}\x{92A3}\x{92A4}\x{92A5}' .
          '\x{92A6}\x{92A7}\x{92A8}\x{92A9}\x{92AA}\x{92AB}\x{92AC}\x{92AD}\x{92AE}' .
          '\x{92AF}\x{92B0}\x{92B1}\x{92B2}\x{92B3}\x{92B4}\x{92B5}\x{92B6}\x{92B7}' .
          '\x{92B8}\x{92B9}\x{92BA}\x{92BB}\x{92BC}\x{92BE}\x{92BF}\x{92C0}\x{92C1}' .
          '\x{92C2}\x{92C3}\x{92C4}\x{92C5}\x{92C6}\x{92C7}\x{92C8}\x{92C9}\x{92CA}' .
          '\x{92CB}\x{92CC}\x{92CD}\x{92CE}\x{92CF}\x{92D0}\x{92D1}\x{92D2}\x{92D3}' .
          '\x{92D5}\x{92D6}\x{92D7}\x{92D8}\x{92D9}\x{92DA}\x{92DC}\x{92DD}\x{92DE}' .
          '\x{92DF}\x{92E0}\x{92E1}\x{92E3}\x{92E4}\x{92E5}\x{92E6}\x{92E7}\x{92E8}' .
          '\x{92E9}\x{92EA}\x{92EB}\x{92EC}\x{92ED}\x{92EE}\x{92EF}\x{92F0}\x{92F1}' .
          '\x{92F2}\x{92F3}\x{92F4}\x{92F5}\x{92F6}\x{92F7}\x{92F8}\x{92F9}\x{92FA}' .
          '\x{92FB}\x{92FC}\x{92FD}\x{92FE}\x{92FF}\x{9300}\x{9301}\x{9302}\x{9303}' .
          '\x{9304}\x{9305}\x{9306}\x{9307}\x{9308}\x{9309}\x{930A}\x{930B}\x{930C}' .
          '\x{930D}\x{930E}\x{930F}\x{9310}\x{9311}\x{9312}\x{9313}\x{9314}\x{9315}' .
          '\x{9316}\x{9317}\x{9318}\x{9319}\x{931A}\x{931B}\x{931D}\x{931E}\x{931F}' .
          '\x{9320}\x{9321}\x{9322}\x{9323}\x{9324}\x{9325}\x{9326}\x{9327}\x{9328}' .
          '\x{9329}\x{932A}\x{932B}\x{932D}\x{932E}\x{932F}\x{9332}\x{9333}\x{9334}' .
          '\x{9335}\x{9336}\x{9337}\x{9338}\x{9339}\x{933A}\x{933B}\x{933C}\x{933D}' .
          '\x{933E}\x{933F}\x{9340}\x{9341}\x{9342}\x{9343}\x{9344}\x{9345}\x{9346}' .
          '\x{9347}\x{9348}\x{9349}\x{934A}\x{934B}\x{934C}\x{934D}\x{934E}\x{934F}' .
          '\x{9350}\x{9351}\x{9352}\x{9353}\x{9354}\x{9355}\x{9356}\x{9357}\x{9358}' .
          '\x{9359}\x{935A}\x{935B}\x{935C}\x{935D}\x{935E}\x{935F}\x{9360}\x{9361}' .
          '\x{9363}\x{9364}\x{9365}\x{9366}\x{9367}\x{9369}\x{936A}\x{936C}\x{936D}' .
          '\x{936E}\x{9370}\x{9371}\x{9372}\x{9374}\x{9375}\x{9376}\x{9377}\x{9379}' .
          '\x{937A}\x{937B}\x{937C}\x{937D}\x{937E}\x{9380}\x{9382}\x{9383}\x{9384}' .
          '\x{9385}\x{9386}\x{9387}\x{9388}\x{9389}\x{938A}\x{938C}\x{938D}\x{938E}' .
          '\x{938F}\x{9390}\x{9391}\x{9392}\x{9393}\x{9394}\x{9395}\x{9396}\x{9397}' .
          '\x{9398}\x{9399}\x{939A}\x{939B}\x{939D}\x{939E}\x{939F}\x{93A1}\x{93A2}' .
          '\x{93A3}\x{93A4}\x{93A5}\x{93A6}\x{93A7}\x{93A8}\x{93A9}\x{93AA}\x{93AC}' .
          '\x{93AD}\x{93AE}\x{93AF}\x{93B0}\x{93B1}\x{93B2}\x{93B3}\x{93B4}\x{93B5}' .
          '\x{93B6}\x{93B7}\x{93B8}\x{93B9}\x{93BA}\x{93BC}\x{93BD}\x{93BE}\x{93BF}' .
          '\x{93C0}\x{93C1}\x{93C2}\x{93C3}\x{93C4}\x{93C5}\x{93C6}\x{93C7}\x{93C8}' .
          '\x{93C9}\x{93CA}\x{93CB}\x{93CC}\x{93CD}\x{93CE}\x{93CF}\x{93D0}\x{93D1}' .
          '\x{93D2}\x{93D3}\x{93D4}\x{93D5}\x{93D6}\x{93D7}\x{93D8}\x{93D9}\x{93DA}' .
          '\x{93DB}\x{93DC}\x{93DD}\x{93DE}\x{93DF}\x{93E1}\x{93E2}\x{93E3}\x{93E4}' .
          '\x{93E6}\x{93E7}\x{93E8}\x{93E9}\x{93EA}\x{93EB}\x{93EC}\x{93ED}\x{93EE}' .
          '\x{93EF}\x{93F0}\x{93F1}\x{93F2}\x{93F4}\x{93F5}\x{93F6}\x{93F7}\x{93F8}' .
          '\x{93F9}\x{93FA}\x{93FB}\x{93FC}\x{93FD}\x{93FE}\x{93FF}\x{9400}\x{9401}' .
          '\x{9403}\x{9404}\x{9405}\x{9406}\x{9407}\x{9408}\x{9409}\x{940A}\x{940B}' .
          '\x{940C}\x{940D}\x{940E}\x{940F}\x{9410}\x{9411}\x{9412}\x{9413}\x{9414}' .
          '\x{9415}\x{9416}\x{9418}\x{9419}\x{941B}\x{941D}\x{9420}\x{9422}\x{9423}' .
          '\x{9425}\x{9426}\x{9427}\x{9428}\x{9429}\x{942A}\x{942B}\x{942C}\x{942D}' .
          '\x{942E}\x{942F}\x{9430}\x{9431}\x{9432}\x{9433}\x{9434}\x{9435}\x{9436}' .
          '\x{9437}\x{9438}\x{9439}\x{943A}\x{943B}\x{943C}\x{943D}\x{943E}\x{943F}' .
          '\x{9440}\x{9441}\x{9442}\x{9444}\x{9445}\x{9446}\x{9447}\x{9448}\x{9449}' .
          '\x{944A}\x{944B}\x{944C}\x{944D}\x{944F}\x{9450}\x{9451}\x{9452}\x{9453}' .
          '\x{9454}\x{9455}\x{9456}\x{9457}\x{9458}\x{9459}\x{945B}\x{945C}\x{945D}' .
          '\x{945E}\x{945F}\x{9460}\x{9461}\x{9462}\x{9463}\x{9464}\x{9465}\x{9466}' .
          '\x{9467}\x{9468}\x{9469}\x{946A}\x{946B}\x{946D}\x{946E}\x{946F}\x{9470}' .
          '\x{9471}\x{9472}\x{9473}\x{9474}\x{9475}\x{9476}\x{9477}\x{9478}\x{9479}' .
          '\x{947A}\x{947C}\x{947D}\x{947E}\x{947F}\x{9480}\x{9481}\x{9482}\x{9483}' .
          '\x{9484}\x{9485}\x{9486}\x{9487}\x{9488}\x{9489}\x{948A}\x{948B}\x{948C}' .
          '\x{948D}\x{948E}\x{948F}\x{9490}\x{9491}\x{9492}\x{9493}\x{9494}\x{9495}' .
          '\x{9496}\x{9497}\x{9498}\x{9499}\x{949A}\x{949B}\x{949C}\x{949D}\x{949E}' .
          '\x{949F}\x{94A0}\x{94A1}\x{94A2}\x{94A3}\x{94A4}\x{94A5}\x{94A6}\x{94A7}' .
          '\x{94A8}\x{94A9}\x{94AA}\x{94AB}\x{94AC}\x{94AD}\x{94AE}\x{94AF}\x{94B0}' .
          '\x{94B1}\x{94B2}\x{94B3}\x{94B4}\x{94B5}\x{94B6}\x{94B7}\x{94B8}\x{94B9}' .
          '\x{94BA}\x{94BB}\x{94BC}\x{94BD}\x{94BE}\x{94BF}\x{94C0}\x{94C1}\x{94C2}' .
          '\x{94C3}\x{94C4}\x{94C5}\x{94C6}\x{94C7}\x{94C8}\x{94C9}\x{94CA}\x{94CB}' .
          '\x{94CC}\x{94CD}\x{94CE}\x{94CF}\x{94D0}\x{94D1}\x{94D2}\x{94D3}\x{94D4}' .
          '\x{94D5}\x{94D6}\x{94D7}\x{94D8}\x{94D9}\x{94DA}\x{94DB}\x{94DC}\x{94DD}' .
          '\x{94DE}\x{94DF}\x{94E0}\x{94E1}\x{94E2}\x{94E3}\x{94E4}\x{94E5}\x{94E6}' .
          '\x{94E7}\x{94E8}\x{94E9}\x{94EA}\x{94EB}\x{94EC}\x{94ED}\x{94EE}\x{94EF}' .
          '\x{94F0}\x{94F1}\x{94F2}\x{94F3}\x{94F4}\x{94F5}\x{94F6}\x{94F7}\x{94F8}' .
          '\x{94F9}\x{94FA}\x{94FB}\x{94FC}\x{94FD}\x{94FE}\x{94FF}\x{9500}\x{9501}' .
          '\x{9502}\x{9503}\x{9504}\x{9505}\x{9506}\x{9507}\x{9508}\x{9509}\x{950A}' .
          '\x{950B}\x{950C}\x{950D}\x{950E}\x{950F}\x{9510}\x{9511}\x{9512}\x{9513}' .
          '\x{9514}\x{9515}\x{9516}\x{9517}\x{9518}\x{9519}\x{951A}\x{951B}\x{951C}' .
          '\x{951D}\x{951E}\x{951F}\x{9520}\x{9521}\x{9522}\x{9523}\x{9524}\x{9525}' .
          '\x{9526}\x{9527}\x{9528}\x{9529}\x{952A}\x{952B}\x{952C}\x{952D}\x{952E}' .
          '\x{952F}\x{9530}\x{9531}\x{9532}\x{9533}\x{9534}\x{9535}\x{9536}\x{9537}' .
          '\x{9538}\x{9539}\x{953A}\x{953B}\x{953C}\x{953D}\x{953E}\x{953F}\x{9540}' .
          '\x{9541}\x{9542}\x{9543}\x{9544}\x{9545}\x{9546}\x{9547}\x{9548}\x{9549}' .
          '\x{954A}\x{954B}\x{954C}\x{954D}\x{954E}\x{954F}\x{9550}\x{9551}\x{9552}' .
          '\x{9553}\x{9554}\x{9555}\x{9556}\x{9557}\x{9558}\x{9559}\x{955A}\x{955B}' .
          '\x{955C}\x{955D}\x{955E}\x{955F}\x{9560}\x{9561}\x{9562}\x{9563}\x{9564}' .
          '\x{9565}\x{9566}\x{9567}\x{9568}\x{9569}\x{956A}\x{956B}\x{956C}\x{956D}' .
          '\x{956E}\x{956F}\x{9570}\x{9571}\x{9572}\x{9573}\x{9574}\x{9575}\x{9576}' .
          '\x{9577}\x{957A}\x{957B}\x{957C}\x{957D}\x{957F}\x{9580}\x{9581}\x{9582}' .
          '\x{9583}\x{9584}\x{9586}\x{9587}\x{9588}\x{9589}\x{958A}\x{958B}\x{958C}' .
          '\x{958D}\x{958E}\x{958F}\x{9590}\x{9591}\x{9592}\x{9593}\x{9594}\x{9595}' .
          '\x{9596}\x{9598}\x{9599}\x{959A}\x{959B}\x{959C}\x{959D}\x{959E}\x{959F}' .
          '\x{95A1}\x{95A2}\x{95A3}\x{95A4}\x{95A5}\x{95A6}\x{95A7}\x{95A8}\x{95A9}' .
          '\x{95AA}\x{95AB}\x{95AC}\x{95AD}\x{95AE}\x{95AF}\x{95B0}\x{95B1}\x{95B2}' .
          '\x{95B5}\x{95B6}\x{95B7}\x{95B9}\x{95BA}\x{95BB}\x{95BC}\x{95BD}\x{95BE}' .
          '\x{95BF}\x{95C0}\x{95C2}\x{95C3}\x{95C4}\x{95C5}\x{95C6}\x{95C7}\x{95C8}' .
          '\x{95C9}\x{95CA}\x{95CB}\x{95CC}\x{95CD}\x{95CE}\x{95CF}\x{95D0}\x{95D1}' .
          '\x{95D2}\x{95D3}\x{95D4}\x{95D5}\x{95D6}\x{95D7}\x{95D8}\x{95DA}\x{95DB}' .
          '\x{95DC}\x{95DE}\x{95DF}\x{95E0}\x{95E1}\x{95E2}\x{95E3}\x{95E4}\x{95E5}' .
          '\x{95E6}\x{95E7}\x{95E8}\x{95E9}\x{95EA}\x{95EB}\x{95EC}\x{95ED}\x{95EE}' .
          '\x{95EF}\x{95F0}\x{95F1}\x{95F2}\x{95F3}\x{95F4}\x{95F5}\x{95F6}\x{95F7}' .
          '\x{95F8}\x{95F9}\x{95FA}\x{95FB}\x{95FC}\x{95FD}\x{95FE}\x{95FF}\x{9600}' .
          '\x{9601}\x{9602}\x{9603}\x{9604}\x{9605}\x{9606}\x{9607}\x{9608}\x{9609}' .
          '\x{960A}\x{960B}\x{960C}\x{960D}\x{960E}\x{960F}\x{9610}\x{9611}\x{9612}' .
          '\x{9613}\x{9614}\x{9615}\x{9616}\x{9617}\x{9618}\x{9619}\x{961A}\x{961B}' .
          '\x{961C}\x{961D}\x{961E}\x{961F}\x{9620}\x{9621}\x{9622}\x{9623}\x{9624}' .
          '\x{9627}\x{9628}\x{962A}\x{962B}\x{962C}\x{962D}\x{962E}\x{962F}\x{9630}' .
          '\x{9631}\x{9632}\x{9633}\x{9634}\x{9635}\x{9636}\x{9637}\x{9638}\x{9639}' .
          '\x{963A}\x{963B}\x{963C}\x{963D}\x{963F}\x{9640}\x{9641}\x{9642}\x{9643}' .
          '\x{9644}\x{9645}\x{9646}\x{9647}\x{9648}\x{9649}\x{964A}\x{964B}\x{964C}' .
          '\x{964D}\x{964E}\x{964F}\x{9650}\x{9651}\x{9652}\x{9653}\x{9654}\x{9655}' .
          '\x{9658}\x{9659}\x{965A}\x{965B}\x{965C}\x{965D}\x{965E}\x{965F}\x{9660}' .
          '\x{9661}\x{9662}\x{9663}\x{9664}\x{9666}\x{9667}\x{9668}\x{9669}\x{966A}' .
          '\x{966B}\x{966C}\x{966D}\x{966E}\x{966F}\x{9670}\x{9671}\x{9672}\x{9673}' .
          '\x{9674}\x{9675}\x{9676}\x{9677}\x{9678}\x{967C}\x{967D}\x{967E}\x{9680}' .
          '\x{9683}\x{9684}\x{9685}\x{9686}\x{9687}\x{9688}\x{9689}\x{968A}\x{968B}' .
          '\x{968D}\x{968E}\x{968F}\x{9690}\x{9691}\x{9692}\x{9693}\x{9694}\x{9695}' .
          '\x{9697}\x{9698}\x{9699}\x{969B}\x{969C}\x{969E}\x{96A0}\x{96A1}\x{96A2}' .
          '\x{96A3}\x{96A4}\x{96A5}\x{96A6}\x{96A7}\x{96A8}\x{96A9}\x{96AA}\x{96AC}' .
          '\x{96AD}\x{96AE}\x{96B0}\x{96B1}\x{96B3}\x{96B4}\x{96B6}\x{96B7}\x{96B8}' .
          '\x{96B9}\x{96BA}\x{96BB}\x{96BC}\x{96BD}\x{96BE}\x{96BF}\x{96C0}\x{96C1}' .
          '\x{96C2}\x{96C3}\x{96C4}\x{96C5}\x{96C6}\x{96C7}\x{96C8}\x{96C9}\x{96CA}' .
          '\x{96CB}\x{96CC}\x{96CD}\x{96CE}\x{96CF}\x{96D0}\x{96D1}\x{96D2}\x{96D3}' .
          '\x{96D4}\x{96D5}\x{96D6}\x{96D7}\x{96D8}\x{96D9}\x{96DA}\x{96DB}\x{96DC}' .
          '\x{96DD}\x{96DE}\x{96DF}\x{96E0}\x{96E1}\x{96E2}\x{96E3}\x{96E5}\x{96E8}' .
          '\x{96E9}\x{96EA}\x{96EB}\x{96EC}\x{96ED}\x{96EE}\x{96EF}\x{96F0}\x{96F1}' .
          '\x{96F2}\x{96F3}\x{96F4}\x{96F5}\x{96F6}\x{96F7}\x{96F8}\x{96F9}\x{96FA}' .
          '\x{96FB}\x{96FD}\x{96FE}\x{96FF}\x{9700}\x{9701}\x{9702}\x{9703}\x{9704}' .
          '\x{9705}\x{9706}\x{9707}\x{9708}\x{9709}\x{970A}\x{970B}\x{970C}\x{970D}' .
          '\x{970E}\x{970F}\x{9710}\x{9711}\x{9712}\x{9713}\x{9715}\x{9716}\x{9718}' .
          '\x{9719}\x{971C}\x{971D}\x{971E}\x{971F}\x{9720}\x{9721}\x{9722}\x{9723}' .
          '\x{9724}\x{9725}\x{9726}\x{9727}\x{9728}\x{9729}\x{972A}\x{972B}\x{972C}' .
          '\x{972D}\x{972E}\x{972F}\x{9730}\x{9731}\x{9732}\x{9735}\x{9736}\x{9738}' .
          '\x{9739}\x{973A}\x{973B}\x{973C}\x{973D}\x{973E}\x{973F}\x{9742}\x{9743}' .
          '\x{9744}\x{9745}\x{9746}\x{9747}\x{9748}\x{9749}\x{974A}\x{974B}\x{974C}' .
          '\x{974E}\x{974F}\x{9750}\x{9751}\x{9752}\x{9753}\x{9754}\x{9755}\x{9756}' .
          '\x{9758}\x{9759}\x{975A}\x{975B}\x{975C}\x{975D}\x{975E}\x{975F}\x{9760}' .
          '\x{9761}\x{9762}\x{9765}\x{9766}\x{9767}\x{9768}\x{9769}\x{976A}\x{976B}' .
          '\x{976C}\x{976D}\x{976E}\x{976F}\x{9770}\x{9772}\x{9773}\x{9774}\x{9776}' .
          '\x{9777}\x{9778}\x{9779}\x{977A}\x{977B}\x{977C}\x{977D}\x{977E}\x{977F}' .
          '\x{9780}\x{9781}\x{9782}\x{9783}\x{9784}\x{9785}\x{9786}\x{9788}\x{978A}' .
          '\x{978B}\x{978C}\x{978D}\x{978E}\x{978F}\x{9790}\x{9791}\x{9792}\x{9793}' .
          '\x{9794}\x{9795}\x{9796}\x{9797}\x{9798}\x{9799}\x{979A}\x{979C}\x{979D}' .
          '\x{979E}\x{979F}\x{97A0}\x{97A1}\x{97A2}\x{97A3}\x{97A4}\x{97A5}\x{97A6}' .
          '\x{97A7}\x{97A8}\x{97AA}\x{97AB}\x{97AC}\x{97AD}\x{97AE}\x{97AF}\x{97B2}' .
          '\x{97B3}\x{97B4}\x{97B6}\x{97B7}\x{97B8}\x{97B9}\x{97BA}\x{97BB}\x{97BC}' .
          '\x{97BD}\x{97BF}\x{97C1}\x{97C2}\x{97C3}\x{97C4}\x{97C5}\x{97C6}\x{97C7}' .
          '\x{97C8}\x{97C9}\x{97CA}\x{97CB}\x{97CC}\x{97CD}\x{97CE}\x{97CF}\x{97D0}' .
          '\x{97D1}\x{97D3}\x{97D4}\x{97D5}\x{97D6}\x{97D7}\x{97D8}\x{97D9}\x{97DA}' .
          '\x{97DB}\x{97DC}\x{97DD}\x{97DE}\x{97DF}\x{97E0}\x{97E1}\x{97E2}\x{97E3}' .
          '\x{97E4}\x{97E5}\x{97E6}\x{97E7}\x{97E8}\x{97E9}\x{97EA}\x{97EB}\x{97EC}' .
          '\x{97ED}\x{97EE}\x{97EF}\x{97F0}\x{97F1}\x{97F2}\x{97F3}\x{97F4}\x{97F5}' .
          '\x{97F6}\x{97F7}\x{97F8}\x{97F9}\x{97FA}\x{97FB}\x{97FD}\x{97FE}\x{97FF}' .
          '\x{9800}\x{9801}\x{9802}\x{9803}\x{9804}\x{9805}\x{9806}\x{9807}\x{9808}' .
          '\x{9809}\x{980A}\x{980B}\x{980C}\x{980D}\x{980E}\x{980F}\x{9810}\x{9811}' .
          '\x{9812}\x{9813}\x{9814}\x{9815}\x{9816}\x{9817}\x{9818}\x{9819}\x{981A}' .
          '\x{981B}\x{981C}\x{981D}\x{981E}\x{9820}\x{9821}\x{9822}\x{9823}\x{9824}' .
          '\x{9826}\x{9827}\x{9828}\x{9829}\x{982B}\x{982D}\x{982E}\x{982F}\x{9830}' .
          '\x{9831}\x{9832}\x{9834}\x{9835}\x{9836}\x{9837}\x{9838}\x{9839}\x{983B}' .
          '\x{983C}\x{983D}\x{983F}\x{9840}\x{9841}\x{9843}\x{9844}\x{9845}\x{9846}' .
          '\x{9848}\x{9849}\x{984A}\x{984C}\x{984D}\x{984E}\x{984F}\x{9850}\x{9851}' .
          '\x{9852}\x{9853}\x{9854}\x{9855}\x{9857}\x{9858}\x{9859}\x{985A}\x{985B}' .
          '\x{985C}\x{985D}\x{985E}\x{985F}\x{9860}\x{9861}\x{9862}\x{9863}\x{9864}' .
          '\x{9865}\x{9867}\x{9869}\x{986A}\x{986B}\x{986C}\x{986D}\x{986E}\x{986F}' .
          '\x{9870}\x{9871}\x{9872}\x{9873}\x{9874}\x{9875}\x{9876}\x{9877}\x{9878}' .
          '\x{9879}\x{987A}\x{987B}\x{987C}\x{987D}\x{987E}\x{987F}\x{9880}\x{9881}' .
          '\x{9882}\x{9883}\x{9884}\x{9885}\x{9886}\x{9887}\x{9888}\x{9889}\x{988A}' .
          '\x{988B}\x{988C}\x{988D}\x{988E}\x{988F}\x{9890}\x{9891}\x{9892}\x{9893}' .
          '\x{9894}\x{9895}\x{9896}\x{9897}\x{9898}\x{9899}\x{989A}\x{989B}\x{989C}' .
          '\x{989D}\x{989E}\x{989F}\x{98A0}\x{98A1}\x{98A2}\x{98A3}\x{98A4}\x{98A5}' .
          '\x{98A6}\x{98A7}\x{98A8}\x{98A9}\x{98AA}\x{98AB}\x{98AC}\x{98AD}\x{98AE}' .
          '\x{98AF}\x{98B0}\x{98B1}\x{98B2}\x{98B3}\x{98B4}\x{98B5}\x{98B6}\x{98B8}' .
          '\x{98B9}\x{98BA}\x{98BB}\x{98BC}\x{98BD}\x{98BE}\x{98BF}\x{98C0}\x{98C1}' .
          '\x{98C2}\x{98C3}\x{98C4}\x{98C5}\x{98C6}\x{98C8}\x{98C9}\x{98CB}\x{98CC}' .
          '\x{98CD}\x{98CE}\x{98CF}\x{98D0}\x{98D1}\x{98D2}\x{98D3}\x{98D4}\x{98D5}' .
          '\x{98D6}\x{98D7}\x{98D8}\x{98D9}\x{98DA}\x{98DB}\x{98DC}\x{98DD}\x{98DE}' .
          '\x{98DF}\x{98E0}\x{98E2}\x{98E3}\x{98E5}\x{98E6}\x{98E7}\x{98E8}\x{98E9}' .
          '\x{98EA}\x{98EB}\x{98ED}\x{98EF}\x{98F0}\x{98F2}\x{98F3}\x{98F4}\x{98F5}' .
          '\x{98F6}\x{98F7}\x{98F9}\x{98FA}\x{98FC}\x{98FD}\x{98FE}\x{98FF}\x{9900}' .
          '\x{9901}\x{9902}\x{9903}\x{9904}\x{9905}\x{9906}\x{9907}\x{9908}\x{9909}' .
          '\x{990A}\x{990B}\x{990C}\x{990D}\x{990E}\x{990F}\x{9910}\x{9911}\x{9912}' .
          '\x{9913}\x{9914}\x{9915}\x{9916}\x{9917}\x{9918}\x{991A}\x{991B}\x{991C}' .
          '\x{991D}\x{991E}\x{991F}\x{9920}\x{9921}\x{9922}\x{9923}\x{9924}\x{9925}' .
          '\x{9926}\x{9927}\x{9928}\x{9929}\x{992A}\x{992B}\x{992C}\x{992D}\x{992E}' .
          '\x{992F}\x{9930}\x{9931}\x{9932}\x{9933}\x{9934}\x{9935}\x{9936}\x{9937}' .
          '\x{9938}\x{9939}\x{993A}\x{993C}\x{993D}\x{993E}\x{993F}\x{9940}\x{9941}' .
          '\x{9942}\x{9943}\x{9945}\x{9946}\x{9947}\x{9948}\x{9949}\x{994A}\x{994B}' .
          '\x{994C}\x{994E}\x{994F}\x{9950}\x{9951}\x{9952}\x{9953}\x{9954}\x{9955}' .
          '\x{9956}\x{9957}\x{9958}\x{9959}\x{995B}\x{995C}\x{995E}\x{995F}\x{9960}' .
          '\x{9961}\x{9962}\x{9963}\x{9964}\x{9965}\x{9966}\x{9967}\x{9968}\x{9969}' .
          '\x{996A}\x{996B}\x{996C}\x{996D}\x{996E}\x{996F}\x{9970}\x{9971}\x{9972}' .
          '\x{9973}\x{9974}\x{9975}\x{9976}\x{9977}\x{9978}\x{9979}\x{997A}\x{997B}' .
          '\x{997C}\x{997D}\x{997E}\x{997F}\x{9980}\x{9981}\x{9982}\x{9983}\x{9984}' .
          '\x{9985}\x{9986}\x{9987}\x{9988}\x{9989}\x{998A}\x{998B}\x{998C}\x{998D}' .
          '\x{998E}\x{998F}\x{9990}\x{9991}\x{9992}\x{9993}\x{9994}\x{9995}\x{9996}' .
          '\x{9997}\x{9998}\x{9999}\x{999A}\x{999B}\x{999C}\x{999D}\x{999E}\x{999F}' .
          '\x{99A0}\x{99A1}\x{99A2}\x{99A3}\x{99A4}\x{99A5}\x{99A6}\x{99A7}\x{99A8}' .
          '\x{99A9}\x{99AA}\x{99AB}\x{99AC}\x{99AD}\x{99AE}\x{99AF}\x{99B0}\x{99B1}' .
          '\x{99B2}\x{99B3}\x{99B4}\x{99B5}\x{99B6}\x{99B7}\x{99B8}\x{99B9}\x{99BA}' .
          '\x{99BB}\x{99BC}\x{99BD}\x{99BE}\x{99C0}\x{99C1}\x{99C2}\x{99C3}\x{99C4}' .
          '\x{99C6}\x{99C7}\x{99C8}\x{99C9}\x{99CA}\x{99CB}\x{99CC}\x{99CD}\x{99CE}' .
          '\x{99CF}\x{99D0}\x{99D1}\x{99D2}\x{99D3}\x{99D4}\x{99D5}\x{99D6}\x{99D7}' .
          '\x{99D8}\x{99D9}\x{99DA}\x{99DB}\x{99DC}\x{99DD}\x{99DE}\x{99DF}\x{99E1}' .
          '\x{99E2}\x{99E3}\x{99E4}\x{99E5}\x{99E7}\x{99E8}\x{99E9}\x{99EA}\x{99EC}' .
          '\x{99ED}\x{99EE}\x{99EF}\x{99F0}\x{99F1}\x{99F2}\x{99F3}\x{99F4}\x{99F6}' .
          '\x{99F7}\x{99F8}\x{99F9}\x{99FA}\x{99FB}\x{99FC}\x{99FD}\x{99FE}\x{99FF}' .
          '\x{9A00}\x{9A01}\x{9A02}\x{9A03}\x{9A04}\x{9A05}\x{9A06}\x{9A07}\x{9A08}' .
          '\x{9A09}\x{9A0A}\x{9A0B}\x{9A0C}\x{9A0D}\x{9A0E}\x{9A0F}\x{9A11}\x{9A14}' .
          '\x{9A15}\x{9A16}\x{9A19}\x{9A1A}\x{9A1B}\x{9A1C}\x{9A1D}\x{9A1E}\x{9A1F}' .
          '\x{9A20}\x{9A21}\x{9A22}\x{9A23}\x{9A24}\x{9A25}\x{9A26}\x{9A27}\x{9A29}' .
          '\x{9A2A}\x{9A2B}\x{9A2C}\x{9A2D}\x{9A2E}\x{9A2F}\x{9A30}\x{9A31}\x{9A32}' .
          '\x{9A33}\x{9A34}\x{9A35}\x{9A36}\x{9A37}\x{9A38}\x{9A39}\x{9A3A}\x{9A3C}' .
          '\x{9A3D}\x{9A3E}\x{9A3F}\x{9A40}\x{9A41}\x{9A42}\x{9A43}\x{9A44}\x{9A45}' .
          '\x{9A46}\x{9A47}\x{9A48}\x{9A49}\x{9A4A}\x{9A4B}\x{9A4C}\x{9A4D}\x{9A4E}' .
          '\x{9A4F}\x{9A50}\x{9A52}\x{9A53}\x{9A54}\x{9A55}\x{9A56}\x{9A57}\x{9A59}' .
          '\x{9A5A}\x{9A5B}\x{9A5C}\x{9A5E}\x{9A5F}\x{9A60}\x{9A61}\x{9A62}\x{9A64}' .
          '\x{9A65}\x{9A66}\x{9A67}\x{9A68}\x{9A69}\x{9A6A}\x{9A6B}\x{9A6C}\x{9A6D}' .
          '\x{9A6E}\x{9A6F}\x{9A70}\x{9A71}\x{9A72}\x{9A73}\x{9A74}\x{9A75}\x{9A76}' .
          '\x{9A77}\x{9A78}\x{9A79}\x{9A7A}\x{9A7B}\x{9A7C}\x{9A7D}\x{9A7E}\x{9A7F}' .
          '\x{9A80}\x{9A81}\x{9A82}\x{9A83}\x{9A84}\x{9A85}\x{9A86}\x{9A87}\x{9A88}' .
          '\x{9A89}\x{9A8A}\x{9A8B}\x{9A8C}\x{9A8D}\x{9A8E}\x{9A8F}\x{9A90}\x{9A91}' .
          '\x{9A92}\x{9A93}\x{9A94}\x{9A95}\x{9A96}\x{9A97}\x{9A98}\x{9A99}\x{9A9A}' .
          '\x{9A9B}\x{9A9C}\x{9A9D}\x{9A9E}\x{9A9F}\x{9AA0}\x{9AA1}\x{9AA2}\x{9AA3}' .
          '\x{9AA4}\x{9AA5}\x{9AA6}\x{9AA7}\x{9AA8}\x{9AAA}\x{9AAB}\x{9AAC}\x{9AAD}' .
          '\x{9AAE}\x{9AAF}\x{9AB0}\x{9AB1}\x{9AB2}\x{9AB3}\x{9AB4}\x{9AB5}\x{9AB6}' .
          '\x{9AB7}\x{9AB8}\x{9AB9}\x{9ABA}\x{9ABB}\x{9ABC}\x{9ABE}\x{9ABF}\x{9AC0}' .
          '\x{9AC1}\x{9AC2}\x{9AC3}\x{9AC4}\x{9AC5}\x{9AC6}\x{9AC7}\x{9AC9}\x{9ACA}' .
          '\x{9ACB}\x{9ACC}\x{9ACD}\x{9ACE}\x{9ACF}\x{9AD0}\x{9AD1}\x{9AD2}\x{9AD3}' .
          '\x{9AD4}\x{9AD5}\x{9AD6}\x{9AD8}\x{9AD9}\x{9ADA}\x{9ADB}\x{9ADC}\x{9ADD}' .
          '\x{9ADE}\x{9ADF}\x{9AE1}\x{9AE2}\x{9AE3}\x{9AE5}\x{9AE6}\x{9AE7}\x{9AEA}' .
          '\x{9AEB}\x{9AEC}\x{9AED}\x{9AEE}\x{9AEF}\x{9AF1}\x{9AF2}\x{9AF3}\x{9AF4}' .
          '\x{9AF5}\x{9AF6}\x{9AF7}\x{9AF8}\x{9AF9}\x{9AFA}\x{9AFB}\x{9AFC}\x{9AFD}' .
          '\x{9AFE}\x{9AFF}\x{9B01}\x{9B03}\x{9B04}\x{9B05}\x{9B06}\x{9B07}\x{9B08}' .
          '\x{9B0A}\x{9B0B}\x{9B0C}\x{9B0D}\x{9B0E}\x{9B0F}\x{9B10}\x{9B11}\x{9B12}' .
          '\x{9B13}\x{9B15}\x{9B16}\x{9B17}\x{9B18}\x{9B19}\x{9B1A}\x{9B1C}\x{9B1D}' .
          '\x{9B1E}\x{9B1F}\x{9B20}\x{9B21}\x{9B22}\x{9B23}\x{9B24}\x{9B25}\x{9B26}' .
          '\x{9B27}\x{9B28}\x{9B29}\x{9B2A}\x{9B2B}\x{9B2C}\x{9B2D}\x{9B2E}\x{9B2F}' .
          '\x{9B30}\x{9B31}\x{9B32}\x{9B33}\x{9B35}\x{9B36}\x{9B37}\x{9B38}\x{9B39}' .
          '\x{9B3A}\x{9B3B}\x{9B3C}\x{9B3E}\x{9B3F}\x{9B41}\x{9B42}\x{9B43}\x{9B44}' .
          '\x{9B45}\x{9B46}\x{9B47}\x{9B48}\x{9B49}\x{9B4A}\x{9B4B}\x{9B4C}\x{9B4D}' .
          '\x{9B4E}\x{9B4F}\x{9B51}\x{9B52}\x{9B53}\x{9B54}\x{9B55}\x{9B56}\x{9B58}' .
          '\x{9B59}\x{9B5A}\x{9B5B}\x{9B5C}\x{9B5D}\x{9B5E}\x{9B5F}\x{9B60}\x{9B61}' .
          '\x{9B63}\x{9B64}\x{9B65}\x{9B66}\x{9B67}\x{9B68}\x{9B69}\x{9B6A}\x{9B6B}' .
          '\x{9B6C}\x{9B6D}\x{9B6E}\x{9B6F}\x{9B70}\x{9B71}\x{9B73}\x{9B74}\x{9B75}' .
          '\x{9B76}\x{9B77}\x{9B78}\x{9B79}\x{9B7A}\x{9B7B}\x{9B7C}\x{9B7D}\x{9B7E}' .
          '\x{9B7F}\x{9B80}\x{9B81}\x{9B82}\x{9B83}\x{9B84}\x{9B85}\x{9B86}\x{9B87}' .
          '\x{9B88}\x{9B8A}\x{9B8B}\x{9B8D}\x{9B8E}\x{9B8F}\x{9B90}\x{9B91}\x{9B92}' .
          '\x{9B93}\x{9B94}\x{9B95}\x{9B96}\x{9B97}\x{9B98}\x{9B9A}\x{9B9B}\x{9B9C}' .
          '\x{9B9D}\x{9B9E}\x{9B9F}\x{9BA0}\x{9BA1}\x{9BA2}\x{9BA3}\x{9BA4}\x{9BA5}' .
          '\x{9BA6}\x{9BA7}\x{9BA8}\x{9BA9}\x{9BAA}\x{9BAB}\x{9BAC}\x{9BAD}\x{9BAE}' .
          '\x{9BAF}\x{9BB0}\x{9BB1}\x{9BB2}\x{9BB3}\x{9BB4}\x{9BB5}\x{9BB6}\x{9BB7}' .
          '\x{9BB8}\x{9BB9}\x{9BBA}\x{9BBB}\x{9BBC}\x{9BBD}\x{9BBE}\x{9BBF}\x{9BC0}' .
          '\x{9BC1}\x{9BC3}\x{9BC4}\x{9BC5}\x{9BC6}\x{9BC7}\x{9BC8}\x{9BC9}\x{9BCA}' .
          '\x{9BCB}\x{9BCC}\x{9BCD}\x{9BCE}\x{9BCF}\x{9BD0}\x{9BD1}\x{9BD2}\x{9BD3}' .
          '\x{9BD4}\x{9BD5}\x{9BD6}\x{9BD7}\x{9BD8}\x{9BD9}\x{9BDA}\x{9BDB}\x{9BDC}' .
          '\x{9BDD}\x{9BDE}\x{9BDF}\x{9BE0}\x{9BE1}\x{9BE2}\x{9BE3}\x{9BE4}\x{9BE5}' .
          '\x{9BE6}\x{9BE7}\x{9BE8}\x{9BE9}\x{9BEA}\x{9BEB}\x{9BEC}\x{9BED}\x{9BEE}' .
          '\x{9BEF}\x{9BF0}\x{9BF1}\x{9BF2}\x{9BF3}\x{9BF4}\x{9BF5}\x{9BF7}\x{9BF8}' .
          '\x{9BF9}\x{9BFA}\x{9BFB}\x{9BFC}\x{9BFD}\x{9BFE}\x{9BFF}\x{9C02}\x{9C05}' .
          '\x{9C06}\x{9C07}\x{9C08}\x{9C09}\x{9C0A}\x{9C0B}\x{9C0C}\x{9C0D}\x{9C0E}' .
          '\x{9C0F}\x{9C10}\x{9C11}\x{9C12}\x{9C13}\x{9C14}\x{9C15}\x{9C16}\x{9C17}' .
          '\x{9C18}\x{9C19}\x{9C1A}\x{9C1B}\x{9C1C}\x{9C1D}\x{9C1E}\x{9C1F}\x{9C20}' .
          '\x{9C21}\x{9C22}\x{9C23}\x{9C24}\x{9C25}\x{9C26}\x{9C27}\x{9C28}\x{9C29}' .
          '\x{9C2A}\x{9C2B}\x{9C2C}\x{9C2D}\x{9C2F}\x{9C30}\x{9C31}\x{9C32}\x{9C33}' .
          '\x{9C34}\x{9C35}\x{9C36}\x{9C37}\x{9C38}\x{9C39}\x{9C3A}\x{9C3B}\x{9C3C}' .
          '\x{9C3D}\x{9C3E}\x{9C3F}\x{9C40}\x{9C41}\x{9C43}\x{9C44}\x{9C45}\x{9C46}' .
          '\x{9C47}\x{9C48}\x{9C49}\x{9C4A}\x{9C4B}\x{9C4C}\x{9C4D}\x{9C4E}\x{9C50}' .
          '\x{9C52}\x{9C53}\x{9C54}\x{9C55}\x{9C56}\x{9C57}\x{9C58}\x{9C59}\x{9C5A}' .
          '\x{9C5B}\x{9C5C}\x{9C5D}\x{9C5E}\x{9C5F}\x{9C60}\x{9C62}\x{9C63}\x{9C65}' .
          '\x{9C66}\x{9C67}\x{9C68}\x{9C69}\x{9C6A}\x{9C6B}\x{9C6C}\x{9C6D}\x{9C6E}' .
          '\x{9C6F}\x{9C70}\x{9C71}\x{9C72}\x{9C73}\x{9C74}\x{9C75}\x{9C77}\x{9C78}' .
          '\x{9C79}\x{9C7A}\x{9C7C}\x{9C7D}\x{9C7E}\x{9C7F}\x{9C80}\x{9C81}\x{9C82}' .
          '\x{9C83}\x{9C84}\x{9C85}\x{9C86}\x{9C87}\x{9C88}\x{9C89}\x{9C8A}\x{9C8B}' .
          '\x{9C8C}\x{9C8D}\x{9C8E}\x{9C8F}\x{9C90}\x{9C91}\x{9C92}\x{9C93}\x{9C94}' .
          '\x{9C95}\x{9C96}\x{9C97}\x{9C98}\x{9C99}\x{9C9A}\x{9C9B}\x{9C9C}\x{9C9D}' .
          '\x{9C9E}\x{9C9F}\x{9CA0}\x{9CA1}\x{9CA2}\x{9CA3}\x{9CA4}\x{9CA5}\x{9CA6}' .
          '\x{9CA7}\x{9CA8}\x{9CA9}\x{9CAA}\x{9CAB}\x{9CAC}\x{9CAD}\x{9CAE}\x{9CAF}' .
          '\x{9CB0}\x{9CB1}\x{9CB2}\x{9CB3}\x{9CB4}\x{9CB5}\x{9CB6}\x{9CB7}\x{9CB8}' .
          '\x{9CB9}\x{9CBA}\x{9CBB}\x{9CBC}\x{9CBD}\x{9CBE}\x{9CBF}\x{9CC0}\x{9CC1}' .
          '\x{9CC2}\x{9CC3}\x{9CC4}\x{9CC5}\x{9CC6}\x{9CC7}\x{9CC8}\x{9CC9}\x{9CCA}' .
          '\x{9CCB}\x{9CCC}\x{9CCD}\x{9CCE}\x{9CCF}\x{9CD0}\x{9CD1}\x{9CD2}\x{9CD3}' .
          '\x{9CD4}\x{9CD5}\x{9CD6}\x{9CD7}\x{9CD8}\x{9CD9}\x{9CDA}\x{9CDB}\x{9CDC}' .
          '\x{9CDD}\x{9CDE}\x{9CDF}\x{9CE0}\x{9CE1}\x{9CE2}\x{9CE3}\x{9CE4}\x{9CE5}' .
          '\x{9CE6}\x{9CE7}\x{9CE8}\x{9CE9}\x{9CEA}\x{9CEB}\x{9CEC}\x{9CED}\x{9CEE}' .
          '\x{9CEF}\x{9CF0}\x{9CF1}\x{9CF2}\x{9CF3}\x{9CF4}\x{9CF5}\x{9CF6}\x{9CF7}' .
          '\x{9CF8}\x{9CF9}\x{9CFA}\x{9CFB}\x{9CFC}\x{9CFD}\x{9CFE}\x{9CFF}\x{9D00}' .
          '\x{9D01}\x{9D02}\x{9D03}\x{9D04}\x{9D05}\x{9D06}\x{9D07}\x{9D08}\x{9D09}' .
          '\x{9D0A}\x{9D0B}\x{9D0F}\x{9D10}\x{9D12}\x{9D13}\x{9D14}\x{9D15}\x{9D16}' .
          '\x{9D17}\x{9D18}\x{9D19}\x{9D1A}\x{9D1B}\x{9D1C}\x{9D1D}\x{9D1E}\x{9D1F}' .
          '\x{9D20}\x{9D21}\x{9D22}\x{9D23}\x{9D24}\x{9D25}\x{9D26}\x{9D28}\x{9D29}' .
          '\x{9D2B}\x{9D2D}\x{9D2E}\x{9D2F}\x{9D30}\x{9D31}\x{9D32}\x{9D33}\x{9D34}' .
          '\x{9D36}\x{9D37}\x{9D38}\x{9D39}\x{9D3A}\x{9D3B}\x{9D3D}\x{9D3E}\x{9D3F}' .
          '\x{9D40}\x{9D41}\x{9D42}\x{9D43}\x{9D45}\x{9D46}\x{9D47}\x{9D48}\x{9D49}' .
          '\x{9D4A}\x{9D4B}\x{9D4C}\x{9D4D}\x{9D4E}\x{9D4F}\x{9D50}\x{9D51}\x{9D52}' .
          '\x{9D53}\x{9D54}\x{9D55}\x{9D56}\x{9D57}\x{9D58}\x{9D59}\x{9D5A}\x{9D5B}' .
          '\x{9D5C}\x{9D5D}\x{9D5E}\x{9D5F}\x{9D60}\x{9D61}\x{9D62}\x{9D63}\x{9D64}' .
          '\x{9D65}\x{9D66}\x{9D67}\x{9D68}\x{9D69}\x{9D6A}\x{9D6B}\x{9D6C}\x{9D6E}' .
          '\x{9D6F}\x{9D70}\x{9D71}\x{9D72}\x{9D73}\x{9D74}\x{9D75}\x{9D76}\x{9D77}' .
          '\x{9D78}\x{9D79}\x{9D7A}\x{9D7B}\x{9D7C}\x{9D7D}\x{9D7E}\x{9D7F}\x{9D80}' .
          '\x{9D81}\x{9D82}\x{9D83}\x{9D84}\x{9D85}\x{9D86}\x{9D87}\x{9D88}\x{9D89}' .
          '\x{9D8A}\x{9D8B}\x{9D8C}\x{9D8D}\x{9D8E}\x{9D90}\x{9D91}\x{9D92}\x{9D93}' .
          '\x{9D94}\x{9D96}\x{9D97}\x{9D98}\x{9D99}\x{9D9A}\x{9D9B}\x{9D9C}\x{9D9D}' .
          '\x{9D9E}\x{9D9F}\x{9DA0}\x{9DA1}\x{9DA2}\x{9DA3}\x{9DA4}\x{9DA5}\x{9DA6}' .
          '\x{9DA7}\x{9DA8}\x{9DA9}\x{9DAA}\x{9DAB}\x{9DAC}\x{9DAD}\x{9DAF}\x{9DB0}' .
          '\x{9DB1}\x{9DB2}\x{9DB3}\x{9DB4}\x{9DB5}\x{9DB6}\x{9DB7}\x{9DB8}\x{9DB9}' .
          '\x{9DBA}\x{9DBB}\x{9DBC}\x{9DBE}\x{9DBF}\x{9DC1}\x{9DC2}\x{9DC3}\x{9DC4}' .
          '\x{9DC5}\x{9DC7}\x{9DC8}\x{9DC9}\x{9DCA}\x{9DCB}\x{9DCC}\x{9DCD}\x{9DCE}' .
          '\x{9DCF}\x{9DD0}\x{9DD1}\x{9DD2}\x{9DD3}\x{9DD4}\x{9DD5}\x{9DD6}\x{9DD7}' .
          '\x{9DD8}\x{9DD9}\x{9DDA}\x{9DDB}\x{9DDC}\x{9DDD}\x{9DDE}\x{9DDF}\x{9DE0}' .
          '\x{9DE1}\x{9DE2}\x{9DE3}\x{9DE4}\x{9DE5}\x{9DE6}\x{9DE7}\x{9DE8}\x{9DE9}' .
          '\x{9DEB}\x{9DEC}\x{9DED}\x{9DEE}\x{9DEF}\x{9DF0}\x{9DF1}\x{9DF2}\x{9DF3}' .
          '\x{9DF4}\x{9DF5}\x{9DF6}\x{9DF7}\x{9DF8}\x{9DF9}\x{9DFA}\x{9DFB}\x{9DFD}' .
          '\x{9DFE}\x{9DFF}\x{9E00}\x{9E01}\x{9E02}\x{9E03}\x{9E04}\x{9E05}\x{9E06}' .
          '\x{9E07}\x{9E08}\x{9E09}\x{9E0A}\x{9E0B}\x{9E0C}\x{9E0D}\x{9E0F}\x{9E10}' .
          '\x{9E11}\x{9E12}\x{9E13}\x{9E14}\x{9E15}\x{9E17}\x{9E18}\x{9E19}\x{9E1A}' .
          '\x{9E1B}\x{9E1D}\x{9E1E}\x{9E1F}\x{9E20}\x{9E21}\x{9E22}\x{9E23}\x{9E24}' .
          '\x{9E25}\x{9E26}\x{9E27}\x{9E28}\x{9E29}\x{9E2A}\x{9E2B}\x{9E2C}\x{9E2D}' .
          '\x{9E2E}\x{9E2F}\x{9E30}\x{9E31}\x{9E32}\x{9E33}\x{9E34}\x{9E35}\x{9E36}' .
          '\x{9E37}\x{9E38}\x{9E39}\x{9E3A}\x{9E3B}\x{9E3C}\x{9E3D}\x{9E3E}\x{9E3F}' .
          '\x{9E40}\x{9E41}\x{9E42}\x{9E43}\x{9E44}\x{9E45}\x{9E46}\x{9E47}\x{9E48}' .
          '\x{9E49}\x{9E4A}\x{9E4B}\x{9E4C}\x{9E4D}\x{9E4E}\x{9E4F}\x{9E50}\x{9E51}' .
          '\x{9E52}\x{9E53}\x{9E54}\x{9E55}\x{9E56}\x{9E57}\x{9E58}\x{9E59}\x{9E5A}' .
          '\x{9E5B}\x{9E5C}\x{9E5D}\x{9E5E}\x{9E5F}\x{9E60}\x{9E61}\x{9E62}\x{9E63}' .
          '\x{9E64}\x{9E65}\x{9E66}\x{9E67}\x{9E68}\x{9E69}\x{9E6A}\x{9E6B}\x{9E6C}' .
          '\x{9E6D}\x{9E6E}\x{9E6F}\x{9E70}\x{9E71}\x{9E72}\x{9E73}\x{9E74}\x{9E75}' .
          '\x{9E76}\x{9E77}\x{9E79}\x{9E7A}\x{9E7C}\x{9E7D}\x{9E7E}\x{9E7F}\x{9E80}' .
          '\x{9E81}\x{9E82}\x{9E83}\x{9E84}\x{9E85}\x{9E86}\x{9E87}\x{9E88}\x{9E89}' .
          '\x{9E8A}\x{9E8B}\x{9E8C}\x{9E8D}\x{9E8E}\x{9E91}\x{9E92}\x{9E93}\x{9E94}' .
          '\x{9E96}\x{9E97}\x{9E99}\x{9E9A}\x{9E9B}\x{9E9C}\x{9E9D}\x{9E9F}\x{9EA0}' .
          '\x{9EA1}\x{9EA3}\x{9EA4}\x{9EA5}\x{9EA6}\x{9EA7}\x{9EA8}\x{9EA9}\x{9EAA}' .
          '\x{9EAD}\x{9EAE}\x{9EAF}\x{9EB0}\x{9EB2}\x{9EB3}\x{9EB4}\x{9EB5}\x{9EB6}' .
          '\x{9EB7}\x{9EB8}\x{9EBB}\x{9EBC}\x{9EBD}\x{9EBE}\x{9EBF}\x{9EC0}\x{9EC1}' .
          '\x{9EC2}\x{9EC3}\x{9EC4}\x{9EC5}\x{9EC6}\x{9EC7}\x{9EC8}\x{9EC9}\x{9ECA}' .
          '\x{9ECB}\x{9ECC}\x{9ECD}\x{9ECE}\x{9ECF}\x{9ED0}\x{9ED1}\x{9ED2}\x{9ED3}' .
          '\x{9ED4}\x{9ED5}\x{9ED6}\x{9ED7}\x{9ED8}\x{9ED9}\x{9EDA}\x{9EDB}\x{9EDC}' .
          '\x{9EDD}\x{9EDE}\x{9EDF}\x{9EE0}\x{9EE1}\x{9EE2}\x{9EE3}\x{9EE4}\x{9EE5}' .
          '\x{9EE6}\x{9EE7}\x{9EE8}\x{9EE9}\x{9EEA}\x{9EEB}\x{9EED}\x{9EEE}\x{9EEF}' .
          '\x{9EF0}\x{9EF2}\x{9EF3}\x{9EF4}\x{9EF5}\x{9EF6}\x{9EF7}\x{9EF8}\x{9EF9}' .
          '\x{9EFA}\x{9EFB}\x{9EFC}\x{9EFD}\x{9EFE}\x{9EFF}\x{9F00}\x{9F01}\x{9F02}' .
          '\x{9F04}\x{9F05}\x{9F06}\x{9F07}\x{9F08}\x{9F09}\x{9F0A}\x{9F0B}\x{9F0C}' .
          '\x{9F0D}\x{9F0E}\x{9F0F}\x{9F10}\x{9F12}\x{9F13}\x{9F15}\x{9F16}\x{9F17}' .
          '\x{9F18}\x{9F19}\x{9F1A}\x{9F1B}\x{9F1C}\x{9F1D}\x{9F1E}\x{9F1F}\x{9F20}' .
          '\x{9F22}\x{9F23}\x{9F24}\x{9F25}\x{9F27}\x{9F28}\x{9F29}\x{9F2A}\x{9F2B}' .
          '\x{9F2C}\x{9F2D}\x{9F2E}\x{9F2F}\x{9F30}\x{9F31}\x{9F32}\x{9F33}\x{9F34}' .
          '\x{9F35}\x{9F36}\x{9F37}\x{9F38}\x{9F39}\x{9F3A}\x{9F3B}\x{9F3C}\x{9F3D}' .
          '\x{9F3E}\x{9F3F}\x{9F40}\x{9F41}\x{9F42}\x{9F43}\x{9F44}\x{9F46}\x{9F47}' .
          '\x{9F48}\x{9F49}\x{9F4A}\x{9F4B}\x{9F4C}\x{9F4D}\x{9F4E}\x{9F4F}\x{9F50}' .
          '\x{9F51}\x{9F52}\x{9F54}\x{9F55}\x{9F56}\x{9F57}\x{9F58}\x{9F59}\x{9F5A}' .
          '\x{9F5B}\x{9F5C}\x{9F5D}\x{9F5E}\x{9F5F}\x{9F60}\x{9F61}\x{9F63}\x{9F64}' .
          '\x{9F65}\x{9F66}\x{9F67}\x{9F68}\x{9F69}\x{9F6A}\x{9F6B}\x{9F6C}\x{9F6E}' .
          '\x{9F6F}\x{9F70}\x{9F71}\x{9F72}\x{9F73}\x{9F74}\x{9F75}\x{9F76}\x{9F77}' .
          '\x{9F78}\x{9F79}\x{9F7A}\x{9F7B}\x{9F7C}\x{9F7D}\x{9F7E}\x{9F7F}\x{9F80}' .
          '\x{9F81}\x{9F82}\x{9F83}\x{9F84}\x{9F85}\x{9F86}\x{9F87}\x{9F88}\x{9F89}' .
          '\x{9F8A}\x{9F8B}\x{9F8C}\x{9F8D}\x{9F8E}\x{9F8F}\x{9F90}\x{9F91}\x{9F92}' .
          '\x{9F93}\x{9F94}\x{9F95}\x{9F96}\x{9F97}\x{9F98}\x{9F99}\x{9F9A}\x{9F9B}' .
          '\x{9F9C}\x{9F9D}\x{9F9E}\x{9F9F}\x{9FA0}\x{9FA2}\x{9FA4}\x{9FA5}]{1,20}$/iu',
];
laminas-validator/src/Hostname/Cn.php000064400000561276147361032560013621 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-validator for the canonical source repository
 * @copyright https://github.com/laminas/laminas-validator/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-validator/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Validator\Hostname;

/**
 * Resource file for chinese idn validation
 */
return [
    1  => '/^[\x{002d}0-9a-z\x{3447}\x{3473}\x{359E}\x{360E}\x{361A}\x{3918}\x{396E}\x{39CF}\x{39D0}' .
          '\x{39DF}\x{3A73}\x{3B4E}\x{3C6E}\x{3CE0}\x{4056}\x{415F}\x{4337}\x{43AC}' .
          '\x{43B1}\x{43DD}\x{44D6}\x{464C}\x{4661}\x{4723}\x{4729}\x{477C}\x{478D}' .
          '\x{4947}\x{497A}\x{497D}\x{4982}\x{4983}\x{4985}\x{4986}\x{499B}\x{499F}' .
          '\x{49B6}\x{49B7}\x{4C77}\x{4C9F}\x{4CA0}\x{4CA1}\x{4CA2}\x{4CA3}\x{4D13}' .
          '\x{4D14}\x{4D15}\x{4D16}\x{4D17}\x{4D18}\x{4D19}\x{4DAE}\x{4E00}\x{4E01}' .
          '\x{4E02}\x{4E03}\x{4E04}\x{4E05}\x{4E06}\x{4E07}\x{4E08}\x{4E09}\x{4E0A}' .
          '\x{4E0B}\x{4E0C}\x{4E0D}\x{4E0E}\x{4E0F}\x{4E10}\x{4E11}\x{4E13}\x{4E14}' .
          '\x{4E15}\x{4E16}\x{4E17}\x{4E18}\x{4E19}\x{4E1A}\x{4E1B}\x{4E1C}\x{4E1D}' .
          '\x{4E1E}\x{4E1F}\x{4E20}\x{4E21}\x{4E22}\x{4E23}\x{4E24}\x{4E25}\x{4E26}' .
          '\x{4E27}\x{4E28}\x{4E2A}\x{4E2B}\x{4E2C}\x{4E2D}\x{4E2E}\x{4E2F}\x{4E30}' .
          '\x{4E31}\x{4E32}\x{4E33}\x{4E34}\x{4E35}\x{4E36}\x{4E37}\x{4E38}\x{4E39}' .
          '\x{4E3A}\x{4E3B}\x{4E3C}\x{4E3D}\x{4E3E}\x{4E3F}\x{4E40}\x{4E41}\x{4E42}' .
          '\x{4E43}\x{4E44}\x{4E45}\x{4E46}\x{4E47}\x{4E48}\x{4E49}\x{4E4A}\x{4E4B}' .
          '\x{4E4C}\x{4E4D}\x{4E4E}\x{4E4F}\x{4E50}\x{4E51}\x{4E52}\x{4E53}\x{4E54}' .
          '\x{4E56}\x{4E57}\x{4E58}\x{4E59}\x{4E5A}\x{4E5B}\x{4E5C}\x{4E5D}\x{4E5E}' .
          '\x{4E5F}\x{4E60}\x{4E61}\x{4E62}\x{4E63}\x{4E64}\x{4E65}\x{4E66}\x{4E67}' .
          '\x{4E69}\x{4E6A}\x{4E6B}\x{4E6C}\x{4E6D}\x{4E6E}\x{4E6F}\x{4E70}\x{4E71}' .
          '\x{4E72}\x{4E73}\x{4E74}\x{4E75}\x{4E76}\x{4E77}\x{4E78}\x{4E7A}\x{4E7B}' .
          '\x{4E7C}\x{4E7D}\x{4E7E}\x{4E7F}\x{4E80}\x{4E81}\x{4E82}\x{4E83}\x{4E84}' .
          '\x{4E85}\x{4E86}\x{4E87}\x{4E88}\x{4E89}\x{4E8B}\x{4E8C}\x{4E8D}\x{4E8E}' .
          '\x{4E8F}\x{4E90}\x{4E91}\x{4E92}\x{4E93}\x{4E94}\x{4E95}\x{4E97}\x{4E98}' .
          '\x{4E99}\x{4E9A}\x{4E9B}\x{4E9C}\x{4E9D}\x{4E9E}\x{4E9F}\x{4EA0}\x{4EA1}' .
          '\x{4EA2}\x{4EA4}\x{4EA5}\x{4EA6}\x{4EA7}\x{4EA8}\x{4EA9}\x{4EAA}\x{4EAB}' .
          '\x{4EAC}\x{4EAD}\x{4EAE}\x{4EAF}\x{4EB0}\x{4EB1}\x{4EB2}\x{4EB3}\x{4EB4}' .
          '\x{4EB5}\x{4EB6}\x{4EB7}\x{4EB8}\x{4EB9}\x{4EBA}\x{4EBB}\x{4EBD}\x{4EBE}' .
          '\x{4EBF}\x{4EC0}\x{4EC1}\x{4EC2}\x{4EC3}\x{4EC4}\x{4EC5}\x{4EC6}\x{4EC7}' .
          '\x{4EC8}\x{4EC9}\x{4ECA}\x{4ECB}\x{4ECD}\x{4ECE}\x{4ECF}\x{4ED0}\x{4ED1}' .
          '\x{4ED2}\x{4ED3}\x{4ED4}\x{4ED5}\x{4ED6}\x{4ED7}\x{4ED8}\x{4ED9}\x{4EDA}' .
          '\x{4EDB}\x{4EDC}\x{4EDD}\x{4EDE}\x{4EDF}\x{4EE0}\x{4EE1}\x{4EE2}\x{4EE3}' .
          '\x{4EE4}\x{4EE5}\x{4EE6}\x{4EE8}\x{4EE9}\x{4EEA}\x{4EEB}\x{4EEC}\x{4EEF}' .
          '\x{4EF0}\x{4EF1}\x{4EF2}\x{4EF3}\x{4EF4}\x{4EF5}\x{4EF6}\x{4EF7}\x{4EFB}' .
          '\x{4EFD}\x{4EFF}\x{4F00}\x{4F01}\x{4F02}\x{4F03}\x{4F04}\x{4F05}\x{4F06}' .
          '\x{4F08}\x{4F09}\x{4F0A}\x{4F0B}\x{4F0C}\x{4F0D}\x{4F0E}\x{4F0F}\x{4F10}' .
          '\x{4F11}\x{4F12}\x{4F13}\x{4F14}\x{4F15}\x{4F17}\x{4F18}\x{4F19}\x{4F1A}' .
          '\x{4F1B}\x{4F1C}\x{4F1D}\x{4F1E}\x{4F1F}\x{4F20}\x{4F21}\x{4F22}\x{4F23}' .
          '\x{4F24}\x{4F25}\x{4F26}\x{4F27}\x{4F29}\x{4F2A}\x{4F2B}\x{4F2C}\x{4F2D}' .
          '\x{4F2E}\x{4F2F}\x{4F30}\x{4F32}\x{4F33}\x{4F34}\x{4F36}\x{4F38}\x{4F39}' .
          '\x{4F3A}\x{4F3B}\x{4F3C}\x{4F3D}\x{4F3E}\x{4F3F}\x{4F41}\x{4F42}\x{4F43}' .
          '\x{4F45}\x{4F46}\x{4F47}\x{4F48}\x{4F49}\x{4F4A}\x{4F4B}\x{4F4C}\x{4F4D}' .
          '\x{4F4E}\x{4F4F}\x{4F50}\x{4F51}\x{4F52}\x{4F53}\x{4F54}\x{4F55}\x{4F56}' .
          '\x{4F57}\x{4F58}\x{4F59}\x{4F5A}\x{4F5B}\x{4F5C}\x{4F5D}\x{4F5E}\x{4F5F}' .
          '\x{4F60}\x{4F61}\x{4F62}\x{4F63}\x{4F64}\x{4F65}\x{4F66}\x{4F67}\x{4F68}' .
          '\x{4F69}\x{4F6A}\x{4F6B}\x{4F6C}\x{4F6D}\x{4F6E}\x{4F6F}\x{4F70}\x{4F72}' .
          '\x{4F73}\x{4F74}\x{4F75}\x{4F76}\x{4F77}\x{4F78}\x{4F79}\x{4F7A}\x{4F7B}' .
          '\x{4F7C}\x{4F7D}\x{4F7E}\x{4F7F}\x{4F80}\x{4F81}\x{4F82}\x{4F83}\x{4F84}' .
          '\x{4F85}\x{4F86}\x{4F87}\x{4F88}\x{4F89}\x{4F8A}\x{4F8B}\x{4F8D}\x{4F8F}' .
          '\x{4F90}\x{4F91}\x{4F92}\x{4F93}\x{4F94}\x{4F95}\x{4F96}\x{4F97}\x{4F98}' .
          '\x{4F99}\x{4F9A}\x{4F9B}\x{4F9C}\x{4F9D}\x{4F9E}\x{4F9F}\x{4FA0}\x{4FA1}' .
          '\x{4FA3}\x{4FA4}\x{4FA5}\x{4FA6}\x{4FA7}\x{4FA8}\x{4FA9}\x{4FAA}\x{4FAB}' .
          '\x{4FAC}\x{4FAE}\x{4FAF}\x{4FB0}\x{4FB1}\x{4FB2}\x{4FB3}\x{4FB4}\x{4FB5}' .
          '\x{4FB6}\x{4FB7}\x{4FB8}\x{4FB9}\x{4FBA}\x{4FBB}\x{4FBC}\x{4FBE}\x{4FBF}' .
          '\x{4FC0}\x{4FC1}\x{4FC2}\x{4FC3}\x{4FC4}\x{4FC5}\x{4FC7}\x{4FC9}\x{4FCA}' .
          '\x{4FCB}\x{4FCD}\x{4FCE}\x{4FCF}\x{4FD0}\x{4FD1}\x{4FD2}\x{4FD3}\x{4FD4}' .
          '\x{4FD5}\x{4FD6}\x{4FD7}\x{4FD8}\x{4FD9}\x{4FDA}\x{4FDB}\x{4FDC}\x{4FDD}' .
          '\x{4FDE}\x{4FDF}\x{4FE0}\x{4FE1}\x{4FE3}\x{4FE4}\x{4FE5}\x{4FE6}\x{4FE7}' .
          '\x{4FE8}\x{4FE9}\x{4FEA}\x{4FEB}\x{4FEC}\x{4FED}\x{4FEE}\x{4FEF}\x{4FF0}' .
          '\x{4FF1}\x{4FF2}\x{4FF3}\x{4FF4}\x{4FF5}\x{4FF6}\x{4FF7}\x{4FF8}\x{4FF9}' .
          '\x{4FFA}\x{4FFB}\x{4FFE}\x{4FFF}\x{5000}\x{5001}\x{5002}\x{5003}\x{5004}' .
          '\x{5005}\x{5006}\x{5007}\x{5008}\x{5009}\x{500A}\x{500B}\x{500C}\x{500D}' .
          '\x{500E}\x{500F}\x{5011}\x{5012}\x{5013}\x{5014}\x{5015}\x{5016}\x{5017}' .
          '\x{5018}\x{5019}\x{501A}\x{501B}\x{501C}\x{501D}\x{501E}\x{501F}\x{5020}' .
          '\x{5021}\x{5022}\x{5023}\x{5024}\x{5025}\x{5026}\x{5027}\x{5028}\x{5029}' .
          '\x{502A}\x{502B}\x{502C}\x{502D}\x{502E}\x{502F}\x{5030}\x{5031}\x{5032}' .
          '\x{5033}\x{5035}\x{5036}\x{5037}\x{5039}\x{503A}\x{503B}\x{503C}\x{503E}' .
          '\x{503F}\x{5040}\x{5041}\x{5043}\x{5044}\x{5045}\x{5046}\x{5047}\x{5048}' .
          '\x{5049}\x{504A}\x{504B}\x{504C}\x{504D}\x{504E}\x{504F}\x{5051}\x{5053}' .
          '\x{5054}\x{5055}\x{5056}\x{5057}\x{5059}\x{505A}\x{505B}\x{505C}\x{505D}' .
          '\x{505E}\x{505F}\x{5060}\x{5061}\x{5062}\x{5063}\x{5064}\x{5065}\x{5066}' .
          '\x{5067}\x{5068}\x{5069}\x{506A}\x{506B}\x{506C}\x{506D}\x{506E}\x{506F}' .
          '\x{5070}\x{5071}\x{5072}\x{5073}\x{5074}\x{5075}\x{5076}\x{5077}\x{5078}' .
          '\x{5079}\x{507A}\x{507B}\x{507D}\x{507E}\x{507F}\x{5080}\x{5082}\x{5083}' .
          '\x{5084}\x{5085}\x{5086}\x{5087}\x{5088}\x{5089}\x{508A}\x{508B}\x{508C}' .
          '\x{508D}\x{508E}\x{508F}\x{5090}\x{5091}\x{5092}\x{5094}\x{5095}\x{5096}' .
          '\x{5098}\x{5099}\x{509A}\x{509B}\x{509C}\x{509D}\x{509E}\x{50A2}\x{50A3}' .
          '\x{50A4}\x{50A5}\x{50A6}\x{50A7}\x{50A8}\x{50A9}\x{50AA}\x{50AB}\x{50AC}' .
          '\x{50AD}\x{50AE}\x{50AF}\x{50B0}\x{50B1}\x{50B2}\x{50B3}\x{50B4}\x{50B5}' .
          '\x{50B6}\x{50B7}\x{50B8}\x{50BA}\x{50BB}\x{50BC}\x{50BD}\x{50BE}\x{50BF}' .
          '\x{50C0}\x{50C1}\x{50C2}\x{50C4}\x{50C5}\x{50C6}\x{50C7}\x{50C8}\x{50C9}' .
          '\x{50CA}\x{50CB}\x{50CC}\x{50CD}\x{50CE}\x{50CF}\x{50D0}\x{50D1}\x{50D2}' .
          '\x{50D3}\x{50D4}\x{50D5}\x{50D6}\x{50D7}\x{50D9}\x{50DA}\x{50DB}\x{50DC}' .
          '\x{50DD}\x{50DE}\x{50E0}\x{50E3}\x{50E4}\x{50E5}\x{50E6}\x{50E7}\x{50E8}' .
          '\x{50E9}\x{50EA}\x{50EC}\x{50ED}\x{50EE}\x{50EF}\x{50F0}\x{50F1}\x{50F2}' .
          '\x{50F3}\x{50F5}\x{50F6}\x{50F8}\x{50F9}\x{50FA}\x{50FB}\x{50FC}\x{50FD}' .
          '\x{50FE}\x{50FF}\x{5100}\x{5101}\x{5102}\x{5103}\x{5104}\x{5105}\x{5106}' .
          '\x{5107}\x{5108}\x{5109}\x{510A}\x{510B}\x{510C}\x{510D}\x{510E}\x{510F}' .
          '\x{5110}\x{5111}\x{5112}\x{5113}\x{5114}\x{5115}\x{5116}\x{5117}\x{5118}' .
          '\x{5119}\x{511A}\x{511C}\x{511D}\x{511E}\x{511F}\x{5120}\x{5121}\x{5122}' .
          '\x{5123}\x{5124}\x{5125}\x{5126}\x{5127}\x{5129}\x{512A}\x{512C}\x{512D}' .
          '\x{512E}\x{512F}\x{5130}\x{5131}\x{5132}\x{5133}\x{5134}\x{5135}\x{5136}' .
          '\x{5137}\x{5138}\x{5139}\x{513A}\x{513B}\x{513C}\x{513D}\x{513E}\x{513F}' .
          '\x{5140}\x{5141}\x{5143}\x{5144}\x{5145}\x{5146}\x{5147}\x{5148}\x{5149}' .
          '\x{514B}\x{514C}\x{514D}\x{514E}\x{5150}\x{5151}\x{5152}\x{5154}\x{5155}' .
          '\x{5156}\x{5157}\x{5159}\x{515A}\x{515B}\x{515C}\x{515D}\x{515E}\x{515F}' .
          '\x{5161}\x{5162}\x{5163}\x{5165}\x{5166}\x{5167}\x{5168}\x{5169}\x{516A}' .
          '\x{516B}\x{516C}\x{516D}\x{516E}\x{516F}\x{5170}\x{5171}\x{5173}\x{5174}' .
          '\x{5175}\x{5176}\x{5177}\x{5178}\x{5179}\x{517A}\x{517B}\x{517C}\x{517D}' .
          '\x{517F}\x{5180}\x{5181}\x{5182}\x{5185}\x{5186}\x{5187}\x{5188}\x{5189}' .
          '\x{518A}\x{518B}\x{518C}\x{518D}\x{518F}\x{5190}\x{5191}\x{5192}\x{5193}' .
          '\x{5194}\x{5195}\x{5196}\x{5197}\x{5198}\x{5199}\x{519A}\x{519B}\x{519C}' .
          '\x{519D}\x{519E}\x{519F}\x{51A0}\x{51A2}\x{51A4}\x{51A5}\x{51A6}\x{51A7}' .
          '\x{51A8}\x{51AA}\x{51AB}\x{51AC}\x{51AE}\x{51AF}\x{51B0}\x{51B1}\x{51B2}' .
          '\x{51B3}\x{51B5}\x{51B6}\x{51B7}\x{51B9}\x{51BB}\x{51BC}\x{51BD}\x{51BE}' .
          '\x{51BF}\x{51C0}\x{51C1}\x{51C3}\x{51C4}\x{51C5}\x{51C6}\x{51C7}\x{51C8}' .
          '\x{51C9}\x{51CA}\x{51CB}\x{51CC}\x{51CD}\x{51CE}\x{51CF}\x{51D0}\x{51D1}' .
          '\x{51D4}\x{51D5}\x{51D6}\x{51D7}\x{51D8}\x{51D9}\x{51DA}\x{51DB}\x{51DC}' .
          '\x{51DD}\x{51DE}\x{51E0}\x{51E1}\x{51E2}\x{51E3}\x{51E4}\x{51E5}\x{51E7}' .
          '\x{51E8}\x{51E9}\x{51EA}\x{51EB}\x{51ED}\x{51EF}\x{51F0}\x{51F1}\x{51F3}' .
          '\x{51F4}\x{51F5}\x{51F6}\x{51F7}\x{51F8}\x{51F9}\x{51FA}\x{51FB}\x{51FC}' .
          '\x{51FD}\x{51FE}\x{51FF}\x{5200}\x{5201}\x{5202}\x{5203}\x{5204}\x{5205}' .
          '\x{5206}\x{5207}\x{5208}\x{5209}\x{520A}\x{520B}\x{520C}\x{520D}\x{520E}' .
          '\x{520F}\x{5210}\x{5211}\x{5212}\x{5213}\x{5214}\x{5215}\x{5216}\x{5217}' .
          '\x{5218}\x{5219}\x{521A}\x{521B}\x{521C}\x{521D}\x{521E}\x{521F}\x{5220}' .
          '\x{5221}\x{5222}\x{5223}\x{5224}\x{5225}\x{5226}\x{5228}\x{5229}\x{522A}' .
          '\x{522B}\x{522C}\x{522D}\x{522E}\x{522F}\x{5230}\x{5231}\x{5232}\x{5233}' .
          '\x{5234}\x{5235}\x{5236}\x{5237}\x{5238}\x{5239}\x{523A}\x{523B}\x{523C}' .
          '\x{523D}\x{523E}\x{523F}\x{5240}\x{5241}\x{5242}\x{5243}\x{5244}\x{5245}' .
          '\x{5246}\x{5247}\x{5248}\x{5249}\x{524A}\x{524B}\x{524C}\x{524D}\x{524E}' .
          '\x{5250}\x{5251}\x{5252}\x{5254}\x{5255}\x{5256}\x{5257}\x{5258}\x{5259}' .
          '\x{525A}\x{525B}\x{525C}\x{525D}\x{525E}\x{525F}\x{5260}\x{5261}\x{5262}' .
          '\x{5263}\x{5264}\x{5265}\x{5267}\x{5268}\x{5269}\x{526A}\x{526B}\x{526C}' .
          '\x{526D}\x{526E}\x{526F}\x{5270}\x{5272}\x{5273}\x{5274}\x{5275}\x{5276}' .
          '\x{5277}\x{5278}\x{527A}\x{527B}\x{527C}\x{527D}\x{527E}\x{527F}\x{5280}' .
          '\x{5281}\x{5282}\x{5283}\x{5284}\x{5286}\x{5287}\x{5288}\x{5289}\x{528A}' .
          '\x{528B}\x{528C}\x{528D}\x{528F}\x{5290}\x{5291}\x{5292}\x{5293}\x{5294}' .
          '\x{5295}\x{5296}\x{5297}\x{5298}\x{5299}\x{529A}\x{529B}\x{529C}\x{529D}' .
          '\x{529E}\x{529F}\x{52A0}\x{52A1}\x{52A2}\x{52A3}\x{52A5}\x{52A6}\x{52A7}' .
          '\x{52A8}\x{52A9}\x{52AA}\x{52AB}\x{52AC}\x{52AD}\x{52AE}\x{52AF}\x{52B0}' .
          '\x{52B1}\x{52B2}\x{52B3}\x{52B4}\x{52B5}\x{52B6}\x{52B7}\x{52B8}\x{52B9}' .
          '\x{52BA}\x{52BB}\x{52BC}\x{52BD}\x{52BE}\x{52BF}\x{52C0}\x{52C1}\x{52C2}' .
          '\x{52C3}\x{52C6}\x{52C7}\x{52C9}\x{52CA}\x{52CB}\x{52CD}\x{52CF}\x{52D0}' .
          '\x{52D2}\x{52D3}\x{52D5}\x{52D6}\x{52D7}\x{52D8}\x{52D9}\x{52DA}\x{52DB}' .
          '\x{52DC}\x{52DD}\x{52DE}\x{52DF}\x{52E0}\x{52E2}\x{52E3}\x{52E4}\x{52E6}' .
          '\x{52E7}\x{52E8}\x{52E9}\x{52EA}\x{52EB}\x{52EC}\x{52ED}\x{52EF}\x{52F0}' .
          '\x{52F1}\x{52F2}\x{52F3}\x{52F4}\x{52F5}\x{52F6}\x{52F7}\x{52F8}\x{52F9}' .
          '\x{52FA}\x{52FB}\x{52FC}\x{52FD}\x{52FE}\x{52FF}\x{5300}\x{5301}\x{5302}' .
          '\x{5305}\x{5306}\x{5307}\x{5308}\x{5309}\x{530A}\x{530B}\x{530C}\x{530D}' .
          '\x{530E}\x{530F}\x{5310}\x{5311}\x{5312}\x{5313}\x{5314}\x{5315}\x{5316}' .
          '\x{5317}\x{5319}\x{531A}\x{531C}\x{531D}\x{531F}\x{5320}\x{5321}\x{5322}' .
          '\x{5323}\x{5324}\x{5325}\x{5326}\x{5328}\x{532A}\x{532B}\x{532C}\x{532D}' .
          '\x{532E}\x{532F}\x{5330}\x{5331}\x{5333}\x{5334}\x{5337}\x{5339}\x{533A}' .
          '\x{533B}\x{533C}\x{533D}\x{533E}\x{533F}\x{5340}\x{5341}\x{5343}\x{5344}' .
          '\x{5345}\x{5346}\x{5347}\x{5348}\x{5349}\x{534A}\x{534B}\x{534C}\x{534D}' .
          '\x{534E}\x{534F}\x{5350}\x{5351}\x{5352}\x{5353}\x{5354}\x{5355}\x{5356}' .
          '\x{5357}\x{5358}\x{5359}\x{535A}\x{535C}\x{535E}\x{535F}\x{5360}\x{5361}' .
          '\x{5362}\x{5363}\x{5364}\x{5365}\x{5366}\x{5367}\x{5369}\x{536B}\x{536C}' .
          '\x{536E}\x{536F}\x{5370}\x{5371}\x{5372}\x{5373}\x{5374}\x{5375}\x{5376}' .
          '\x{5377}\x{5378}\x{5379}\x{537A}\x{537B}\x{537C}\x{537D}\x{537E}\x{537F}' .
          '\x{5381}\x{5382}\x{5383}\x{5384}\x{5385}\x{5386}\x{5387}\x{5388}\x{5389}' .
          '\x{538A}\x{538B}\x{538C}\x{538D}\x{538E}\x{538F}\x{5390}\x{5391}\x{5392}' .
          '\x{5393}\x{5394}\x{5395}\x{5396}\x{5397}\x{5398}\x{5399}\x{539A}\x{539B}' .
          '\x{539C}\x{539D}\x{539E}\x{539F}\x{53A0}\x{53A2}\x{53A3}\x{53A4}\x{53A5}' .
          '\x{53A6}\x{53A7}\x{53A8}\x{53A9}\x{53AC}\x{53AD}\x{53AE}\x{53B0}\x{53B1}' .
          '\x{53B2}\x{53B3}\x{53B4}\x{53B5}\x{53B6}\x{53B7}\x{53B8}\x{53B9}\x{53BB}' .
          '\x{53BC}\x{53BD}\x{53BE}\x{53BF}\x{53C0}\x{53C1}\x{53C2}\x{53C3}\x{53C4}' .
          '\x{53C6}\x{53C7}\x{53C8}\x{53C9}\x{53CA}\x{53CB}\x{53CC}\x{53CD}\x{53CE}' .
          '\x{53D0}\x{53D1}\x{53D2}\x{53D3}\x{53D4}\x{53D5}\x{53D6}\x{53D7}\x{53D8}' .
          '\x{53D9}\x{53DB}\x{53DC}\x{53DF}\x{53E0}\x{53E1}\x{53E2}\x{53E3}\x{53E4}' .
          '\x{53E5}\x{53E6}\x{53E8}\x{53E9}\x{53EA}\x{53EB}\x{53EC}\x{53ED}\x{53EE}' .
          '\x{53EF}\x{53F0}\x{53F1}\x{53F2}\x{53F3}\x{53F4}\x{53F5}\x{53F6}\x{53F7}' .
          '\x{53F8}\x{53F9}\x{53FA}\x{53FB}\x{53FC}\x{53FD}\x{53FE}\x{5401}\x{5402}' .
          '\x{5403}\x{5404}\x{5405}\x{5406}\x{5407}\x{5408}\x{5409}\x{540A}\x{540B}' .
          '\x{540C}\x{540D}\x{540E}\x{540F}\x{5410}\x{5411}\x{5412}\x{5413}\x{5414}' .
          '\x{5415}\x{5416}\x{5417}\x{5418}\x{5419}\x{541B}\x{541C}\x{541D}\x{541E}' .
          '\x{541F}\x{5420}\x{5421}\x{5423}\x{5424}\x{5425}\x{5426}\x{5427}\x{5428}' .
          '\x{5429}\x{542A}\x{542B}\x{542C}\x{542D}\x{542E}\x{542F}\x{5430}\x{5431}' .
          '\x{5432}\x{5433}\x{5434}\x{5435}\x{5436}\x{5437}\x{5438}\x{5439}\x{543A}' .
          '\x{543B}\x{543C}\x{543D}\x{543E}\x{543F}\x{5440}\x{5441}\x{5442}\x{5443}' .
          '\x{5444}\x{5445}\x{5446}\x{5447}\x{5448}\x{5449}\x{544A}\x{544B}\x{544D}' .
          '\x{544E}\x{544F}\x{5450}\x{5451}\x{5452}\x{5453}\x{5454}\x{5455}\x{5456}' .
          '\x{5457}\x{5458}\x{5459}\x{545A}\x{545B}\x{545C}\x{545E}\x{545F}\x{5460}' .
          '\x{5461}\x{5462}\x{5463}\x{5464}\x{5465}\x{5466}\x{5467}\x{5468}\x{546A}' .
          '\x{546B}\x{546C}\x{546D}\x{546E}\x{546F}\x{5470}\x{5471}\x{5472}\x{5473}' .
          '\x{5474}\x{5475}\x{5476}\x{5477}\x{5478}\x{5479}\x{547A}\x{547B}\x{547C}' .
          '\x{547D}\x{547E}\x{547F}\x{5480}\x{5481}\x{5482}\x{5483}\x{5484}\x{5485}' .
          '\x{5486}\x{5487}\x{5488}\x{5489}\x{548B}\x{548C}\x{548D}\x{548E}\x{548F}' .
          '\x{5490}\x{5491}\x{5492}\x{5493}\x{5494}\x{5495}\x{5496}\x{5497}\x{5498}' .
          '\x{5499}\x{549A}\x{549B}\x{549C}\x{549D}\x{549E}\x{549F}\x{54A0}\x{54A1}' .
          '\x{54A2}\x{54A3}\x{54A4}\x{54A5}\x{54A6}\x{54A7}\x{54A8}\x{54A9}\x{54AA}' .
          '\x{54AB}\x{54AC}\x{54AD}\x{54AE}\x{54AF}\x{54B0}\x{54B1}\x{54B2}\x{54B3}' .
          '\x{54B4}\x{54B6}\x{54B7}\x{54B8}\x{54B9}\x{54BA}\x{54BB}\x{54BC}\x{54BD}' .
          '\x{54BE}\x{54BF}\x{54C0}\x{54C1}\x{54C2}\x{54C3}\x{54C4}\x{54C5}\x{54C6}' .
          '\x{54C7}\x{54C8}\x{54C9}\x{54CA}\x{54CB}\x{54CC}\x{54CD}\x{54CE}\x{54CF}' .
          '\x{54D0}\x{54D1}\x{54D2}\x{54D3}\x{54D4}\x{54D5}\x{54D6}\x{54D7}\x{54D8}' .
          '\x{54D9}\x{54DA}\x{54DB}\x{54DC}\x{54DD}\x{54DE}\x{54DF}\x{54E0}\x{54E1}' .
          '\x{54E2}\x{54E3}\x{54E4}\x{54E5}\x{54E6}\x{54E7}\x{54E8}\x{54E9}\x{54EA}' .
          '\x{54EB}\x{54EC}\x{54ED}\x{54EE}\x{54EF}\x{54F0}\x{54F1}\x{54F2}\x{54F3}' .
          '\x{54F4}\x{54F5}\x{54F7}\x{54F8}\x{54F9}\x{54FA}\x{54FB}\x{54FC}\x{54FD}' .
          '\x{54FE}\x{54FF}\x{5500}\x{5501}\x{5502}\x{5503}\x{5504}\x{5505}\x{5506}' .
          '\x{5507}\x{5508}\x{5509}\x{550A}\x{550B}\x{550C}\x{550D}\x{550E}\x{550F}' .
          '\x{5510}\x{5511}\x{5512}\x{5513}\x{5514}\x{5516}\x{5517}\x{551A}\x{551B}' .
          '\x{551C}\x{551D}\x{551E}\x{551F}\x{5520}\x{5521}\x{5522}\x{5523}\x{5524}' .
          '\x{5525}\x{5526}\x{5527}\x{5528}\x{5529}\x{552A}\x{552B}\x{552C}\x{552D}' .
          '\x{552E}\x{552F}\x{5530}\x{5531}\x{5532}\x{5533}\x{5534}\x{5535}\x{5536}' .
          '\x{5537}\x{5538}\x{5539}\x{553A}\x{553B}\x{553C}\x{553D}\x{553E}\x{553F}' .
          '\x{5540}\x{5541}\x{5542}\x{5543}\x{5544}\x{5545}\x{5546}\x{5548}\x{5549}' .
          '\x{554A}\x{554B}\x{554C}\x{554D}\x{554E}\x{554F}\x{5550}\x{5551}\x{5552}' .
          '\x{5553}\x{5554}\x{5555}\x{5556}\x{5557}\x{5558}\x{5559}\x{555A}\x{555B}' .
          '\x{555C}\x{555D}\x{555E}\x{555F}\x{5561}\x{5562}\x{5563}\x{5564}\x{5565}' .
          '\x{5566}\x{5567}\x{5568}\x{5569}\x{556A}\x{556B}\x{556C}\x{556D}\x{556E}' .
          '\x{556F}\x{5570}\x{5571}\x{5572}\x{5573}\x{5574}\x{5575}\x{5576}\x{5577}' .
          '\x{5578}\x{5579}\x{557B}\x{557C}\x{557D}\x{557E}\x{557F}\x{5580}\x{5581}' .
          '\x{5582}\x{5583}\x{5584}\x{5585}\x{5586}\x{5587}\x{5588}\x{5589}\x{558A}' .
          '\x{558B}\x{558C}\x{558D}\x{558E}\x{558F}\x{5590}\x{5591}\x{5592}\x{5593}' .
          '\x{5594}\x{5595}\x{5596}\x{5597}\x{5598}\x{5599}\x{559A}\x{559B}\x{559C}' .
          '\x{559D}\x{559E}\x{559F}\x{55A0}\x{55A1}\x{55A2}\x{55A3}\x{55A4}\x{55A5}' .
          '\x{55A6}\x{55A7}\x{55A8}\x{55A9}\x{55AA}\x{55AB}\x{55AC}\x{55AD}\x{55AE}' .
          '\x{55AF}\x{55B0}\x{55B1}\x{55B2}\x{55B3}\x{55B4}\x{55B5}\x{55B6}\x{55B7}' .
          '\x{55B8}\x{55B9}\x{55BA}\x{55BB}\x{55BC}\x{55BD}\x{55BE}\x{55BF}\x{55C0}' .
          '\x{55C1}\x{55C2}\x{55C3}\x{55C4}\x{55C5}\x{55C6}\x{55C7}\x{55C8}\x{55C9}' .
          '\x{55CA}\x{55CB}\x{55CC}\x{55CD}\x{55CE}\x{55CF}\x{55D0}\x{55D1}\x{55D2}' .
          '\x{55D3}\x{55D4}\x{55D5}\x{55D6}\x{55D7}\x{55D8}\x{55D9}\x{55DA}\x{55DB}' .
          '\x{55DC}\x{55DD}\x{55DE}\x{55DF}\x{55E1}\x{55E2}\x{55E3}\x{55E4}\x{55E5}' .
          '\x{55E6}\x{55E7}\x{55E8}\x{55E9}\x{55EA}\x{55EB}\x{55EC}\x{55ED}\x{55EE}' .
          '\x{55EF}\x{55F0}\x{55F1}\x{55F2}\x{55F3}\x{55F4}\x{55F5}\x{55F6}\x{55F7}' .
          '\x{55F9}\x{55FA}\x{55FB}\x{55FC}\x{55FD}\x{55FE}\x{55FF}\x{5600}\x{5601}' .
          '\x{5602}\x{5603}\x{5604}\x{5606}\x{5607}\x{5608}\x{5609}\x{560C}\x{560D}' .
          '\x{560E}\x{560F}\x{5610}\x{5611}\x{5612}\x{5613}\x{5614}\x{5615}\x{5616}' .
          '\x{5617}\x{5618}\x{5619}\x{561A}\x{561B}\x{561C}\x{561D}\x{561E}\x{561F}' .
          '\x{5621}\x{5622}\x{5623}\x{5624}\x{5625}\x{5626}\x{5627}\x{5628}\x{5629}' .
          '\x{562A}\x{562C}\x{562D}\x{562E}\x{562F}\x{5630}\x{5631}\x{5632}\x{5633}' .
          '\x{5634}\x{5635}\x{5636}\x{5638}\x{5639}\x{563A}\x{563B}\x{563D}\x{563E}' .
          '\x{563F}\x{5640}\x{5641}\x{5642}\x{5643}\x{5645}\x{5646}\x{5647}\x{5648}' .
          '\x{5649}\x{564A}\x{564C}\x{564D}\x{564E}\x{564F}\x{5650}\x{5652}\x{5653}' .
          '\x{5654}\x{5655}\x{5657}\x{5658}\x{5659}\x{565A}\x{565B}\x{565C}\x{565D}' .
          '\x{565E}\x{5660}\x{5662}\x{5663}\x{5664}\x{5665}\x{5666}\x{5667}\x{5668}' .
          '\x{5669}\x{566A}\x{566B}\x{566C}\x{566D}\x{566E}\x{566F}\x{5670}\x{5671}' .
          '\x{5672}\x{5673}\x{5674}\x{5676}\x{5677}\x{5678}\x{5679}\x{567A}\x{567B}' .
          '\x{567C}\x{567E}\x{567F}\x{5680}\x{5681}\x{5682}\x{5683}\x{5684}\x{5685}' .
          '\x{5686}\x{5687}\x{568A}\x{568C}\x{568D}\x{568E}\x{568F}\x{5690}\x{5691}' .
          '\x{5692}\x{5693}\x{5694}\x{5695}\x{5697}\x{5698}\x{5699}\x{569A}\x{569B}' .
          '\x{569C}\x{569D}\x{569F}\x{56A0}\x{56A1}\x{56A3}\x{56A4}\x{56A5}\x{56A6}' .
          '\x{56A7}\x{56A8}\x{56A9}\x{56AA}\x{56AB}\x{56AC}\x{56AD}\x{56AE}\x{56AF}' .
          '\x{56B0}\x{56B1}\x{56B2}\x{56B3}\x{56B4}\x{56B5}\x{56B6}\x{56B7}\x{56B8}' .
          '\x{56B9}\x{56BB}\x{56BC}\x{56BD}\x{56BE}\x{56BF}\x{56C0}\x{56C1}\x{56C2}' .
          '\x{56C3}\x{56C4}\x{56C5}\x{56C6}\x{56C7}\x{56C8}\x{56C9}\x{56CA}\x{56CB}' .
          '\x{56CC}\x{56CD}\x{56CE}\x{56D0}\x{56D1}\x{56D2}\x{56D3}\x{56D4}\x{56D5}' .
          '\x{56D6}\x{56D7}\x{56D8}\x{56DA}\x{56DB}\x{56DC}\x{56DD}\x{56DE}\x{56DF}' .
          '\x{56E0}\x{56E1}\x{56E2}\x{56E3}\x{56E4}\x{56E5}\x{56E7}\x{56E8}\x{56E9}' .
          '\x{56EA}\x{56EB}\x{56EC}\x{56ED}\x{56EE}\x{56EF}\x{56F0}\x{56F1}\x{56F2}' .
          '\x{56F3}\x{56F4}\x{56F5}\x{56F7}\x{56F9}\x{56FA}\x{56FD}\x{56FE}\x{56FF}' .
          '\x{5700}\x{5701}\x{5702}\x{5703}\x{5704}\x{5706}\x{5707}\x{5708}\x{5709}' .
          '\x{570A}\x{570B}\x{570C}\x{570D}\x{570E}\x{570F}\x{5710}\x{5712}\x{5713}' .
          '\x{5714}\x{5715}\x{5716}\x{5718}\x{5719}\x{571A}\x{571B}\x{571C}\x{571D}' .
          '\x{571E}\x{571F}\x{5720}\x{5722}\x{5723}\x{5725}\x{5726}\x{5727}\x{5728}' .
          '\x{5729}\x{572A}\x{572B}\x{572C}\x{572D}\x{572E}\x{572F}\x{5730}\x{5731}' .
          '\x{5732}\x{5733}\x{5734}\x{5735}\x{5736}\x{5737}\x{5738}\x{5739}\x{573A}' .
          '\x{573B}\x{573C}\x{573E}\x{573F}\x{5740}\x{5741}\x{5742}\x{5744}\x{5745}' .
          '\x{5746}\x{5747}\x{5749}\x{574A}\x{574B}\x{574C}\x{574D}\x{574E}\x{574F}' .
          '\x{5750}\x{5751}\x{5752}\x{5753}\x{5754}\x{5757}\x{5759}\x{575A}\x{575B}' .
          '\x{575C}\x{575D}\x{575E}\x{575F}\x{5760}\x{5761}\x{5762}\x{5764}\x{5765}' .
          '\x{5766}\x{5767}\x{5768}\x{5769}\x{576A}\x{576B}\x{576C}\x{576D}\x{576F}' .
          '\x{5770}\x{5771}\x{5772}\x{5773}\x{5774}\x{5775}\x{5776}\x{5777}\x{5779}' .
          '\x{577A}\x{577B}\x{577C}\x{577D}\x{577E}\x{577F}\x{5780}\x{5782}\x{5783}' .
          '\x{5784}\x{5785}\x{5786}\x{5788}\x{5789}\x{578A}\x{578B}\x{578C}\x{578D}' .
          '\x{578E}\x{578F}\x{5790}\x{5791}\x{5792}\x{5793}\x{5794}\x{5795}\x{5797}' .
          '\x{5798}\x{5799}\x{579A}\x{579B}\x{579C}\x{579D}\x{579E}\x{579F}\x{57A0}' .
          '\x{57A1}\x{57A2}\x{57A3}\x{57A4}\x{57A5}\x{57A6}\x{57A7}\x{57A9}\x{57AA}' .
          '\x{57AB}\x{57AC}\x{57AD}\x{57AE}\x{57AF}\x{57B0}\x{57B1}\x{57B2}\x{57B3}' .
          '\x{57B4}\x{57B5}\x{57B6}\x{57B7}\x{57B8}\x{57B9}\x{57BA}\x{57BB}\x{57BC}' .
          '\x{57BD}\x{57BE}\x{57BF}\x{57C0}\x{57C1}\x{57C2}\x{57C3}\x{57C4}\x{57C5}' .
          '\x{57C6}\x{57C7}\x{57C8}\x{57C9}\x{57CB}\x{57CC}\x{57CD}\x{57CE}\x{57CF}' .
          '\x{57D0}\x{57D2}\x{57D3}\x{57D4}\x{57D5}\x{57D6}\x{57D8}\x{57D9}\x{57DA}' .
          '\x{57DC}\x{57DD}\x{57DF}\x{57E0}\x{57E1}\x{57E2}\x{57E3}\x{57E4}\x{57E5}' .
          '\x{57E6}\x{57E7}\x{57E8}\x{57E9}\x{57EA}\x{57EB}\x{57EC}\x{57ED}\x{57EE}' .
          '\x{57EF}\x{57F0}\x{57F1}\x{57F2}\x{57F3}\x{57F4}\x{57F5}\x{57F6}\x{57F7}' .
          '\x{57F8}\x{57F9}\x{57FA}\x{57FB}\x{57FC}\x{57FD}\x{57FE}\x{57FF}\x{5800}' .
          '\x{5801}\x{5802}\x{5803}\x{5804}\x{5805}\x{5806}\x{5807}\x{5808}\x{5809}' .
          '\x{580A}\x{580B}\x{580C}\x{580D}\x{580E}\x{580F}\x{5810}\x{5811}\x{5812}' .
          '\x{5813}\x{5814}\x{5815}\x{5816}\x{5819}\x{581A}\x{581B}\x{581C}\x{581D}' .
          '\x{581E}\x{581F}\x{5820}\x{5821}\x{5822}\x{5823}\x{5824}\x{5825}\x{5826}' .
          '\x{5827}\x{5828}\x{5829}\x{582A}\x{582B}\x{582C}\x{582D}\x{582E}\x{582F}' .
          '\x{5830}\x{5831}\x{5832}\x{5833}\x{5834}\x{5835}\x{5836}\x{5837}\x{5838}' .
          '\x{5839}\x{583A}\x{583B}\x{583C}\x{583D}\x{583E}\x{583F}\x{5840}\x{5842}' .
          '\x{5843}\x{5844}\x{5845}\x{5846}\x{5847}\x{5848}\x{5849}\x{584A}\x{584B}' .
          '\x{584C}\x{584D}\x{584E}\x{584F}\x{5851}\x{5852}\x{5853}\x{5854}\x{5855}' .
          '\x{5857}\x{5858}\x{5859}\x{585A}\x{585B}\x{585C}\x{585D}\x{585E}\x{585F}' .
          '\x{5861}\x{5862}\x{5863}\x{5864}\x{5865}\x{5868}\x{5869}\x{586A}\x{586B}' .
          '\x{586C}\x{586D}\x{586E}\x{586F}\x{5870}\x{5871}\x{5872}\x{5873}\x{5874}' .
          '\x{5875}\x{5876}\x{5878}\x{5879}\x{587A}\x{587B}\x{587C}\x{587D}\x{587E}' .
          '\x{587F}\x{5880}\x{5881}\x{5882}\x{5883}\x{5884}\x{5885}\x{5886}\x{5887}' .
          '\x{5888}\x{5889}\x{588A}\x{588B}\x{588C}\x{588D}\x{588E}\x{588F}\x{5890}' .
          '\x{5891}\x{5892}\x{5893}\x{5894}\x{5896}\x{5897}\x{5898}\x{5899}\x{589A}' .
          '\x{589B}\x{589C}\x{589D}\x{589E}\x{589F}\x{58A0}\x{58A1}\x{58A2}\x{58A3}' .
          '\x{58A4}\x{58A5}\x{58A6}\x{58A7}\x{58A8}\x{58A9}\x{58AB}\x{58AC}\x{58AD}' .
          '\x{58AE}\x{58AF}\x{58B0}\x{58B1}\x{58B2}\x{58B3}\x{58B4}\x{58B7}\x{58B8}' .
          '\x{58B9}\x{58BA}\x{58BB}\x{58BC}\x{58BD}\x{58BE}\x{58BF}\x{58C1}\x{58C2}' .
          '\x{58C5}\x{58C6}\x{58C7}\x{58C8}\x{58C9}\x{58CA}\x{58CB}\x{58CE}\x{58CF}' .
          '\x{58D1}\x{58D2}\x{58D3}\x{58D4}\x{58D5}\x{58D6}\x{58D7}\x{58D8}\x{58D9}' .
          '\x{58DA}\x{58DB}\x{58DD}\x{58DE}\x{58DF}\x{58E0}\x{58E2}\x{58E3}\x{58E4}' .
          '\x{58E5}\x{58E7}\x{58E8}\x{58E9}\x{58EA}\x{58EB}\x{58EC}\x{58ED}\x{58EE}' .
          '\x{58EF}\x{58F0}\x{58F1}\x{58F2}\x{58F3}\x{58F4}\x{58F6}\x{58F7}\x{58F8}' .
          '\x{58F9}\x{58FA}\x{58FB}\x{58FC}\x{58FD}\x{58FE}\x{58FF}\x{5900}\x{5902}' .
          '\x{5903}\x{5904}\x{5906}\x{5907}\x{5909}\x{590A}\x{590B}\x{590C}\x{590D}' .
          '\x{590E}\x{590F}\x{5910}\x{5912}\x{5914}\x{5915}\x{5916}\x{5917}\x{5918}' .
          '\x{5919}\x{591A}\x{591B}\x{591C}\x{591D}\x{591E}\x{591F}\x{5920}\x{5921}' .
          '\x{5922}\x{5924}\x{5925}\x{5926}\x{5927}\x{5928}\x{5929}\x{592A}\x{592B}' .
          '\x{592C}\x{592D}\x{592E}\x{592F}\x{5930}\x{5931}\x{5932}\x{5934}\x{5935}' .
          '\x{5937}\x{5938}\x{5939}\x{593A}\x{593B}\x{593C}\x{593D}\x{593E}\x{593F}' .
          '\x{5940}\x{5941}\x{5942}\x{5943}\x{5944}\x{5945}\x{5946}\x{5947}\x{5948}' .
          '\x{5949}\x{594A}\x{594B}\x{594C}\x{594D}\x{594E}\x{594F}\x{5950}\x{5951}' .
          '\x{5952}\x{5953}\x{5954}\x{5955}\x{5956}\x{5957}\x{5958}\x{595A}\x{595C}' .
          '\x{595D}\x{595E}\x{595F}\x{5960}\x{5961}\x{5962}\x{5963}\x{5964}\x{5965}' .
          '\x{5966}\x{5967}\x{5968}\x{5969}\x{596A}\x{596B}\x{596C}\x{596D}\x{596E}' .
          '\x{596F}\x{5970}\x{5971}\x{5972}\x{5973}\x{5974}\x{5975}\x{5976}\x{5977}' .
          '\x{5978}\x{5979}\x{597A}\x{597B}\x{597C}\x{597D}\x{597E}\x{597F}\x{5980}' .
          '\x{5981}\x{5982}\x{5983}\x{5984}\x{5985}\x{5986}\x{5987}\x{5988}\x{5989}' .
          '\x{598A}\x{598B}\x{598C}\x{598D}\x{598E}\x{598F}\x{5990}\x{5991}\x{5992}' .
          '\x{5993}\x{5994}\x{5995}\x{5996}\x{5997}\x{5998}\x{5999}\x{599A}\x{599C}' .
          '\x{599D}\x{599E}\x{599F}\x{59A0}\x{59A1}\x{59A2}\x{59A3}\x{59A4}\x{59A5}' .
          '\x{59A6}\x{59A7}\x{59A8}\x{59A9}\x{59AA}\x{59AB}\x{59AC}\x{59AD}\x{59AE}' .
          '\x{59AF}\x{59B0}\x{59B1}\x{59B2}\x{59B3}\x{59B4}\x{59B5}\x{59B6}\x{59B8}' .
          '\x{59B9}\x{59BA}\x{59BB}\x{59BC}\x{59BD}\x{59BE}\x{59BF}\x{59C0}\x{59C1}' .
          '\x{59C2}\x{59C3}\x{59C4}\x{59C5}\x{59C6}\x{59C7}\x{59C8}\x{59C9}\x{59CA}' .
          '\x{59CB}\x{59CC}\x{59CD}\x{59CE}\x{59CF}\x{59D0}\x{59D1}\x{59D2}\x{59D3}' .
          '\x{59D4}\x{59D5}\x{59D6}\x{59D7}\x{59D8}\x{59D9}\x{59DA}\x{59DB}\x{59DC}' .
          '\x{59DD}\x{59DE}\x{59DF}\x{59E0}\x{59E1}\x{59E2}\x{59E3}\x{59E4}\x{59E5}' .
          '\x{59E6}\x{59E8}\x{59E9}\x{59EA}\x{59EB}\x{59EC}\x{59ED}\x{59EE}\x{59EF}' .
          '\x{59F0}\x{59F1}\x{59F2}\x{59F3}\x{59F4}\x{59F5}\x{59F6}\x{59F7}\x{59F8}' .
          '\x{59F9}\x{59FA}\x{59FB}\x{59FC}\x{59FD}\x{59FE}\x{59FF}\x{5A00}\x{5A01}' .
          '\x{5A02}\x{5A03}\x{5A04}\x{5A05}\x{5A06}\x{5A07}\x{5A08}\x{5A09}\x{5A0A}' .
          '\x{5A0B}\x{5A0C}\x{5A0D}\x{5A0E}\x{5A0F}\x{5A10}\x{5A11}\x{5A12}\x{5A13}' .
          '\x{5A14}\x{5A15}\x{5A16}\x{5A17}\x{5A18}\x{5A19}\x{5A1A}\x{5A1B}\x{5A1C}' .
          '\x{5A1D}\x{5A1E}\x{5A1F}\x{5A20}\x{5A21}\x{5A22}\x{5A23}\x{5A25}\x{5A27}' .
          '\x{5A28}\x{5A29}\x{5A2A}\x{5A2B}\x{5A2D}\x{5A2E}\x{5A2F}\x{5A31}\x{5A32}' .
          '\x{5A33}\x{5A34}\x{5A35}\x{5A36}\x{5A37}\x{5A38}\x{5A39}\x{5A3A}\x{5A3B}' .
          '\x{5A3C}\x{5A3D}\x{5A3E}\x{5A3F}\x{5A40}\x{5A41}\x{5A42}\x{5A43}\x{5A44}' .
          '\x{5A45}\x{5A46}\x{5A47}\x{5A48}\x{5A49}\x{5A4A}\x{5A4B}\x{5A4C}\x{5A4D}' .
          '\x{5A4E}\x{5A4F}\x{5A50}\x{5A51}\x{5A52}\x{5A53}\x{5A55}\x{5A56}\x{5A57}' .
          '\x{5A58}\x{5A5A}\x{5A5B}\x{5A5C}\x{5A5D}\x{5A5E}\x{5A5F}\x{5A60}\x{5A61}' .
          '\x{5A62}\x{5A63}\x{5A64}\x{5A65}\x{5A66}\x{5A67}\x{5A68}\x{5A69}\x{5A6A}' .
          '\x{5A6B}\x{5A6C}\x{5A6D}\x{5A6E}\x{5A70}\x{5A72}\x{5A73}\x{5A74}\x{5A75}' .
          '\x{5A76}\x{5A77}\x{5A78}\x{5A79}\x{5A7A}\x{5A7B}\x{5A7C}\x{5A7D}\x{5A7E}' .
          '\x{5A7F}\x{5A80}\x{5A81}\x{5A82}\x{5A83}\x{5A84}\x{5A85}\x{5A86}\x{5A88}' .
          '\x{5A89}\x{5A8A}\x{5A8B}\x{5A8C}\x{5A8E}\x{5A8F}\x{5A90}\x{5A91}\x{5A92}' .
          '\x{5A93}\x{5A94}\x{5A95}\x{5A96}\x{5A97}\x{5A98}\x{5A99}\x{5A9A}\x{5A9B}' .
          '\x{5A9C}\x{5A9D}\x{5A9E}\x{5A9F}\x{5AA0}\x{5AA1}\x{5AA2}\x{5AA3}\x{5AA4}' .
          '\x{5AA5}\x{5AA6}\x{5AA7}\x{5AA8}\x{5AA9}\x{5AAA}\x{5AAC}\x{5AAD}\x{5AAE}' .
          '\x{5AAF}\x{5AB0}\x{5AB1}\x{5AB2}\x{5AB3}\x{5AB4}\x{5AB5}\x{5AB6}\x{5AB7}' .
          '\x{5AB8}\x{5AB9}\x{5ABA}\x{5ABB}\x{5ABC}\x{5ABD}\x{5ABE}\x{5ABF}\x{5AC0}' .
          '\x{5AC1}\x{5AC2}\x{5AC3}\x{5AC4}\x{5AC5}\x{5AC6}\x{5AC7}\x{5AC8}\x{5AC9}' .
          '\x{5ACA}\x{5ACB}\x{5ACC}\x{5ACD}\x{5ACE}\x{5ACF}\x{5AD1}\x{5AD2}\x{5AD4}' .
          '\x{5AD5}\x{5AD6}\x{5AD7}\x{5AD8}\x{5AD9}\x{5ADA}\x{5ADB}\x{5ADC}\x{5ADD}' .
          '\x{5ADE}\x{5ADF}\x{5AE0}\x{5AE1}\x{5AE2}\x{5AE3}\x{5AE4}\x{5AE5}\x{5AE6}' .
          '\x{5AE7}\x{5AE8}\x{5AE9}\x{5AEA}\x{5AEB}\x{5AEC}\x{5AED}\x{5AEE}\x{5AF1}' .
          '\x{5AF2}\x{5AF3}\x{5AF4}\x{5AF5}\x{5AF6}\x{5AF7}\x{5AF8}\x{5AF9}\x{5AFA}' .
          '\x{5AFB}\x{5AFC}\x{5AFD}\x{5AFE}\x{5AFF}\x{5B00}\x{5B01}\x{5B02}\x{5B03}' .
          '\x{5B04}\x{5B05}\x{5B06}\x{5B07}\x{5B08}\x{5B09}\x{5B0B}\x{5B0C}\x{5B0E}' .
          '\x{5B0F}\x{5B10}\x{5B11}\x{5B12}\x{5B13}\x{5B14}\x{5B15}\x{5B16}\x{5B17}' .
          '\x{5B18}\x{5B19}\x{5B1A}\x{5B1B}\x{5B1C}\x{5B1D}\x{5B1E}\x{5B1F}\x{5B20}' .
          '\x{5B21}\x{5B22}\x{5B23}\x{5B24}\x{5B25}\x{5B26}\x{5B27}\x{5B28}\x{5B29}' .
          '\x{5B2A}\x{5B2B}\x{5B2C}\x{5B2D}\x{5B2E}\x{5B2F}\x{5B30}\x{5B31}\x{5B32}' .
          '\x{5B33}\x{5B34}\x{5B35}\x{5B36}\x{5B37}\x{5B38}\x{5B3A}\x{5B3B}\x{5B3C}' .
          '\x{5B3D}\x{5B3E}\x{5B3F}\x{5B40}\x{5B41}\x{5B42}\x{5B43}\x{5B44}\x{5B45}' .
          '\x{5B47}\x{5B48}\x{5B49}\x{5B4A}\x{5B4B}\x{5B4C}\x{5B4D}\x{5B4E}\x{5B50}' .
          '\x{5B51}\x{5B53}\x{5B54}\x{5B55}\x{5B56}\x{5B57}\x{5B58}\x{5B59}\x{5B5A}' .
          '\x{5B5B}\x{5B5C}\x{5B5D}\x{5B5E}\x{5B5F}\x{5B62}\x{5B63}\x{5B64}\x{5B65}' .
          '\x{5B66}\x{5B67}\x{5B68}\x{5B69}\x{5B6A}\x{5B6B}\x{5B6C}\x{5B6D}\x{5B6E}' .
          '\x{5B70}\x{5B71}\x{5B72}\x{5B73}\x{5B74}\x{5B75}\x{5B76}\x{5B77}\x{5B78}' .
          '\x{5B7A}\x{5B7B}\x{5B7C}\x{5B7D}\x{5B7F}\x{5B80}\x{5B81}\x{5B82}\x{5B83}' .
          '\x{5B84}\x{5B85}\x{5B87}\x{5B88}\x{5B89}\x{5B8A}\x{5B8B}\x{5B8C}\x{5B8D}' .
          '\x{5B8E}\x{5B8F}\x{5B91}\x{5B92}\x{5B93}\x{5B94}\x{5B95}\x{5B96}\x{5B97}' .
          '\x{5B98}\x{5B99}\x{5B9A}\x{5B9B}\x{5B9C}\x{5B9D}\x{5B9E}\x{5B9F}\x{5BA0}' .
          '\x{5BA1}\x{5BA2}\x{5BA3}\x{5BA4}\x{5BA5}\x{5BA6}\x{5BA7}\x{5BA8}\x{5BAA}' .
          '\x{5BAB}\x{5BAC}\x{5BAD}\x{5BAE}\x{5BAF}\x{5BB0}\x{5BB1}\x{5BB3}\x{5BB4}' .
          '\x{5BB5}\x{5BB6}\x{5BB8}\x{5BB9}\x{5BBA}\x{5BBB}\x{5BBD}\x{5BBE}\x{5BBF}' .
          '\x{5BC0}\x{5BC1}\x{5BC2}\x{5BC3}\x{5BC4}\x{5BC5}\x{5BC6}\x{5BC7}\x{5BCA}' .
          '\x{5BCB}\x{5BCC}\x{5BCD}\x{5BCE}\x{5BCF}\x{5BD0}\x{5BD1}\x{5BD2}\x{5BD3}' .
          '\x{5BD4}\x{5BD5}\x{5BD6}\x{5BD8}\x{5BD9}\x{5BDB}\x{5BDC}\x{5BDD}\x{5BDE}' .
          '\x{5BDF}\x{5BE0}\x{5BE1}\x{5BE2}\x{5BE3}\x{5BE4}\x{5BE5}\x{5BE6}\x{5BE7}' .
          '\x{5BE8}\x{5BE9}\x{5BEA}\x{5BEB}\x{5BEC}\x{5BED}\x{5BEE}\x{5BEF}\x{5BF0}' .
          '\x{5BF1}\x{5BF2}\x{5BF3}\x{5BF4}\x{5BF5}\x{5BF6}\x{5BF7}\x{5BF8}\x{5BF9}' .
          '\x{5BFA}\x{5BFB}\x{5BFC}\x{5BFD}\x{5BFF}\x{5C01}\x{5C03}\x{5C04}\x{5C05}' .
          '\x{5C06}\x{5C07}\x{5C08}\x{5C09}\x{5C0A}\x{5C0B}\x{5C0C}\x{5C0D}\x{5C0E}' .
          '\x{5C0F}\x{5C10}\x{5C11}\x{5C12}\x{5C13}\x{5C14}\x{5C15}\x{5C16}\x{5C17}' .
          '\x{5C18}\x{5C19}\x{5C1A}\x{5C1C}\x{5C1D}\x{5C1E}\x{5C1F}\x{5C20}\x{5C21}' .
          '\x{5C22}\x{5C24}\x{5C25}\x{5C27}\x{5C28}\x{5C2A}\x{5C2B}\x{5C2C}\x{5C2D}' .
          '\x{5C2E}\x{5C2F}\x{5C30}\x{5C31}\x{5C32}\x{5C33}\x{5C34}\x{5C35}\x{5C37}' .
          '\x{5C38}\x{5C39}\x{5C3A}\x{5C3B}\x{5C3C}\x{5C3D}\x{5C3E}\x{5C3F}\x{5C40}' .
          '\x{5C41}\x{5C42}\x{5C43}\x{5C44}\x{5C45}\x{5C46}\x{5C47}\x{5C48}\x{5C49}' .
          '\x{5C4A}\x{5C4B}\x{5C4C}\x{5C4D}\x{5C4E}\x{5C4F}\x{5C50}\x{5C51}\x{5C52}' .
          '\x{5C53}\x{5C54}\x{5C55}\x{5C56}\x{5C57}\x{5C58}\x{5C59}\x{5C5B}\x{5C5C}' .
          '\x{5C5D}\x{5C5E}\x{5C5F}\x{5C60}\x{5C61}\x{5C62}\x{5C63}\x{5C64}\x{5C65}' .
          '\x{5C66}\x{5C67}\x{5C68}\x{5C69}\x{5C6A}\x{5C6B}\x{5C6C}\x{5C6D}\x{5C6E}' .
          '\x{5C6F}\x{5C70}\x{5C71}\x{5C72}\x{5C73}\x{5C74}\x{5C75}\x{5C76}\x{5C77}' .
          '\x{5C78}\x{5C79}\x{5C7A}\x{5C7B}\x{5C7C}\x{5C7D}\x{5C7E}\x{5C7F}\x{5C80}' .
          '\x{5C81}\x{5C82}\x{5C83}\x{5C84}\x{5C86}\x{5C87}\x{5C88}\x{5C89}\x{5C8A}' .
          '\x{5C8B}\x{5C8C}\x{5C8D}\x{5C8E}\x{5C8F}\x{5C90}\x{5C91}\x{5C92}\x{5C93}' .
          '\x{5C94}\x{5C95}\x{5C96}\x{5C97}\x{5C98}\x{5C99}\x{5C9A}\x{5C9B}\x{5C9C}' .
          '\x{5C9D}\x{5C9E}\x{5C9F}\x{5CA0}\x{5CA1}\x{5CA2}\x{5CA3}\x{5CA4}\x{5CA5}' .
          '\x{5CA6}\x{5CA7}\x{5CA8}\x{5CA9}\x{5CAA}\x{5CAB}\x{5CAC}\x{5CAD}\x{5CAE}' .
          '\x{5CAF}\x{5CB0}\x{5CB1}\x{5CB2}\x{5CB3}\x{5CB5}\x{5CB6}\x{5CB7}\x{5CB8}' .
          '\x{5CBA}\x{5CBB}\x{5CBC}\x{5CBD}\x{5CBE}\x{5CBF}\x{5CC1}\x{5CC2}\x{5CC3}' .
          '\x{5CC4}\x{5CC5}\x{5CC6}\x{5CC7}\x{5CC8}\x{5CC9}\x{5CCA}\x{5CCB}\x{5CCC}' .
          '\x{5CCD}\x{5CCE}\x{5CCF}\x{5CD0}\x{5CD1}\x{5CD2}\x{5CD3}\x{5CD4}\x{5CD6}' .
          '\x{5CD7}\x{5CD8}\x{5CD9}\x{5CDA}\x{5CDB}\x{5CDC}\x{5CDE}\x{5CDF}\x{5CE0}' .
          '\x{5CE1}\x{5CE2}\x{5CE3}\x{5CE4}\x{5CE5}\x{5CE6}\x{5CE7}\x{5CE8}\x{5CE9}' .
          '\x{5CEA}\x{5CEB}\x{5CEC}\x{5CED}\x{5CEE}\x{5CEF}\x{5CF0}\x{5CF1}\x{5CF2}' .
          '\x{5CF3}\x{5CF4}\x{5CF6}\x{5CF7}\x{5CF8}\x{5CF9}\x{5CFA}\x{5CFB}\x{5CFC}' .
          '\x{5CFD}\x{5CFE}\x{5CFF}\x{5D00}\x{5D01}\x{5D02}\x{5D03}\x{5D04}\x{5D05}' .
          '\x{5D06}\x{5D07}\x{5D08}\x{5D09}\x{5D0A}\x{5D0B}\x{5D0C}\x{5D0D}\x{5D0E}' .
          '\x{5D0F}\x{5D10}\x{5D11}\x{5D12}\x{5D13}\x{5D14}\x{5D15}\x{5D16}\x{5D17}' .
          '\x{5D18}\x{5D19}\x{5D1A}\x{5D1B}\x{5D1C}\x{5D1D}\x{5D1E}\x{5D1F}\x{5D20}' .
          '\x{5D21}\x{5D22}\x{5D23}\x{5D24}\x{5D25}\x{5D26}\x{5D27}\x{5D28}\x{5D29}' .
          '\x{5D2A}\x{5D2C}\x{5D2D}\x{5D2E}\x{5D30}\x{5D31}\x{5D32}\x{5D33}\x{5D34}' .
          '\x{5D35}\x{5D36}\x{5D37}\x{5D38}\x{5D39}\x{5D3A}\x{5D3C}\x{5D3D}\x{5D3E}' .
          '\x{5D3F}\x{5D40}\x{5D41}\x{5D42}\x{5D43}\x{5D44}\x{5D45}\x{5D46}\x{5D47}' .
          '\x{5D48}\x{5D49}\x{5D4A}\x{5D4B}\x{5D4C}\x{5D4D}\x{5D4E}\x{5D4F}\x{5D50}' .
          '\x{5D51}\x{5D52}\x{5D54}\x{5D55}\x{5D56}\x{5D58}\x{5D59}\x{5D5A}\x{5D5B}' .
          '\x{5D5D}\x{5D5E}\x{5D5F}\x{5D61}\x{5D62}\x{5D63}\x{5D64}\x{5D65}\x{5D66}' .
          '\x{5D67}\x{5D68}\x{5D69}\x{5D6A}\x{5D6B}\x{5D6C}\x{5D6D}\x{5D6E}\x{5D6F}' .
          '\x{5D70}\x{5D71}\x{5D72}\x{5D73}\x{5D74}\x{5D75}\x{5D76}\x{5D77}\x{5D78}' .
          '\x{5D79}\x{5D7A}\x{5D7B}\x{5D7C}\x{5D7D}\x{5D7E}\x{5D7F}\x{5D80}\x{5D81}' .
          '\x{5D82}\x{5D84}\x{5D85}\x{5D86}\x{5D87}\x{5D88}\x{5D89}\x{5D8A}\x{5D8B}' .
          '\x{5D8C}\x{5D8D}\x{5D8E}\x{5D8F}\x{5D90}\x{5D91}\x{5D92}\x{5D93}\x{5D94}' .
          '\x{5D95}\x{5D97}\x{5D98}\x{5D99}\x{5D9A}\x{5D9B}\x{5D9C}\x{5D9D}\x{5D9E}' .
          '\x{5D9F}\x{5DA0}\x{5DA1}\x{5DA2}\x{5DA5}\x{5DA6}\x{5DA7}\x{5DA8}\x{5DA9}' .
          '\x{5DAA}\x{5DAC}\x{5DAD}\x{5DAE}\x{5DAF}\x{5DB0}\x{5DB1}\x{5DB2}\x{5DB4}' .
          '\x{5DB5}\x{5DB6}\x{5DB7}\x{5DB8}\x{5DBA}\x{5DBB}\x{5DBC}\x{5DBD}\x{5DBE}' .
          '\x{5DBF}\x{5DC0}\x{5DC1}\x{5DC2}\x{5DC3}\x{5DC5}\x{5DC6}\x{5DC7}\x{5DC8}' .
          '\x{5DC9}\x{5DCA}\x{5DCB}\x{5DCC}\x{5DCD}\x{5DCE}\x{5DCF}\x{5DD0}\x{5DD1}' .
          '\x{5DD2}\x{5DD3}\x{5DD4}\x{5DD5}\x{5DD6}\x{5DD8}\x{5DD9}\x{5DDB}\x{5DDD}' .
          '\x{5DDE}\x{5DDF}\x{5DE0}\x{5DE1}\x{5DE2}\x{5DE3}\x{5DE4}\x{5DE5}\x{5DE6}' .
          '\x{5DE7}\x{5DE8}\x{5DE9}\x{5DEA}\x{5DEB}\x{5DEC}\x{5DED}\x{5DEE}\x{5DEF}' .
          '\x{5DF0}\x{5DF1}\x{5DF2}\x{5DF3}\x{5DF4}\x{5DF5}\x{5DF7}\x{5DF8}\x{5DF9}' .
          '\x{5DFA}\x{5DFB}\x{5DFC}\x{5DFD}\x{5DFE}\x{5DFF}\x{5E00}\x{5E01}\x{5E02}' .
          '\x{5E03}\x{5E04}\x{5E05}\x{5E06}\x{5E07}\x{5E08}\x{5E09}\x{5E0A}\x{5E0B}' .
          '\x{5E0C}\x{5E0D}\x{5E0E}\x{5E0F}\x{5E10}\x{5E11}\x{5E13}\x{5E14}\x{5E15}' .
          '\x{5E16}\x{5E17}\x{5E18}\x{5E19}\x{5E1A}\x{5E1B}\x{5E1C}\x{5E1D}\x{5E1E}' .
          '\x{5E1F}\x{5E20}\x{5E21}\x{5E22}\x{5E23}\x{5E24}\x{5E25}\x{5E26}\x{5E27}' .
          '\x{5E28}\x{5E29}\x{5E2A}\x{5E2B}\x{5E2C}\x{5E2D}\x{5E2E}\x{5E2F}\x{5E30}' .
          '\x{5E31}\x{5E32}\x{5E33}\x{5E34}\x{5E35}\x{5E36}\x{5E37}\x{5E38}\x{5E39}' .
          '\x{5E3A}\x{5E3B}\x{5E3C}\x{5E3D}\x{5E3E}\x{5E40}\x{5E41}\x{5E42}\x{5E43}' .
          '\x{5E44}\x{5E45}\x{5E46}\x{5E47}\x{5E49}\x{5E4A}\x{5E4B}\x{5E4C}\x{5E4D}' .
          '\x{5E4E}\x{5E4F}\x{5E50}\x{5E52}\x{5E53}\x{5E54}\x{5E55}\x{5E56}\x{5E57}' .
          '\x{5E58}\x{5E59}\x{5E5A}\x{5E5B}\x{5E5C}\x{5E5D}\x{5E5E}\x{5E5F}\x{5E60}' .
          '\x{5E61}\x{5E62}\x{5E63}\x{5E64}\x{5E65}\x{5E66}\x{5E67}\x{5E68}\x{5E69}' .
          '\x{5E6A}\x{5E6B}\x{5E6C}\x{5E6D}\x{5E6E}\x{5E6F}\x{5E70}\x{5E71}\x{5E72}' .
          '\x{5E73}\x{5E74}\x{5E75}\x{5E76}\x{5E77}\x{5E78}\x{5E79}\x{5E7A}\x{5E7B}' .
          '\x{5E7C}\x{5E7D}\x{5E7E}\x{5E7F}\x{5E80}\x{5E81}\x{5E82}\x{5E83}\x{5E84}' .
          '\x{5E85}\x{5E86}\x{5E87}\x{5E88}\x{5E89}\x{5E8A}\x{5E8B}\x{5E8C}\x{5E8D}' .
          '\x{5E8E}\x{5E8F}\x{5E90}\x{5E91}\x{5E93}\x{5E94}\x{5E95}\x{5E96}\x{5E97}' .
          '\x{5E98}\x{5E99}\x{5E9A}\x{5E9B}\x{5E9C}\x{5E9D}\x{5E9E}\x{5E9F}\x{5EA0}' .
          '\x{5EA1}\x{5EA2}\x{5EA3}\x{5EA4}\x{5EA5}\x{5EA6}\x{5EA7}\x{5EA8}\x{5EA9}' .
          '\x{5EAA}\x{5EAB}\x{5EAC}\x{5EAD}\x{5EAE}\x{5EAF}\x{5EB0}\x{5EB1}\x{5EB2}' .
          '\x{5EB3}\x{5EB4}\x{5EB5}\x{5EB6}\x{5EB7}\x{5EB8}\x{5EB9}\x{5EBB}\x{5EBC}' .
          '\x{5EBD}\x{5EBE}\x{5EBF}\x{5EC1}\x{5EC2}\x{5EC3}\x{5EC4}\x{5EC5}\x{5EC6}' .
          '\x{5EC7}\x{5EC8}\x{5EC9}\x{5ECA}\x{5ECB}\x{5ECC}\x{5ECD}\x{5ECE}\x{5ECF}' .
          '\x{5ED0}\x{5ED1}\x{5ED2}\x{5ED3}\x{5ED4}\x{5ED5}\x{5ED6}\x{5ED7}\x{5ED8}' .
          '\x{5ED9}\x{5EDA}\x{5EDB}\x{5EDC}\x{5EDD}\x{5EDE}\x{5EDF}\x{5EE0}\x{5EE1}' .
          '\x{5EE2}\x{5EE3}\x{5EE4}\x{5EE5}\x{5EE6}\x{5EE7}\x{5EE8}\x{5EE9}\x{5EEA}' .
          '\x{5EEC}\x{5EED}\x{5EEE}\x{5EEF}\x{5EF0}\x{5EF1}\x{5EF2}\x{5EF3}\x{5EF4}' .
          '\x{5EF5}\x{5EF6}\x{5EF7}\x{5EF8}\x{5EFA}\x{5EFB}\x{5EFC}\x{5EFD}\x{5EFE}' .
          '\x{5EFF}\x{5F00}\x{5F01}\x{5F02}\x{5F03}\x{5F04}\x{5F05}\x{5F06}\x{5F07}' .
          '\x{5F08}\x{5F0A}\x{5F0B}\x{5F0C}\x{5F0D}\x{5F0F}\x{5F11}\x{5F12}\x{5F13}' .
          '\x{5F14}\x{5F15}\x{5F16}\x{5F17}\x{5F18}\x{5F19}\x{5F1A}\x{5F1B}\x{5F1C}' .
          '\x{5F1D}\x{5F1E}\x{5F1F}\x{5F20}\x{5F21}\x{5F22}\x{5F23}\x{5F24}\x{5F25}' .
          '\x{5F26}\x{5F27}\x{5F28}\x{5F29}\x{5F2A}\x{5F2B}\x{5F2C}\x{5F2D}\x{5F2E}' .
          '\x{5F2F}\x{5F30}\x{5F31}\x{5F32}\x{5F33}\x{5F34}\x{5F35}\x{5F36}\x{5F37}' .
          '\x{5F38}\x{5F39}\x{5F3A}\x{5F3C}\x{5F3E}\x{5F3F}\x{5F40}\x{5F41}\x{5F42}' .
          '\x{5F43}\x{5F44}\x{5F45}\x{5F46}\x{5F47}\x{5F48}\x{5F49}\x{5F4A}\x{5F4B}' .
          '\x{5F4C}\x{5F4D}\x{5F4E}\x{5F4F}\x{5F50}\x{5F51}\x{5F52}\x{5F53}\x{5F54}' .
          '\x{5F55}\x{5F56}\x{5F57}\x{5F58}\x{5F59}\x{5F5A}\x{5F5B}\x{5F5C}\x{5F5D}' .
          '\x{5F5E}\x{5F5F}\x{5F60}\x{5F61}\x{5F62}\x{5F63}\x{5F64}\x{5F65}\x{5F66}' .
          '\x{5F67}\x{5F68}\x{5F69}\x{5F6A}\x{5F6B}\x{5F6C}\x{5F6D}\x{5F6E}\x{5F6F}' .
          '\x{5F70}\x{5F71}\x{5F72}\x{5F73}\x{5F74}\x{5F75}\x{5F76}\x{5F77}\x{5F78}' .
          '\x{5F79}\x{5F7A}\x{5F7B}\x{5F7C}\x{5F7D}\x{5F7E}\x{5F7F}\x{5F80}\x{5F81}' .
          '\x{5F82}\x{5F83}\x{5F84}\x{5F85}\x{5F86}\x{5F87}\x{5F88}\x{5F89}\x{5F8A}' .
          '\x{5F8B}\x{5F8C}\x{5F8D}\x{5F8E}\x{5F90}\x{5F91}\x{5F92}\x{5F93}\x{5F94}' .
          '\x{5F95}\x{5F96}\x{5F97}\x{5F98}\x{5F99}\x{5F9B}\x{5F9C}\x{5F9D}\x{5F9E}' .
          '\x{5F9F}\x{5FA0}\x{5FA1}\x{5FA2}\x{5FA5}\x{5FA6}\x{5FA7}\x{5FA8}\x{5FA9}' .
          '\x{5FAA}\x{5FAB}\x{5FAC}\x{5FAD}\x{5FAE}\x{5FAF}\x{5FB1}\x{5FB2}\x{5FB3}' .
          '\x{5FB4}\x{5FB5}\x{5FB6}\x{5FB7}\x{5FB8}\x{5FB9}\x{5FBA}\x{5FBB}\x{5FBC}' .
          '\x{5FBD}\x{5FBE}\x{5FBF}\x{5FC0}\x{5FC1}\x{5FC3}\x{5FC4}\x{5FC5}\x{5FC6}' .
          '\x{5FC7}\x{5FC8}\x{5FC9}\x{5FCA}\x{5FCB}\x{5FCC}\x{5FCD}\x{5FCF}\x{5FD0}' .
          '\x{5FD1}\x{5FD2}\x{5FD3}\x{5FD4}\x{5FD5}\x{5FD6}\x{5FD7}\x{5FD8}\x{5FD9}' .
          '\x{5FDA}\x{5FDC}\x{5FDD}\x{5FDE}\x{5FE0}\x{5FE1}\x{5FE3}\x{5FE4}\x{5FE5}' .
          '\x{5FE6}\x{5FE7}\x{5FE8}\x{5FE9}\x{5FEA}\x{5FEB}\x{5FED}\x{5FEE}\x{5FEF}' .
          '\x{5FF0}\x{5FF1}\x{5FF2}\x{5FF3}\x{5FF4}\x{5FF5}\x{5FF6}\x{5FF7}\x{5FF8}' .
          '\x{5FF9}\x{5FFA}\x{5FFB}\x{5FFD}\x{5FFE}\x{5FFF}\x{6000}\x{6001}\x{6002}' .
          '\x{6003}\x{6004}\x{6005}\x{6006}\x{6007}\x{6008}\x{6009}\x{600A}\x{600B}' .
          '\x{600C}\x{600D}\x{600E}\x{600F}\x{6010}\x{6011}\x{6012}\x{6013}\x{6014}' .
          '\x{6015}\x{6016}\x{6017}\x{6018}\x{6019}\x{601A}\x{601B}\x{601C}\x{601D}' .
          '\x{601E}\x{601F}\x{6020}\x{6021}\x{6022}\x{6024}\x{6025}\x{6026}\x{6027}' .
          '\x{6028}\x{6029}\x{602A}\x{602B}\x{602C}\x{602D}\x{602E}\x{602F}\x{6030}' .
          '\x{6031}\x{6032}\x{6033}\x{6034}\x{6035}\x{6036}\x{6037}\x{6038}\x{6039}' .
          '\x{603A}\x{603B}\x{603C}\x{603D}\x{603E}\x{603F}\x{6040}\x{6041}\x{6042}' .
          '\x{6043}\x{6044}\x{6045}\x{6046}\x{6047}\x{6048}\x{6049}\x{604A}\x{604B}' .
          '\x{604C}\x{604D}\x{604E}\x{604F}\x{6050}\x{6051}\x{6052}\x{6053}\x{6054}' .
          '\x{6055}\x{6057}\x{6058}\x{6059}\x{605A}\x{605B}\x{605C}\x{605D}\x{605E}' .
          '\x{605F}\x{6062}\x{6063}\x{6064}\x{6065}\x{6066}\x{6067}\x{6068}\x{6069}' .
          '\x{606A}\x{606B}\x{606C}\x{606D}\x{606E}\x{606F}\x{6070}\x{6072}\x{6073}' .
          '\x{6075}\x{6076}\x{6077}\x{6078}\x{6079}\x{607A}\x{607B}\x{607C}\x{607D}' .
          '\x{607E}\x{607F}\x{6080}\x{6081}\x{6082}\x{6083}\x{6084}\x{6085}\x{6086}' .
          '\x{6087}\x{6088}\x{6089}\x{608A}\x{608B}\x{608C}\x{608D}\x{608E}\x{608F}' .
          '\x{6090}\x{6092}\x{6094}\x{6095}\x{6096}\x{6097}\x{6098}\x{6099}\x{609A}' .
          '\x{609B}\x{609C}\x{609D}\x{609E}\x{609F}\x{60A0}\x{60A1}\x{60A2}\x{60A3}' .
          '\x{60A4}\x{60A6}\x{60A7}\x{60A8}\x{60AA}\x{60AB}\x{60AC}\x{60AD}\x{60AE}' .
          '\x{60AF}\x{60B0}\x{60B1}\x{60B2}\x{60B3}\x{60B4}\x{60B5}\x{60B6}\x{60B7}' .
          '\x{60B8}\x{60B9}\x{60BA}\x{60BB}\x{60BC}\x{60BD}\x{60BE}\x{60BF}\x{60C0}' .
          '\x{60C1}\x{60C2}\x{60C3}\x{60C4}\x{60C5}\x{60C6}\x{60C7}\x{60C8}\x{60C9}' .
          '\x{60CA}\x{60CB}\x{60CC}\x{60CD}\x{60CE}\x{60CF}\x{60D0}\x{60D1}\x{60D3}' .
          '\x{60D4}\x{60D5}\x{60D7}\x{60D8}\x{60D9}\x{60DA}\x{60DB}\x{60DC}\x{60DD}' .
          '\x{60DF}\x{60E0}\x{60E1}\x{60E2}\x{60E4}\x{60E6}\x{60E7}\x{60E8}\x{60E9}' .
          '\x{60EA}\x{60EB}\x{60EC}\x{60ED}\x{60EE}\x{60EF}\x{60F0}\x{60F1}\x{60F2}' .
          '\x{60F3}\x{60F4}\x{60F5}\x{60F6}\x{60F7}\x{60F8}\x{60F9}\x{60FA}\x{60FB}' .
          '\x{60FC}\x{60FE}\x{60FF}\x{6100}\x{6101}\x{6103}\x{6104}\x{6105}\x{6106}' .
          '\x{6108}\x{6109}\x{610A}\x{610B}\x{610C}\x{610D}\x{610E}\x{610F}\x{6110}' .
          '\x{6112}\x{6113}\x{6114}\x{6115}\x{6116}\x{6117}\x{6118}\x{6119}\x{611A}' .
          '\x{611B}\x{611C}\x{611D}\x{611F}\x{6120}\x{6122}\x{6123}\x{6124}\x{6125}' .
          '\x{6126}\x{6127}\x{6128}\x{6129}\x{612A}\x{612B}\x{612C}\x{612D}\x{612E}' .
          '\x{612F}\x{6130}\x{6132}\x{6134}\x{6136}\x{6137}\x{613A}\x{613B}\x{613C}' .
          '\x{613D}\x{613E}\x{613F}\x{6140}\x{6141}\x{6142}\x{6143}\x{6144}\x{6145}' .
          '\x{6146}\x{6147}\x{6148}\x{6149}\x{614A}\x{614B}\x{614C}\x{614D}\x{614E}' .
          '\x{614F}\x{6150}\x{6151}\x{6152}\x{6153}\x{6154}\x{6155}\x{6156}\x{6157}' .
          '\x{6158}\x{6159}\x{615A}\x{615B}\x{615C}\x{615D}\x{615E}\x{615F}\x{6161}' .
          '\x{6162}\x{6163}\x{6164}\x{6165}\x{6166}\x{6167}\x{6168}\x{6169}\x{616A}' .
          '\x{616B}\x{616C}\x{616D}\x{616E}\x{6170}\x{6171}\x{6172}\x{6173}\x{6174}' .
          '\x{6175}\x{6176}\x{6177}\x{6178}\x{6179}\x{617A}\x{617C}\x{617E}\x{6180}' .
          '\x{6181}\x{6182}\x{6183}\x{6184}\x{6185}\x{6187}\x{6188}\x{6189}\x{618A}' .
          '\x{618B}\x{618C}\x{618D}\x{618E}\x{618F}\x{6190}\x{6191}\x{6192}\x{6193}' .
          '\x{6194}\x{6195}\x{6196}\x{6198}\x{6199}\x{619A}\x{619B}\x{619D}\x{619E}' .
          '\x{619F}\x{61A0}\x{61A1}\x{61A2}\x{61A3}\x{61A4}\x{61A5}\x{61A6}\x{61A7}' .
          '\x{61A8}\x{61A9}\x{61AA}\x{61AB}\x{61AC}\x{61AD}\x{61AE}\x{61AF}\x{61B0}' .
          '\x{61B1}\x{61B2}\x{61B3}\x{61B4}\x{61B5}\x{61B6}\x{61B7}\x{61B8}\x{61BA}' .
          '\x{61BC}\x{61BD}\x{61BE}\x{61BF}\x{61C0}\x{61C1}\x{61C2}\x{61C3}\x{61C4}' .
          '\x{61C5}\x{61C6}\x{61C7}\x{61C8}\x{61C9}\x{61CA}\x{61CB}\x{61CC}\x{61CD}' .
          '\x{61CE}\x{61CF}\x{61D0}\x{61D1}\x{61D2}\x{61D4}\x{61D6}\x{61D7}\x{61D8}' .
          '\x{61D9}\x{61DA}\x{61DB}\x{61DC}\x{61DD}\x{61DE}\x{61DF}\x{61E0}\x{61E1}' .
          '\x{61E2}\x{61E3}\x{61E4}\x{61E5}\x{61E6}\x{61E7}\x{61E8}\x{61E9}\x{61EA}' .
          '\x{61EB}\x{61ED}\x{61EE}\x{61F0}\x{61F1}\x{61F2}\x{61F3}\x{61F5}\x{61F6}' .
          '\x{61F7}\x{61F8}\x{61F9}\x{61FA}\x{61FB}\x{61FC}\x{61FD}\x{61FE}\x{61FF}' .
          '\x{6200}\x{6201}\x{6202}\x{6203}\x{6204}\x{6206}\x{6207}\x{6208}\x{6209}' .
          '\x{620A}\x{620B}\x{620C}\x{620D}\x{620E}\x{620F}\x{6210}\x{6211}\x{6212}' .
          '\x{6213}\x{6214}\x{6215}\x{6216}\x{6217}\x{6218}\x{6219}\x{621A}\x{621B}' .
          '\x{621C}\x{621D}\x{621E}\x{621F}\x{6220}\x{6221}\x{6222}\x{6223}\x{6224}' .
          '\x{6225}\x{6226}\x{6227}\x{6228}\x{6229}\x{622A}\x{622B}\x{622C}\x{622D}' .
          '\x{622E}\x{622F}\x{6230}\x{6231}\x{6232}\x{6233}\x{6234}\x{6236}\x{6237}' .
          '\x{6238}\x{623A}\x{623B}\x{623C}\x{623D}\x{623E}\x{623F}\x{6240}\x{6241}' .
          '\x{6242}\x{6243}\x{6244}\x{6245}\x{6246}\x{6247}\x{6248}\x{6249}\x{624A}' .
          '\x{624B}\x{624C}\x{624D}\x{624E}\x{624F}\x{6250}\x{6251}\x{6252}\x{6253}' .
          '\x{6254}\x{6255}\x{6256}\x{6258}\x{6259}\x{625A}\x{625B}\x{625C}\x{625D}' .
          '\x{625E}\x{625F}\x{6260}\x{6261}\x{6262}\x{6263}\x{6264}\x{6265}\x{6266}' .
          '\x{6267}\x{6268}\x{6269}\x{626A}\x{626B}\x{626C}\x{626D}\x{626E}\x{626F}' .
          '\x{6270}\x{6271}\x{6272}\x{6273}\x{6274}\x{6275}\x{6276}\x{6277}\x{6278}' .
          '\x{6279}\x{627A}\x{627B}\x{627C}\x{627D}\x{627E}\x{627F}\x{6280}\x{6281}' .
          '\x{6283}\x{6284}\x{6285}\x{6286}\x{6287}\x{6288}\x{6289}\x{628A}\x{628B}' .
          '\x{628C}\x{628E}\x{628F}\x{6290}\x{6291}\x{6292}\x{6293}\x{6294}\x{6295}' .
          '\x{6296}\x{6297}\x{6298}\x{6299}\x{629A}\x{629B}\x{629C}\x{629E}\x{629F}' .
          '\x{62A0}\x{62A1}\x{62A2}\x{62A3}\x{62A4}\x{62A5}\x{62A7}\x{62A8}\x{62A9}' .
          '\x{62AA}\x{62AB}\x{62AC}\x{62AD}\x{62AE}\x{62AF}\x{62B0}\x{62B1}\x{62B2}' .
          '\x{62B3}\x{62B4}\x{62B5}\x{62B6}\x{62B7}\x{62B8}\x{62B9}\x{62BA}\x{62BB}' .
          '\x{62BC}\x{62BD}\x{62BE}\x{62BF}\x{62C0}\x{62C1}\x{62C2}\x{62C3}\x{62C4}' .
          '\x{62C5}\x{62C6}\x{62C7}\x{62C8}\x{62C9}\x{62CA}\x{62CB}\x{62CC}\x{62CD}' .
          '\x{62CE}\x{62CF}\x{62D0}\x{62D1}\x{62D2}\x{62D3}\x{62D4}\x{62D5}\x{62D6}' .
          '\x{62D7}\x{62D8}\x{62D9}\x{62DA}\x{62DB}\x{62DC}\x{62DD}\x{62DF}\x{62E0}' .
          '\x{62E1}\x{62E2}\x{62E3}\x{62E4}\x{62E5}\x{62E6}\x{62E7}\x{62E8}\x{62E9}' .
          '\x{62EB}\x{62EC}\x{62ED}\x{62EE}\x{62EF}\x{62F0}\x{62F1}\x{62F2}\x{62F3}' .
          '\x{62F4}\x{62F5}\x{62F6}\x{62F7}\x{62F8}\x{62F9}\x{62FA}\x{62FB}\x{62FC}' .
          '\x{62FD}\x{62FE}\x{62FF}\x{6300}\x{6301}\x{6302}\x{6303}\x{6304}\x{6305}' .
          '\x{6306}\x{6307}\x{6308}\x{6309}\x{630B}\x{630C}\x{630D}\x{630E}\x{630F}' .
          '\x{6310}\x{6311}\x{6312}\x{6313}\x{6314}\x{6315}\x{6316}\x{6318}\x{6319}' .
          '\x{631A}\x{631B}\x{631C}\x{631D}\x{631E}\x{631F}\x{6320}\x{6321}\x{6322}' .
          '\x{6323}\x{6324}\x{6325}\x{6326}\x{6327}\x{6328}\x{6329}\x{632A}\x{632B}' .
          '\x{632C}\x{632D}\x{632E}\x{632F}\x{6330}\x{6332}\x{6333}\x{6334}\x{6336}' .
          '\x{6338}\x{6339}\x{633A}\x{633B}\x{633C}\x{633D}\x{633E}\x{6340}\x{6341}' .
          '\x{6342}\x{6343}\x{6344}\x{6345}\x{6346}\x{6347}\x{6348}\x{6349}\x{634A}' .
          '\x{634B}\x{634C}\x{634D}\x{634E}\x{634F}\x{6350}\x{6351}\x{6352}\x{6353}' .
          '\x{6354}\x{6355}\x{6356}\x{6357}\x{6358}\x{6359}\x{635A}\x{635C}\x{635D}' .
          '\x{635E}\x{635F}\x{6360}\x{6361}\x{6362}\x{6363}\x{6364}\x{6365}\x{6366}' .
          '\x{6367}\x{6368}\x{6369}\x{636A}\x{636B}\x{636C}\x{636D}\x{636E}\x{636F}' .
          '\x{6370}\x{6371}\x{6372}\x{6373}\x{6374}\x{6375}\x{6376}\x{6377}\x{6378}' .
          '\x{6379}\x{637A}\x{637B}\x{637C}\x{637D}\x{637E}\x{6380}\x{6381}\x{6382}' .
          '\x{6383}\x{6384}\x{6385}\x{6386}\x{6387}\x{6388}\x{6389}\x{638A}\x{638C}' .
          '\x{638D}\x{638E}\x{638F}\x{6390}\x{6391}\x{6392}\x{6394}\x{6395}\x{6396}' .
          '\x{6397}\x{6398}\x{6399}\x{639A}\x{639B}\x{639C}\x{639D}\x{639E}\x{639F}' .
          '\x{63A0}\x{63A1}\x{63A2}\x{63A3}\x{63A4}\x{63A5}\x{63A6}\x{63A7}\x{63A8}' .
          '\x{63A9}\x{63AA}\x{63AB}\x{63AC}\x{63AD}\x{63AE}\x{63AF}\x{63B0}\x{63B1}' .
          '\x{63B2}\x{63B3}\x{63B4}\x{63B5}\x{63B6}\x{63B7}\x{63B8}\x{63B9}\x{63BA}' .
          '\x{63BC}\x{63BD}\x{63BE}\x{63BF}\x{63C0}\x{63C1}\x{63C2}\x{63C3}\x{63C4}' .
          '\x{63C5}\x{63C6}\x{63C7}\x{63C8}\x{63C9}\x{63CA}\x{63CB}\x{63CC}\x{63CD}' .
          '\x{63CE}\x{63CF}\x{63D0}\x{63D2}\x{63D3}\x{63D4}\x{63D5}\x{63D6}\x{63D7}' .
          '\x{63D8}\x{63D9}\x{63DA}\x{63DB}\x{63DC}\x{63DD}\x{63DE}\x{63DF}\x{63E0}' .
          '\x{63E1}\x{63E2}\x{63E3}\x{63E4}\x{63E5}\x{63E6}\x{63E7}\x{63E8}\x{63E9}' .
          '\x{63EA}\x{63EB}\x{63EC}\x{63ED}\x{63EE}\x{63EF}\x{63F0}\x{63F1}\x{63F2}' .
          '\x{63F3}\x{63F4}\x{63F5}\x{63F6}\x{63F7}\x{63F8}\x{63F9}\x{63FA}\x{63FB}' .
          '\x{63FC}\x{63FD}\x{63FE}\x{63FF}\x{6400}\x{6401}\x{6402}\x{6403}\x{6404}' .
          '\x{6405}\x{6406}\x{6408}\x{6409}\x{640A}\x{640B}\x{640C}\x{640D}\x{640E}' .
          '\x{640F}\x{6410}\x{6411}\x{6412}\x{6413}\x{6414}\x{6415}\x{6416}\x{6417}' .
          '\x{6418}\x{6419}\x{641A}\x{641B}\x{641C}\x{641D}\x{641E}\x{641F}\x{6420}' .
          '\x{6421}\x{6422}\x{6423}\x{6424}\x{6425}\x{6426}\x{6427}\x{6428}\x{6429}' .
          '\x{642A}\x{642B}\x{642C}\x{642D}\x{642E}\x{642F}\x{6430}\x{6431}\x{6432}' .
          '\x{6433}\x{6434}\x{6435}\x{6436}\x{6437}\x{6438}\x{6439}\x{643A}\x{643D}' .
          '\x{643E}\x{643F}\x{6440}\x{6441}\x{6443}\x{6444}\x{6445}\x{6446}\x{6447}' .
          '\x{6448}\x{644A}\x{644B}\x{644C}\x{644D}\x{644E}\x{644F}\x{6450}\x{6451}' .
          '\x{6452}\x{6453}\x{6454}\x{6455}\x{6456}\x{6457}\x{6458}\x{6459}\x{645B}' .
          '\x{645C}\x{645D}\x{645E}\x{645F}\x{6460}\x{6461}\x{6462}\x{6463}\x{6464}' .
          '\x{6465}\x{6466}\x{6467}\x{6468}\x{6469}\x{646A}\x{646B}\x{646C}\x{646D}' .
          '\x{646E}\x{646F}\x{6470}\x{6471}\x{6472}\x{6473}\x{6474}\x{6475}\x{6476}' .
          '\x{6477}\x{6478}\x{6479}\x{647A}\x{647B}\x{647C}\x{647D}\x{647F}\x{6480}' .
          '\x{6481}\x{6482}\x{6483}\x{6484}\x{6485}\x{6487}\x{6488}\x{6489}\x{648A}' .
          '\x{648B}\x{648C}\x{648D}\x{648E}\x{648F}\x{6490}\x{6491}\x{6492}\x{6493}' .
          '\x{6494}\x{6495}\x{6496}\x{6497}\x{6498}\x{6499}\x{649A}\x{649B}\x{649C}' .
          '\x{649D}\x{649E}\x{649F}\x{64A0}\x{64A2}\x{64A3}\x{64A4}\x{64A5}\x{64A6}' .
          '\x{64A7}\x{64A8}\x{64A9}\x{64AA}\x{64AB}\x{64AC}\x{64AD}\x{64AE}\x{64B0}' .
          '\x{64B1}\x{64B2}\x{64B3}\x{64B4}\x{64B5}\x{64B7}\x{64B8}\x{64B9}\x{64BA}' .
          '\x{64BB}\x{64BC}\x{64BD}\x{64BE}\x{64BF}\x{64C0}\x{64C1}\x{64C2}\x{64C3}' .
          '\x{64C4}\x{64C5}\x{64C6}\x{64C7}\x{64C9}\x{64CA}\x{64CB}\x{64CC}\x{64CD}' .
          '\x{64CE}\x{64CF}\x{64D0}\x{64D1}\x{64D2}\x{64D3}\x{64D4}\x{64D6}\x{64D7}' .
          '\x{64D8}\x{64D9}\x{64DA}\x{64DB}\x{64DC}\x{64DD}\x{64DE}\x{64DF}\x{64E0}' .
          '\x{64E2}\x{64E3}\x{64E4}\x{64E6}\x{64E7}\x{64E8}\x{64E9}\x{64EA}\x{64EB}' .
          '\x{64EC}\x{64ED}\x{64EF}\x{64F0}\x{64F1}\x{64F2}\x{64F3}\x{64F4}\x{64F6}' .
          '\x{64F7}\x{64F8}\x{64FA}\x{64FB}\x{64FC}\x{64FD}\x{64FE}\x{64FF}\x{6500}' .
          '\x{6501}\x{6503}\x{6504}\x{6505}\x{6506}\x{6507}\x{6508}\x{6509}\x{650B}' .
          '\x{650C}\x{650D}\x{650E}\x{650F}\x{6510}\x{6511}\x{6512}\x{6513}\x{6514}' .
          '\x{6515}\x{6516}\x{6517}\x{6518}\x{6519}\x{651A}\x{651B}\x{651C}\x{651D}' .
          '\x{651E}\x{6520}\x{6521}\x{6522}\x{6523}\x{6524}\x{6525}\x{6526}\x{6527}' .
          '\x{6529}\x{652A}\x{652B}\x{652C}\x{652D}\x{652E}\x{652F}\x{6530}\x{6531}' .
          '\x{6532}\x{6533}\x{6534}\x{6535}\x{6536}\x{6537}\x{6538}\x{6539}\x{653A}' .
          '\x{653B}\x{653C}\x{653D}\x{653E}\x{653F}\x{6541}\x{6543}\x{6544}\x{6545}' .
          '\x{6546}\x{6547}\x{6548}\x{6549}\x{654A}\x{654B}\x{654C}\x{654D}\x{654E}' .
          '\x{654F}\x{6550}\x{6551}\x{6552}\x{6553}\x{6554}\x{6555}\x{6556}\x{6557}' .
          '\x{6558}\x{6559}\x{655B}\x{655C}\x{655D}\x{655E}\x{6560}\x{6561}\x{6562}' .
          '\x{6563}\x{6564}\x{6565}\x{6566}\x{6567}\x{6568}\x{6569}\x{656A}\x{656B}' .
          '\x{656C}\x{656E}\x{656F}\x{6570}\x{6571}\x{6572}\x{6573}\x{6574}\x{6575}' .
          '\x{6576}\x{6577}\x{6578}\x{6579}\x{657A}\x{657B}\x{657C}\x{657E}\x{657F}' .
          '\x{6580}\x{6581}\x{6582}\x{6583}\x{6584}\x{6585}\x{6586}\x{6587}\x{6588}' .
          '\x{6589}\x{658B}\x{658C}\x{658D}\x{658E}\x{658F}\x{6590}\x{6591}\x{6592}' .
          '\x{6593}\x{6594}\x{6595}\x{6596}\x{6597}\x{6598}\x{6599}\x{659B}\x{659C}' .
          '\x{659D}\x{659E}\x{659F}\x{65A0}\x{65A1}\x{65A2}\x{65A3}\x{65A4}\x{65A5}' .
          '\x{65A6}\x{65A7}\x{65A8}\x{65A9}\x{65AA}\x{65AB}\x{65AC}\x{65AD}\x{65AE}' .
          '\x{65AF}\x{65B0}\x{65B1}\x{65B2}\x{65B3}\x{65B4}\x{65B6}\x{65B7}\x{65B8}' .
          '\x{65B9}\x{65BA}\x{65BB}\x{65BC}\x{65BD}\x{65BF}\x{65C0}\x{65C1}\x{65C2}' .
          '\x{65C3}\x{65C4}\x{65C5}\x{65C6}\x{65C7}\x{65CA}\x{65CB}\x{65CC}\x{65CD}' .
          '\x{65CE}\x{65CF}\x{65D0}\x{65D2}\x{65D3}\x{65D4}\x{65D5}\x{65D6}\x{65D7}' .
          '\x{65DA}\x{65DB}\x{65DD}\x{65DE}\x{65DF}\x{65E0}\x{65E1}\x{65E2}\x{65E3}' .
          '\x{65E5}\x{65E6}\x{65E7}\x{65E8}\x{65E9}\x{65EB}\x{65EC}\x{65ED}\x{65EE}' .
          '\x{65EF}\x{65F0}\x{65F1}\x{65F2}\x{65F3}\x{65F4}\x{65F5}\x{65F6}\x{65F7}' .
          '\x{65F8}\x{65FA}\x{65FB}\x{65FC}\x{65FD}\x{6600}\x{6601}\x{6602}\x{6603}' .
          '\x{6604}\x{6605}\x{6606}\x{6607}\x{6608}\x{6609}\x{660A}\x{660B}\x{660C}' .
          '\x{660D}\x{660E}\x{660F}\x{6610}\x{6611}\x{6612}\x{6613}\x{6614}\x{6615}' .
          '\x{6616}\x{6618}\x{6619}\x{661A}\x{661B}\x{661C}\x{661D}\x{661F}\x{6620}' .
          '\x{6621}\x{6622}\x{6623}\x{6624}\x{6625}\x{6626}\x{6627}\x{6628}\x{6629}' .
          '\x{662A}\x{662B}\x{662D}\x{662E}\x{662F}\x{6630}\x{6631}\x{6632}\x{6633}' .
          '\x{6634}\x{6635}\x{6636}\x{6639}\x{663A}\x{663C}\x{663D}\x{663E}\x{6640}' .
          '\x{6641}\x{6642}\x{6643}\x{6644}\x{6645}\x{6646}\x{6647}\x{6649}\x{664A}' .
          '\x{664B}\x{664C}\x{664E}\x{664F}\x{6650}\x{6651}\x{6652}\x{6653}\x{6654}' .
          '\x{6655}\x{6656}\x{6657}\x{6658}\x{6659}\x{665A}\x{665B}\x{665C}\x{665D}' .
          '\x{665E}\x{665F}\x{6661}\x{6662}\x{6664}\x{6665}\x{6666}\x{6668}\x{6669}' .
          '\x{666A}\x{666B}\x{666C}\x{666D}\x{666E}\x{666F}\x{6670}\x{6671}\x{6672}' .
          '\x{6673}\x{6674}\x{6675}\x{6676}\x{6677}\x{6678}\x{6679}\x{667A}\x{667B}' .
          '\x{667C}\x{667D}\x{667E}\x{667F}\x{6680}\x{6681}\x{6682}\x{6683}\x{6684}' .
          '\x{6685}\x{6686}\x{6687}\x{6688}\x{6689}\x{668A}\x{668B}\x{668C}\x{668D}' .
          '\x{668E}\x{668F}\x{6690}\x{6691}\x{6693}\x{6694}\x{6695}\x{6696}\x{6697}' .
          '\x{6698}\x{6699}\x{669A}\x{669B}\x{669D}\x{669F}\x{66A0}\x{66A1}\x{66A2}' .
          '\x{66A3}\x{66A4}\x{66A5}\x{66A6}\x{66A7}\x{66A8}\x{66A9}\x{66AA}\x{66AB}' .
          '\x{66AE}\x{66AF}\x{66B0}\x{66B1}\x{66B2}\x{66B3}\x{66B4}\x{66B5}\x{66B6}' .
          '\x{66B7}\x{66B8}\x{66B9}\x{66BA}\x{66BB}\x{66BC}\x{66BD}\x{66BE}\x{66BF}' .
          '\x{66C0}\x{66C1}\x{66C2}\x{66C3}\x{66C4}\x{66C5}\x{66C6}\x{66C7}\x{66C8}' .
          '\x{66C9}\x{66CA}\x{66CB}\x{66CC}\x{66CD}\x{66CE}\x{66CF}\x{66D1}\x{66D2}' .
          '\x{66D4}\x{66D5}\x{66D6}\x{66D8}\x{66D9}\x{66DA}\x{66DB}\x{66DC}\x{66DD}' .
          '\x{66DE}\x{66E0}\x{66E1}\x{66E2}\x{66E3}\x{66E4}\x{66E5}\x{66E6}\x{66E7}' .
          '\x{66E8}\x{66E9}\x{66EA}\x{66EB}\x{66EC}\x{66ED}\x{66EE}\x{66F0}\x{66F1}' .
          '\x{66F2}\x{66F3}\x{66F4}\x{66F5}\x{66F6}\x{66F7}\x{66F8}\x{66F9}\x{66FA}' .
          '\x{66FB}\x{66FC}\x{66FE}\x{66FF}\x{6700}\x{6701}\x{6703}\x{6704}\x{6705}' .
          '\x{6706}\x{6708}\x{6709}\x{670A}\x{670B}\x{670C}\x{670D}\x{670E}\x{670F}' .
          '\x{6710}\x{6711}\x{6712}\x{6713}\x{6714}\x{6715}\x{6716}\x{6717}\x{6718}' .
          '\x{671A}\x{671B}\x{671C}\x{671D}\x{671E}\x{671F}\x{6720}\x{6721}\x{6722}' .
          '\x{6723}\x{6725}\x{6726}\x{6727}\x{6728}\x{672A}\x{672B}\x{672C}\x{672D}' .
          '\x{672E}\x{672F}\x{6730}\x{6731}\x{6732}\x{6733}\x{6734}\x{6735}\x{6736}' .
          '\x{6737}\x{6738}\x{6739}\x{673A}\x{673B}\x{673C}\x{673D}\x{673E}\x{673F}' .
          '\x{6740}\x{6741}\x{6742}\x{6743}\x{6744}\x{6745}\x{6746}\x{6747}\x{6748}' .
          '\x{6749}\x{674A}\x{674B}\x{674C}\x{674D}\x{674E}\x{674F}\x{6750}\x{6751}' .
          '\x{6752}\x{6753}\x{6754}\x{6755}\x{6756}\x{6757}\x{6758}\x{6759}\x{675A}' .
          '\x{675B}\x{675C}\x{675D}\x{675E}\x{675F}\x{6760}\x{6761}\x{6762}\x{6763}' .
          '\x{6764}\x{6765}\x{6766}\x{6768}\x{6769}\x{676A}\x{676B}\x{676C}\x{676D}' .
          '\x{676E}\x{676F}\x{6770}\x{6771}\x{6772}\x{6773}\x{6774}\x{6775}\x{6776}' .
          '\x{6777}\x{6778}\x{6779}\x{677A}\x{677B}\x{677C}\x{677D}\x{677E}\x{677F}' .
          '\x{6780}\x{6781}\x{6782}\x{6783}\x{6784}\x{6785}\x{6786}\x{6787}\x{6789}' .
          '\x{678A}\x{678B}\x{678C}\x{678D}\x{678E}\x{678F}\x{6790}\x{6791}\x{6792}' .
          '\x{6793}\x{6794}\x{6795}\x{6797}\x{6798}\x{6799}\x{679A}\x{679B}\x{679C}' .
          '\x{679D}\x{679E}\x{679F}\x{67A0}\x{67A1}\x{67A2}\x{67A3}\x{67A4}\x{67A5}' .
          '\x{67A6}\x{67A7}\x{67A8}\x{67AA}\x{67AB}\x{67AC}\x{67AD}\x{67AE}\x{67AF}' .
          '\x{67B0}\x{67B1}\x{67B2}\x{67B3}\x{67B4}\x{67B5}\x{67B6}\x{67B7}\x{67B8}' .
          '\x{67B9}\x{67BA}\x{67BB}\x{67BC}\x{67BE}\x{67C0}\x{67C1}\x{67C2}\x{67C3}' .
          '\x{67C4}\x{67C5}\x{67C6}\x{67C7}\x{67C8}\x{67C9}\x{67CA}\x{67CB}\x{67CC}' .
          '\x{67CD}\x{67CE}\x{67CF}\x{67D0}\x{67D1}\x{67D2}\x{67D3}\x{67D4}\x{67D6}' .
          '\x{67D8}\x{67D9}\x{67DA}\x{67DB}\x{67DC}\x{67DD}\x{67DE}\x{67DF}\x{67E0}' .
          '\x{67E1}\x{67E2}\x{67E3}\x{67E4}\x{67E5}\x{67E6}\x{67E7}\x{67E8}\x{67E9}' .
          '\x{67EA}\x{67EB}\x{67EC}\x{67ED}\x{67EE}\x{67EF}\x{67F0}\x{67F1}\x{67F2}' .
          '\x{67F3}\x{67F4}\x{67F5}\x{67F6}\x{67F7}\x{67F8}\x{67FA}\x{67FB}\x{67FC}' .
          '\x{67FD}\x{67FE}\x{67FF}\x{6800}\x{6802}\x{6803}\x{6804}\x{6805}\x{6806}' .
          '\x{6807}\x{6808}\x{6809}\x{680A}\x{680B}\x{680C}\x{680D}\x{680E}\x{680F}' .
          '\x{6810}\x{6811}\x{6812}\x{6813}\x{6814}\x{6816}\x{6817}\x{6818}\x{6819}' .
          '\x{681A}\x{681B}\x{681C}\x{681D}\x{681F}\x{6820}\x{6821}\x{6822}\x{6823}' .
          '\x{6824}\x{6825}\x{6826}\x{6828}\x{6829}\x{682A}\x{682B}\x{682C}\x{682D}' .
          '\x{682E}\x{682F}\x{6831}\x{6832}\x{6833}\x{6834}\x{6835}\x{6836}\x{6837}' .
          '\x{6838}\x{6839}\x{683A}\x{683B}\x{683C}\x{683D}\x{683E}\x{683F}\x{6840}' .
          '\x{6841}\x{6842}\x{6843}\x{6844}\x{6845}\x{6846}\x{6847}\x{6848}\x{6849}' .
          '\x{684A}\x{684B}\x{684C}\x{684D}\x{684E}\x{684F}\x{6850}\x{6851}\x{6852}' .
          '\x{6853}\x{6854}\x{6855}\x{6856}\x{6857}\x{685B}\x{685D}\x{6860}\x{6861}' .
          '\x{6862}\x{6863}\x{6864}\x{6865}\x{6866}\x{6867}\x{6868}\x{6869}\x{686A}' .
          '\x{686B}\x{686C}\x{686D}\x{686E}\x{686F}\x{6870}\x{6871}\x{6872}\x{6873}' .
          '\x{6874}\x{6875}\x{6876}\x{6877}\x{6878}\x{6879}\x{687B}\x{687C}\x{687D}' .
          '\x{687E}\x{687F}\x{6880}\x{6881}\x{6882}\x{6883}\x{6884}\x{6885}\x{6886}' .
          '\x{6887}\x{6888}\x{6889}\x{688A}\x{688B}\x{688C}\x{688D}\x{688E}\x{688F}' .
          '\x{6890}\x{6891}\x{6892}\x{6893}\x{6894}\x{6896}\x{6897}\x{6898}\x{689A}' .
          '\x{689B}\x{689C}\x{689D}\x{689E}\x{689F}\x{68A0}\x{68A1}\x{68A2}\x{68A3}' .
          '\x{68A4}\x{68A6}\x{68A7}\x{68A8}\x{68A9}\x{68AA}\x{68AB}\x{68AC}\x{68AD}' .
          '\x{68AE}\x{68AF}\x{68B0}\x{68B1}\x{68B2}\x{68B3}\x{68B4}\x{68B5}\x{68B6}' .
          '\x{68B7}\x{68B9}\x{68BB}\x{68BC}\x{68BD}\x{68BE}\x{68BF}\x{68C0}\x{68C1}' .
          '\x{68C2}\x{68C4}\x{68C6}\x{68C7}\x{68C8}\x{68C9}\x{68CA}\x{68CB}\x{68CC}' .
          '\x{68CD}\x{68CE}\x{68CF}\x{68D0}\x{68D1}\x{68D2}\x{68D3}\x{68D4}\x{68D5}' .
          '\x{68D6}\x{68D7}\x{68D8}\x{68DA}\x{68DB}\x{68DC}\x{68DD}\x{68DE}\x{68DF}' .
          '\x{68E0}\x{68E1}\x{68E3}\x{68E4}\x{68E6}\x{68E7}\x{68E8}\x{68E9}\x{68EA}' .
          '\x{68EB}\x{68EC}\x{68ED}\x{68EE}\x{68EF}\x{68F0}\x{68F1}\x{68F2}\x{68F3}' .
          '\x{68F4}\x{68F5}\x{68F6}\x{68F7}\x{68F8}\x{68F9}\x{68FA}\x{68FB}\x{68FC}' .
          '\x{68FD}\x{68FE}\x{68FF}\x{6901}\x{6902}\x{6903}\x{6904}\x{6905}\x{6906}' .
          '\x{6907}\x{6908}\x{690A}\x{690B}\x{690C}\x{690D}\x{690E}\x{690F}\x{6910}' .
          '\x{6911}\x{6912}\x{6913}\x{6914}\x{6915}\x{6916}\x{6917}\x{6918}\x{6919}' .
          '\x{691A}\x{691B}\x{691C}\x{691D}\x{691E}\x{691F}\x{6920}\x{6921}\x{6922}' .
          '\x{6923}\x{6924}\x{6925}\x{6926}\x{6927}\x{6928}\x{6929}\x{692A}\x{692B}' .
          '\x{692C}\x{692D}\x{692E}\x{692F}\x{6930}\x{6931}\x{6932}\x{6933}\x{6934}' .
          '\x{6935}\x{6936}\x{6937}\x{6938}\x{6939}\x{693A}\x{693B}\x{693C}\x{693D}' .
          '\x{693F}\x{6940}\x{6941}\x{6942}\x{6943}\x{6944}\x{6945}\x{6946}\x{6947}' .
          '\x{6948}\x{6949}\x{694A}\x{694B}\x{694C}\x{694E}\x{694F}\x{6950}\x{6951}' .
          '\x{6952}\x{6953}\x{6954}\x{6955}\x{6956}\x{6957}\x{6958}\x{6959}\x{695A}' .
          '\x{695B}\x{695C}\x{695D}\x{695E}\x{695F}\x{6960}\x{6961}\x{6962}\x{6963}' .
          '\x{6964}\x{6965}\x{6966}\x{6967}\x{6968}\x{6969}\x{696A}\x{696B}\x{696C}' .
          '\x{696D}\x{696E}\x{696F}\x{6970}\x{6971}\x{6972}\x{6973}\x{6974}\x{6975}' .
          '\x{6976}\x{6977}\x{6978}\x{6979}\x{697A}\x{697B}\x{697C}\x{697D}\x{697E}' .
          '\x{697F}\x{6980}\x{6981}\x{6982}\x{6983}\x{6984}\x{6985}\x{6986}\x{6987}' .
          '\x{6988}\x{6989}\x{698A}\x{698B}\x{698C}\x{698D}\x{698E}\x{698F}\x{6990}' .
          '\x{6991}\x{6992}\x{6993}\x{6994}\x{6995}\x{6996}\x{6997}\x{6998}\x{6999}' .
          '\x{699A}\x{699B}\x{699C}\x{699D}\x{699E}\x{69A0}\x{69A1}\x{69A3}\x{69A4}' .
          '\x{69A5}\x{69A6}\x{69A7}\x{69A8}\x{69A9}\x{69AA}\x{69AB}\x{69AC}\x{69AD}' .
          '\x{69AE}\x{69AF}\x{69B0}\x{69B1}\x{69B2}\x{69B3}\x{69B4}\x{69B5}\x{69B6}' .
          '\x{69B7}\x{69B8}\x{69B9}\x{69BA}\x{69BB}\x{69BC}\x{69BD}\x{69BE}\x{69BF}' .
          '\x{69C1}\x{69C2}\x{69C3}\x{69C4}\x{69C5}\x{69C6}\x{69C7}\x{69C8}\x{69C9}' .
          '\x{69CA}\x{69CB}\x{69CC}\x{69CD}\x{69CE}\x{69CF}\x{69D0}\x{69D3}\x{69D4}' .
          '\x{69D8}\x{69D9}\x{69DA}\x{69DB}\x{69DC}\x{69DD}\x{69DE}\x{69DF}\x{69E0}' .
          '\x{69E1}\x{69E2}\x{69E3}\x{69E4}\x{69E5}\x{69E6}\x{69E7}\x{69E8}\x{69E9}' .
          '\x{69EA}\x{69EB}\x{69EC}\x{69ED}\x{69EE}\x{69EF}\x{69F0}\x{69F1}\x{69F2}' .
          '\x{69F3}\x{69F4}\x{69F5}\x{69F6}\x{69F7}\x{69F8}\x{69FA}\x{69FB}\x{69FC}' .
          '\x{69FD}\x{69FE}\x{69FF}\x{6A00}\x{6A01}\x{6A02}\x{6A04}\x{6A05}\x{6A06}' .
          '\x{6A07}\x{6A08}\x{6A09}\x{6A0A}\x{6A0B}\x{6A0D}\x{6A0E}\x{6A0F}\x{6A10}' .
          '\x{6A11}\x{6A12}\x{6A13}\x{6A14}\x{6A15}\x{6A16}\x{6A17}\x{6A18}\x{6A19}' .
          '\x{6A1A}\x{6A1B}\x{6A1D}\x{6A1E}\x{6A1F}\x{6A20}\x{6A21}\x{6A22}\x{6A23}' .
          '\x{6A25}\x{6A26}\x{6A27}\x{6A28}\x{6A29}\x{6A2A}\x{6A2B}\x{6A2C}\x{6A2D}' .
          '\x{6A2E}\x{6A2F}\x{6A30}\x{6A31}\x{6A32}\x{6A33}\x{6A34}\x{6A35}\x{6A36}' .
          '\x{6A38}\x{6A39}\x{6A3A}\x{6A3B}\x{6A3C}\x{6A3D}\x{6A3E}\x{6A3F}\x{6A40}' .
          '\x{6A41}\x{6A42}\x{6A43}\x{6A44}\x{6A45}\x{6A46}\x{6A47}\x{6A48}\x{6A49}' .
          '\x{6A4B}\x{6A4C}\x{6A4D}\x{6A4E}\x{6A4F}\x{6A50}\x{6A51}\x{6A52}\x{6A54}' .
          '\x{6A55}\x{6A56}\x{6A57}\x{6A58}\x{6A59}\x{6A5A}\x{6A5B}\x{6A5D}\x{6A5E}' .
          '\x{6A5F}\x{6A60}\x{6A61}\x{6A62}\x{6A63}\x{6A64}\x{6A65}\x{6A66}\x{6A67}' .
          '\x{6A68}\x{6A69}\x{6A6A}\x{6A6B}\x{6A6C}\x{6A6D}\x{6A6F}\x{6A71}\x{6A72}' .
          '\x{6A73}\x{6A74}\x{6A75}\x{6A76}\x{6A77}\x{6A78}\x{6A79}\x{6A7A}\x{6A7B}' .
          '\x{6A7C}\x{6A7D}\x{6A7E}\x{6A7F}\x{6A80}\x{6A81}\x{6A82}\x{6A83}\x{6A84}' .
          '\x{6A85}\x{6A87}\x{6A88}\x{6A89}\x{6A8B}\x{6A8C}\x{6A8D}\x{6A8E}\x{6A90}' .
          '\x{6A91}\x{6A92}\x{6A93}\x{6A94}\x{6A95}\x{6A96}\x{6A97}\x{6A98}\x{6A9A}' .
          '\x{6A9B}\x{6A9C}\x{6A9E}\x{6A9F}\x{6AA0}\x{6AA1}\x{6AA2}\x{6AA3}\x{6AA4}' .
          '\x{6AA5}\x{6AA6}\x{6AA7}\x{6AA8}\x{6AA9}\x{6AAB}\x{6AAC}\x{6AAD}\x{6AAE}' .
          '\x{6AAF}\x{6AB0}\x{6AB2}\x{6AB3}\x{6AB4}\x{6AB5}\x{6AB6}\x{6AB7}\x{6AB8}' .
          '\x{6AB9}\x{6ABA}\x{6ABB}\x{6ABC}\x{6ABD}\x{6ABF}\x{6AC1}\x{6AC2}\x{6AC3}' .
          '\x{6AC5}\x{6AC6}\x{6AC7}\x{6ACA}\x{6ACB}\x{6ACC}\x{6ACD}\x{6ACE}\x{6ACF}' .
          '\x{6AD0}\x{6AD1}\x{6AD2}\x{6AD3}\x{6AD4}\x{6AD5}\x{6AD6}\x{6AD7}\x{6AD9}' .
          '\x{6ADA}\x{6ADB}\x{6ADC}\x{6ADD}\x{6ADE}\x{6ADF}\x{6AE0}\x{6AE1}\x{6AE2}' .
          '\x{6AE3}\x{6AE4}\x{6AE5}\x{6AE6}\x{6AE7}\x{6AE8}\x{6AEA}\x{6AEB}\x{6AEC}' .
          '\x{6AED}\x{6AEE}\x{6AEF}\x{6AF0}\x{6AF1}\x{6AF2}\x{6AF3}\x{6AF4}\x{6AF5}' .
          '\x{6AF6}\x{6AF7}\x{6AF8}\x{6AF9}\x{6AFA}\x{6AFB}\x{6AFC}\x{6AFD}\x{6AFE}' .
          '\x{6AFF}\x{6B00}\x{6B01}\x{6B02}\x{6B03}\x{6B04}\x{6B05}\x{6B06}\x{6B07}' .
          '\x{6B08}\x{6B09}\x{6B0A}\x{6B0B}\x{6B0C}\x{6B0D}\x{6B0F}\x{6B10}\x{6B11}' .
          '\x{6B12}\x{6B13}\x{6B14}\x{6B15}\x{6B16}\x{6B17}\x{6B18}\x{6B19}\x{6B1A}' .
          '\x{6B1C}\x{6B1D}\x{6B1E}\x{6B1F}\x{6B20}\x{6B21}\x{6B22}\x{6B23}\x{6B24}' .
          '\x{6B25}\x{6B26}\x{6B27}\x{6B28}\x{6B29}\x{6B2A}\x{6B2B}\x{6B2C}\x{6B2D}' .
          '\x{6B2F}\x{6B30}\x{6B31}\x{6B32}\x{6B33}\x{6B34}\x{6B36}\x{6B37}\x{6B38}' .
          '\x{6B39}\x{6B3A}\x{6B3B}\x{6B3C}\x{6B3D}\x{6B3E}\x{6B3F}\x{6B41}\x{6B42}' .
          '\x{6B43}\x{6B44}\x{6B45}\x{6B46}\x{6B47}\x{6B48}\x{6B49}\x{6B4A}\x{6B4B}' .
          '\x{6B4C}\x{6B4D}\x{6B4E}\x{6B4F}\x{6B50}\x{6B51}\x{6B52}\x{6B53}\x{6B54}' .
          '\x{6B55}\x{6B56}\x{6B59}\x{6B5A}\x{6B5B}\x{6B5C}\x{6B5E}\x{6B5F}\x{6B60}' .
          '\x{6B61}\x{6B62}\x{6B63}\x{6B64}\x{6B65}\x{6B66}\x{6B67}\x{6B69}\x{6B6A}' .
          '\x{6B6B}\x{6B6D}\x{6B6F}\x{6B70}\x{6B72}\x{6B73}\x{6B74}\x{6B76}\x{6B77}' .
          '\x{6B78}\x{6B79}\x{6B7A}\x{6B7B}\x{6B7C}\x{6B7E}\x{6B7F}\x{6B80}\x{6B81}' .
          '\x{6B82}\x{6B83}\x{6B84}\x{6B85}\x{6B86}\x{6B87}\x{6B88}\x{6B89}\x{6B8A}' .
          '\x{6B8B}\x{6B8C}\x{6B8D}\x{6B8E}\x{6B8F}\x{6B90}\x{6B91}\x{6B92}\x{6B93}' .
          '\x{6B94}\x{6B95}\x{6B96}\x{6B97}\x{6B98}\x{6B99}\x{6B9A}\x{6B9B}\x{6B9C}' .
          '\x{6B9D}\x{6B9E}\x{6B9F}\x{6BA0}\x{6BA1}\x{6BA2}\x{6BA3}\x{6BA4}\x{6BA5}' .
          '\x{6BA6}\x{6BA7}\x{6BA8}\x{6BA9}\x{6BAA}\x{6BAB}\x{6BAC}\x{6BAD}\x{6BAE}' .
          '\x{6BAF}\x{6BB0}\x{6BB2}\x{6BB3}\x{6BB4}\x{6BB5}\x{6BB6}\x{6BB7}\x{6BB9}' .
          '\x{6BBA}\x{6BBB}\x{6BBC}\x{6BBD}\x{6BBE}\x{6BBF}\x{6BC0}\x{6BC1}\x{6BC2}' .
          '\x{6BC3}\x{6BC4}\x{6BC5}\x{6BC6}\x{6BC7}\x{6BC8}\x{6BC9}\x{6BCA}\x{6BCB}' .
          '\x{6BCC}\x{6BCD}\x{6BCE}\x{6BCF}\x{6BD0}\x{6BD1}\x{6BD2}\x{6BD3}\x{6BD4}' .
          '\x{6BD5}\x{6BD6}\x{6BD7}\x{6BD8}\x{6BD9}\x{6BDA}\x{6BDB}\x{6BDC}\x{6BDD}' .
          '\x{6BDE}\x{6BDF}\x{6BE0}\x{6BE1}\x{6BE2}\x{6BE3}\x{6BE4}\x{6BE5}\x{6BE6}' .
          '\x{6BE7}\x{6BE8}\x{6BEA}\x{6BEB}\x{6BEC}\x{6BED}\x{6BEE}\x{6BEF}\x{6BF0}' .
          '\x{6BF2}\x{6BF3}\x{6BF5}\x{6BF6}\x{6BF7}\x{6BF8}\x{6BF9}\x{6BFB}\x{6BFC}' .
          '\x{6BFD}\x{6BFE}\x{6BFF}\x{6C00}\x{6C01}\x{6C02}\x{6C03}\x{6C04}\x{6C05}' .
          '\x{6C06}\x{6C07}\x{6C08}\x{6C09}\x{6C0B}\x{6C0C}\x{6C0D}\x{6C0E}\x{6C0F}' .
          '\x{6C10}\x{6C11}\x{6C12}\x{6C13}\x{6C14}\x{6C15}\x{6C16}\x{6C18}\x{6C19}' .
          '\x{6C1A}\x{6C1B}\x{6C1D}\x{6C1E}\x{6C1F}\x{6C20}\x{6C21}\x{6C22}\x{6C23}' .
          '\x{6C24}\x{6C25}\x{6C26}\x{6C27}\x{6C28}\x{6C29}\x{6C2A}\x{6C2B}\x{6C2C}' .
          '\x{6C2E}\x{6C2F}\x{6C30}\x{6C31}\x{6C32}\x{6C33}\x{6C34}\x{6C35}\x{6C36}' .
          '\x{6C37}\x{6C38}\x{6C3A}\x{6C3B}\x{6C3D}\x{6C3E}\x{6C3F}\x{6C40}\x{6C41}' .
          '\x{6C42}\x{6C43}\x{6C44}\x{6C46}\x{6C47}\x{6C48}\x{6C49}\x{6C4A}\x{6C4B}' .
          '\x{6C4C}\x{6C4D}\x{6C4E}\x{6C4F}\x{6C50}\x{6C51}\x{6C52}\x{6C53}\x{6C54}' .
          '\x{6C55}\x{6C56}\x{6C57}\x{6C58}\x{6C59}\x{6C5A}\x{6C5B}\x{6C5C}\x{6C5D}' .
          '\x{6C5E}\x{6C5F}\x{6C60}\x{6C61}\x{6C62}\x{6C63}\x{6C64}\x{6C65}\x{6C66}' .
          '\x{6C67}\x{6C68}\x{6C69}\x{6C6A}\x{6C6B}\x{6C6D}\x{6C6F}\x{6C70}\x{6C71}' .
          '\x{6C72}\x{6C73}\x{6C74}\x{6C75}\x{6C76}\x{6C77}\x{6C78}\x{6C79}\x{6C7A}' .
          '\x{6C7B}\x{6C7C}\x{6C7D}\x{6C7E}\x{6C7F}\x{6C80}\x{6C81}\x{6C82}\x{6C83}' .
          '\x{6C84}\x{6C85}\x{6C86}\x{6C87}\x{6C88}\x{6C89}\x{6C8A}\x{6C8B}\x{6C8C}' .
          '\x{6C8D}\x{6C8E}\x{6C8F}\x{6C90}\x{6C91}\x{6C92}\x{6C93}\x{6C94}\x{6C95}' .
          '\x{6C96}\x{6C97}\x{6C98}\x{6C99}\x{6C9A}\x{6C9B}\x{6C9C}\x{6C9D}\x{6C9E}' .
          '\x{6C9F}\x{6CA1}\x{6CA2}\x{6CA3}\x{6CA4}\x{6CA5}\x{6CA6}\x{6CA7}\x{6CA8}' .
          '\x{6CA9}\x{6CAA}\x{6CAB}\x{6CAC}\x{6CAD}\x{6CAE}\x{6CAF}\x{6CB0}\x{6CB1}' .
          '\x{6CB2}\x{6CB3}\x{6CB4}\x{6CB5}\x{6CB6}\x{6CB7}\x{6CB8}\x{6CB9}\x{6CBA}' .
          '\x{6CBB}\x{6CBC}\x{6CBD}\x{6CBE}\x{6CBF}\x{6CC0}\x{6CC1}\x{6CC2}\x{6CC3}' .
          '\x{6CC4}\x{6CC5}\x{6CC6}\x{6CC7}\x{6CC8}\x{6CC9}\x{6CCA}\x{6CCB}\x{6CCC}' .
          '\x{6CCD}\x{6CCE}\x{6CCF}\x{6CD0}\x{6CD1}\x{6CD2}\x{6CD3}\x{6CD4}\x{6CD5}' .
          '\x{6CD6}\x{6CD7}\x{6CD9}\x{6CDA}\x{6CDB}\x{6CDC}\x{6CDD}\x{6CDE}\x{6CDF}' .
          '\x{6CE0}\x{6CE1}\x{6CE2}\x{6CE3}\x{6CE4}\x{6CE5}\x{6CE6}\x{6CE7}\x{6CE8}' .
          '\x{6CE9}\x{6CEA}\x{6CEB}\x{6CEC}\x{6CED}\x{6CEE}\x{6CEF}\x{6CF0}\x{6CF1}' .
          '\x{6CF2}\x{6CF3}\x{6CF5}\x{6CF6}\x{6CF7}\x{6CF8}\x{6CF9}\x{6CFA}\x{6CFB}' .
          '\x{6CFC}\x{6CFD}\x{6CFE}\x{6CFF}\x{6D00}\x{6D01}\x{6D03}\x{6D04}\x{6D05}' .
          '\x{6D06}\x{6D07}\x{6D08}\x{6D09}\x{6D0A}\x{6D0B}\x{6D0C}\x{6D0D}\x{6D0E}' .
          '\x{6D0F}\x{6D10}\x{6D11}\x{6D12}\x{6D13}\x{6D14}\x{6D15}\x{6D16}\x{6D17}' .
          '\x{6D18}\x{6D19}\x{6D1A}\x{6D1B}\x{6D1D}\x{6D1E}\x{6D1F}\x{6D20}\x{6D21}' .
          '\x{6D22}\x{6D23}\x{6D25}\x{6D26}\x{6D27}\x{6D28}\x{6D29}\x{6D2A}\x{6D2B}' .
          '\x{6D2C}\x{6D2D}\x{6D2E}\x{6D2F}\x{6D30}\x{6D31}\x{6D32}\x{6D33}\x{6D34}' .
          '\x{6D35}\x{6D36}\x{6D37}\x{6D38}\x{6D39}\x{6D3A}\x{6D3B}\x{6D3C}\x{6D3D}' .
          '\x{6D3E}\x{6D3F}\x{6D40}\x{6D41}\x{6D42}\x{6D43}\x{6D44}\x{6D45}\x{6D46}' .
          '\x{6D47}\x{6D48}\x{6D49}\x{6D4A}\x{6D4B}\x{6D4C}\x{6D4D}\x{6D4E}\x{6D4F}' .
          '\x{6D50}\x{6D51}\x{6D52}\x{6D53}\x{6D54}\x{6D55}\x{6D56}\x{6D57}\x{6D58}' .
          '\x{6D59}\x{6D5A}\x{6D5B}\x{6D5C}\x{6D5D}\x{6D5E}\x{6D5F}\x{6D60}\x{6D61}' .
          '\x{6D62}\x{6D63}\x{6D64}\x{6D65}\x{6D66}\x{6D67}\x{6D68}\x{6D69}\x{6D6A}' .
          '\x{6D6B}\x{6D6C}\x{6D6D}\x{6D6E}\x{6D6F}\x{6D70}\x{6D72}\x{6D73}\x{6D74}' .
          '\x{6D75}\x{6D76}\x{6D77}\x{6D78}\x{6D79}\x{6D7A}\x{6D7B}\x{6D7C}\x{6D7D}' .
          '\x{6D7E}\x{6D7F}\x{6D80}\x{6D82}\x{6D83}\x{6D84}\x{6D85}\x{6D86}\x{6D87}' .
          '\x{6D88}\x{6D89}\x{6D8A}\x{6D8B}\x{6D8C}\x{6D8D}\x{6D8E}\x{6D8F}\x{6D90}' .
          '\x{6D91}\x{6D92}\x{6D93}\x{6D94}\x{6D95}\x{6D97}\x{6D98}\x{6D99}\x{6D9A}' .
          '\x{6D9B}\x{6D9D}\x{6D9E}\x{6D9F}\x{6DA0}\x{6DA1}\x{6DA2}\x{6DA3}\x{6DA4}' .
          '\x{6DA5}\x{6DA6}\x{6DA7}\x{6DA8}\x{6DA9}\x{6DAA}\x{6DAB}\x{6DAC}\x{6DAD}' .
          '\x{6DAE}\x{6DAF}\x{6DB2}\x{6DB3}\x{6DB4}\x{6DB5}\x{6DB7}\x{6DB8}\x{6DB9}' .
          '\x{6DBA}\x{6DBB}\x{6DBC}\x{6DBD}\x{6DBE}\x{6DBF}\x{6DC0}\x{6DC1}\x{6DC2}' .
          '\x{6DC3}\x{6DC4}\x{6DC5}\x{6DC6}\x{6DC7}\x{6DC8}\x{6DC9}\x{6DCA}\x{6DCB}' .
          '\x{6DCC}\x{6DCD}\x{6DCE}\x{6DCF}\x{6DD0}\x{6DD1}\x{6DD2}\x{6DD3}\x{6DD4}' .
          '\x{6DD5}\x{6DD6}\x{6DD7}\x{6DD8}\x{6DD9}\x{6DDA}\x{6DDB}\x{6DDC}\x{6DDD}' .
          '\x{6DDE}\x{6DDF}\x{6DE0}\x{6DE1}\x{6DE2}\x{6DE3}\x{6DE4}\x{6DE5}\x{6DE6}' .
          '\x{6DE7}\x{6DE8}\x{6DE9}\x{6DEA}\x{6DEB}\x{6DEC}\x{6DED}\x{6DEE}\x{6DEF}' .
          '\x{6DF0}\x{6DF1}\x{6DF2}\x{6DF3}\x{6DF4}\x{6DF5}\x{6DF6}\x{6DF7}\x{6DF8}' .
          '\x{6DF9}\x{6DFA}\x{6DFB}\x{6DFC}\x{6DFD}\x{6E00}\x{6E03}\x{6E04}\x{6E05}' .
          '\x{6E07}\x{6E08}\x{6E09}\x{6E0A}\x{6E0B}\x{6E0C}\x{6E0D}\x{6E0E}\x{6E0F}' .
          '\x{6E10}\x{6E11}\x{6E14}\x{6E15}\x{6E16}\x{6E17}\x{6E19}\x{6E1A}\x{6E1B}' .
          '\x{6E1C}\x{6E1D}\x{6E1E}\x{6E1F}\x{6E20}\x{6E21}\x{6E22}\x{6E23}\x{6E24}' .
          '\x{6E25}\x{6E26}\x{6E27}\x{6E28}\x{6E29}\x{6E2B}\x{6E2C}\x{6E2D}\x{6E2E}' .
          '\x{6E2F}\x{6E30}\x{6E31}\x{6E32}\x{6E33}\x{6E34}\x{6E35}\x{6E36}\x{6E37}' .
          '\x{6E38}\x{6E39}\x{6E3A}\x{6E3B}\x{6E3C}\x{6E3D}\x{6E3E}\x{6E3F}\x{6E40}' .
          '\x{6E41}\x{6E42}\x{6E43}\x{6E44}\x{6E45}\x{6E46}\x{6E47}\x{6E48}\x{6E49}' .
          '\x{6E4A}\x{6E4B}\x{6E4D}\x{6E4E}\x{6E4F}\x{6E50}\x{6E51}\x{6E52}\x{6E53}' .
          '\x{6E54}\x{6E55}\x{6E56}\x{6E57}\x{6E58}\x{6E59}\x{6E5A}\x{6E5B}\x{6E5C}' .
          '\x{6E5D}\x{6E5E}\x{6E5F}\x{6E60}\x{6E61}\x{6E62}\x{6E63}\x{6E64}\x{6E65}' .
          '\x{6E66}\x{6E67}\x{6E68}\x{6E69}\x{6E6A}\x{6E6B}\x{6E6D}\x{6E6E}\x{6E6F}' .
          '\x{6E70}\x{6E71}\x{6E72}\x{6E73}\x{6E74}\x{6E75}\x{6E77}\x{6E78}\x{6E79}' .
          '\x{6E7E}\x{6E7F}\x{6E80}\x{6E81}\x{6E82}\x{6E83}\x{6E84}\x{6E85}\x{6E86}' .
          '\x{6E87}\x{6E88}\x{6E89}\x{6E8A}\x{6E8D}\x{6E8E}\x{6E8F}\x{6E90}\x{6E91}' .
          '\x{6E92}\x{6E93}\x{6E94}\x{6E96}\x{6E97}\x{6E98}\x{6E99}\x{6E9A}\x{6E9B}' .
          '\x{6E9C}\x{6E9D}\x{6E9E}\x{6E9F}\x{6EA0}\x{6EA1}\x{6EA2}\x{6EA3}\x{6EA4}' .
          '\x{6EA5}\x{6EA6}\x{6EA7}\x{6EA8}\x{6EA9}\x{6EAA}\x{6EAB}\x{6EAC}\x{6EAD}' .
          '\x{6EAE}\x{6EAF}\x{6EB0}\x{6EB1}\x{6EB2}\x{6EB3}\x{6EB4}\x{6EB5}\x{6EB6}' .
          '\x{6EB7}\x{6EB8}\x{6EB9}\x{6EBA}\x{6EBB}\x{6EBC}\x{6EBD}\x{6EBE}\x{6EBF}' .
          '\x{6EC0}\x{6EC1}\x{6EC2}\x{6EC3}\x{6EC4}\x{6EC5}\x{6EC6}\x{6EC7}\x{6EC8}' .
          '\x{6EC9}\x{6ECA}\x{6ECB}\x{6ECC}\x{6ECD}\x{6ECE}\x{6ECF}\x{6ED0}\x{6ED1}' .
          '\x{6ED2}\x{6ED3}\x{6ED4}\x{6ED5}\x{6ED6}\x{6ED7}\x{6ED8}\x{6ED9}\x{6EDA}' .
          '\x{6EDC}\x{6EDE}\x{6EDF}\x{6EE0}\x{6EE1}\x{6EE2}\x{6EE4}\x{6EE5}\x{6EE6}' .
          '\x{6EE7}\x{6EE8}\x{6EE9}\x{6EEA}\x{6EEB}\x{6EEC}\x{6EED}\x{6EEE}\x{6EEF}' .
          '\x{6EF0}\x{6EF1}\x{6EF2}\x{6EF3}\x{6EF4}\x{6EF5}\x{6EF6}\x{6EF7}\x{6EF8}' .
          '\x{6EF9}\x{6EFA}\x{6EFB}\x{6EFC}\x{6EFD}\x{6EFE}\x{6EFF}\x{6F00}\x{6F01}' .
          '\x{6F02}\x{6F03}\x{6F05}\x{6F06}\x{6F07}\x{6F08}\x{6F09}\x{6F0A}\x{6F0C}' .
          '\x{6F0D}\x{6F0E}\x{6F0F}\x{6F10}\x{6F11}\x{6F12}\x{6F13}\x{6F14}\x{6F15}' .
          '\x{6F16}\x{6F17}\x{6F18}\x{6F19}\x{6F1A}\x{6F1B}\x{6F1C}\x{6F1D}\x{6F1E}' .
          '\x{6F1F}\x{6F20}\x{6F21}\x{6F22}\x{6F23}\x{6F24}\x{6F25}\x{6F26}\x{6F27}' .
          '\x{6F28}\x{6F29}\x{6F2A}\x{6F2B}\x{6F2C}\x{6F2D}\x{6F2E}\x{6F2F}\x{6F30}' .
          '\x{6F31}\x{6F32}\x{6F33}\x{6F34}\x{6F35}\x{6F36}\x{6F37}\x{6F38}\x{6F39}' .
          '\x{6F3A}\x{6F3B}\x{6F3C}\x{6F3D}\x{6F3E}\x{6F3F}\x{6F40}\x{6F41}\x{6F43}' .
          '\x{6F44}\x{6F45}\x{6F46}\x{6F47}\x{6F49}\x{6F4B}\x{6F4C}\x{6F4D}\x{6F4E}' .
          '\x{6F4F}\x{6F50}\x{6F51}\x{6F52}\x{6F53}\x{6F54}\x{6F55}\x{6F56}\x{6F57}' .
          '\x{6F58}\x{6F59}\x{6F5A}\x{6F5B}\x{6F5C}\x{6F5D}\x{6F5E}\x{6F5F}\x{6F60}' .
          '\x{6F61}\x{6F62}\x{6F63}\x{6F64}\x{6F65}\x{6F66}\x{6F67}\x{6F68}\x{6F69}' .
          '\x{6F6A}\x{6F6B}\x{6F6C}\x{6F6D}\x{6F6E}\x{6F6F}\x{6F70}\x{6F71}\x{6F72}' .
          '\x{6F73}\x{6F74}\x{6F75}\x{6F76}\x{6F77}\x{6F78}\x{6F7A}\x{6F7B}\x{6F7C}' .
          '\x{6F7D}\x{6F7E}\x{6F7F}\x{6F80}\x{6F81}\x{6F82}\x{6F83}\x{6F84}\x{6F85}' .
          '\x{6F86}\x{6F87}\x{6F88}\x{6F89}\x{6F8A}\x{6F8B}\x{6F8C}\x{6F8D}\x{6F8E}' .
          '\x{6F8F}\x{6F90}\x{6F91}\x{6F92}\x{6F93}\x{6F94}\x{6F95}\x{6F96}\x{6F97}' .
          '\x{6F99}\x{6F9B}\x{6F9C}\x{6F9D}\x{6F9E}\x{6FA0}\x{6FA1}\x{6FA2}\x{6FA3}' .
          '\x{6FA4}\x{6FA5}\x{6FA6}\x{6FA7}\x{6FA8}\x{6FA9}\x{6FAA}\x{6FAB}\x{6FAC}' .
          '\x{6FAD}\x{6FAE}\x{6FAF}\x{6FB0}\x{6FB1}\x{6FB2}\x{6FB3}\x{6FB4}\x{6FB5}' .
          '\x{6FB6}\x{6FB8}\x{6FB9}\x{6FBA}\x{6FBB}\x{6FBC}\x{6FBD}\x{6FBE}\x{6FBF}' .
          '\x{6FC0}\x{6FC1}\x{6FC2}\x{6FC3}\x{6FC4}\x{6FC6}\x{6FC7}\x{6FC8}\x{6FC9}' .
          '\x{6FCA}\x{6FCB}\x{6FCC}\x{6FCD}\x{6FCE}\x{6FCF}\x{6FD1}\x{6FD2}\x{6FD4}' .
          '\x{6FD5}\x{6FD6}\x{6FD7}\x{6FD8}\x{6FD9}\x{6FDA}\x{6FDB}\x{6FDC}\x{6FDD}' .
          '\x{6FDE}\x{6FDF}\x{6FE0}\x{6FE1}\x{6FE2}\x{6FE3}\x{6FE4}\x{6FE5}\x{6FE6}' .
          '\x{6FE7}\x{6FE8}\x{6FE9}\x{6FEA}\x{6FEB}\x{6FEC}\x{6FED}\x{6FEE}\x{6FEF}' .
          '\x{6FF0}\x{6FF1}\x{6FF2}\x{6FF3}\x{6FF4}\x{6FF6}\x{6FF7}\x{6FF8}\x{6FF9}' .
          '\x{6FFA}\x{6FFB}\x{6FFC}\x{6FFE}\x{6FFF}\x{7000}\x{7001}\x{7002}\x{7003}' .
          '\x{7004}\x{7005}\x{7006}\x{7007}\x{7008}\x{7009}\x{700A}\x{700B}\x{700C}' .
          '\x{700D}\x{700E}\x{700F}\x{7011}\x{7012}\x{7014}\x{7015}\x{7016}\x{7017}' .
          '\x{7018}\x{7019}\x{701A}\x{701B}\x{701C}\x{701D}\x{701F}\x{7020}\x{7021}' .
          '\x{7022}\x{7023}\x{7024}\x{7025}\x{7026}\x{7027}\x{7028}\x{7029}\x{702A}' .
          '\x{702B}\x{702C}\x{702D}\x{702E}\x{702F}\x{7030}\x{7031}\x{7032}\x{7033}' .
          '\x{7034}\x{7035}\x{7036}\x{7037}\x{7038}\x{7039}\x{703A}\x{703B}\x{703C}' .
          '\x{703D}\x{703E}\x{703F}\x{7040}\x{7041}\x{7042}\x{7043}\x{7044}\x{7045}' .
          '\x{7046}\x{7048}\x{7049}\x{704A}\x{704C}\x{704D}\x{704F}\x{7050}\x{7051}' .
          '\x{7052}\x{7053}\x{7054}\x{7055}\x{7056}\x{7057}\x{7058}\x{7059}\x{705A}' .
          '\x{705B}\x{705C}\x{705D}\x{705E}\x{705F}\x{7060}\x{7061}\x{7062}\x{7063}' .
          '\x{7064}\x{7065}\x{7066}\x{7067}\x{7068}\x{7069}\x{706A}\x{706B}\x{706C}' .
          '\x{706D}\x{706E}\x{706F}\x{7070}\x{7071}\x{7074}\x{7075}\x{7076}\x{7077}' .
          '\x{7078}\x{7079}\x{707A}\x{707C}\x{707D}\x{707E}\x{707F}\x{7080}\x{7082}' .
          '\x{7083}\x{7084}\x{7085}\x{7086}\x{7087}\x{7088}\x{7089}\x{708A}\x{708B}' .
          '\x{708C}\x{708E}\x{708F}\x{7090}\x{7091}\x{7092}\x{7093}\x{7094}\x{7095}' .
          '\x{7096}\x{7098}\x{7099}\x{709A}\x{709C}\x{709D}\x{709E}\x{709F}\x{70A0}' .
          '\x{70A1}\x{70A2}\x{70A3}\x{70A4}\x{70A5}\x{70A6}\x{70A7}\x{70A8}\x{70A9}' .
          '\x{70AB}\x{70AC}\x{70AD}\x{70AE}\x{70AF}\x{70B0}\x{70B1}\x{70B3}\x{70B4}' .
          '\x{70B5}\x{70B7}\x{70B8}\x{70B9}\x{70BA}\x{70BB}\x{70BC}\x{70BD}\x{70BE}' .
          '\x{70BF}\x{70C0}\x{70C1}\x{70C2}\x{70C3}\x{70C4}\x{70C5}\x{70C6}\x{70C7}' .
          '\x{70C8}\x{70C9}\x{70CA}\x{70CB}\x{70CC}\x{70CD}\x{70CE}\x{70CF}\x{70D0}' .
          '\x{70D1}\x{70D2}\x{70D3}\x{70D4}\x{70D6}\x{70D7}\x{70D8}\x{70D9}\x{70DA}' .
          '\x{70DB}\x{70DC}\x{70DD}\x{70DE}\x{70DF}\x{70E0}\x{70E1}\x{70E2}\x{70E3}' .
          '\x{70E4}\x{70E5}\x{70E6}\x{70E7}\x{70E8}\x{70E9}\x{70EA}\x{70EB}\x{70EC}' .
          '\x{70ED}\x{70EE}\x{70EF}\x{70F0}\x{70F1}\x{70F2}\x{70F3}\x{70F4}\x{70F5}' .
          '\x{70F6}\x{70F7}\x{70F8}\x{70F9}\x{70FA}\x{70FB}\x{70FC}\x{70FD}\x{70FF}' .
          '\x{7100}\x{7101}\x{7102}\x{7103}\x{7104}\x{7105}\x{7106}\x{7107}\x{7109}' .
          '\x{710A}\x{710B}\x{710C}\x{710D}\x{710E}\x{710F}\x{7110}\x{7111}\x{7112}' .
          '\x{7113}\x{7115}\x{7116}\x{7117}\x{7118}\x{7119}\x{711A}\x{711B}\x{711C}' .
          '\x{711D}\x{711E}\x{711F}\x{7120}\x{7121}\x{7122}\x{7123}\x{7125}\x{7126}' .
          '\x{7127}\x{7128}\x{7129}\x{712A}\x{712B}\x{712C}\x{712D}\x{712E}\x{712F}' .
          '\x{7130}\x{7131}\x{7132}\x{7135}\x{7136}\x{7137}\x{7138}\x{7139}\x{713A}' .
          '\x{713B}\x{713D}\x{713E}\x{713F}\x{7140}\x{7141}\x{7142}\x{7143}\x{7144}' .
          '\x{7145}\x{7146}\x{7147}\x{7148}\x{7149}\x{714A}\x{714B}\x{714C}\x{714D}' .
          '\x{714E}\x{714F}\x{7150}\x{7151}\x{7152}\x{7153}\x{7154}\x{7156}\x{7158}' .
          '\x{7159}\x{715A}\x{715B}\x{715C}\x{715D}\x{715E}\x{715F}\x{7160}\x{7161}' .
          '\x{7162}\x{7163}\x{7164}\x{7165}\x{7166}\x{7167}\x{7168}\x{7169}\x{716A}' .
          '\x{716C}\x{716E}\x{716F}\x{7170}\x{7171}\x{7172}\x{7173}\x{7174}\x{7175}' .
          '\x{7176}\x{7177}\x{7178}\x{7179}\x{717A}\x{717B}\x{717C}\x{717D}\x{717E}' .
          '\x{717F}\x{7180}\x{7181}\x{7182}\x{7183}\x{7184}\x{7185}\x{7186}\x{7187}' .
          '\x{7188}\x{7189}\x{718A}\x{718B}\x{718C}\x{718E}\x{718F}\x{7190}\x{7191}' .
          '\x{7192}\x{7193}\x{7194}\x{7195}\x{7197}\x{7198}\x{7199}\x{719A}\x{719B}' .
          '\x{719C}\x{719D}\x{719E}\x{719F}\x{71A0}\x{71A1}\x{71A2}\x{71A3}\x{71A4}' .
          '\x{71A5}\x{71A7}\x{71A8}\x{71A9}\x{71AA}\x{71AC}\x{71AD}\x{71AE}\x{71AF}' .
          '\x{71B0}\x{71B1}\x{71B2}\x{71B3}\x{71B4}\x{71B5}\x{71B7}\x{71B8}\x{71B9}' .
          '\x{71BA}\x{71BB}\x{71BC}\x{71BD}\x{71BE}\x{71BF}\x{71C0}\x{71C1}\x{71C2}' .
          '\x{71C3}\x{71C4}\x{71C5}\x{71C6}\x{71C7}\x{71C8}\x{71C9}\x{71CA}\x{71CB}' .
          '\x{71CD}\x{71CE}\x{71CF}\x{71D0}\x{71D1}\x{71D2}\x{71D4}\x{71D5}\x{71D6}' .
          '\x{71D7}\x{71D8}\x{71D9}\x{71DA}\x{71DB}\x{71DC}\x{71DD}\x{71DE}\x{71DF}' .
          '\x{71E0}\x{71E1}\x{71E2}\x{71E3}\x{71E4}\x{71E5}\x{71E6}\x{71E7}\x{71E8}' .
          '\x{71E9}\x{71EA}\x{71EB}\x{71EC}\x{71ED}\x{71EE}\x{71EF}\x{71F0}\x{71F1}' .
          '\x{71F2}\x{71F4}\x{71F5}\x{71F6}\x{71F7}\x{71F8}\x{71F9}\x{71FB}\x{71FC}' .
          '\x{71FD}\x{71FE}\x{71FF}\x{7201}\x{7202}\x{7203}\x{7204}\x{7205}\x{7206}' .
          '\x{7207}\x{7208}\x{7209}\x{720A}\x{720C}\x{720D}\x{720E}\x{720F}\x{7210}' .
          '\x{7212}\x{7213}\x{7214}\x{7216}\x{7218}\x{7219}\x{721A}\x{721B}\x{721C}' .
          '\x{721D}\x{721E}\x{721F}\x{7221}\x{7222}\x{7223}\x{7226}\x{7227}\x{7228}' .
          '\x{7229}\x{722A}\x{722B}\x{722C}\x{722D}\x{722E}\x{7230}\x{7231}\x{7232}' .
          '\x{7233}\x{7235}\x{7236}\x{7237}\x{7238}\x{7239}\x{723A}\x{723B}\x{723C}' .
          '\x{723D}\x{723E}\x{723F}\x{7240}\x{7241}\x{7242}\x{7243}\x{7244}\x{7246}' .
          '\x{7247}\x{7248}\x{7249}\x{724A}\x{724B}\x{724C}\x{724D}\x{724F}\x{7251}' .
          '\x{7252}\x{7253}\x{7254}\x{7256}\x{7257}\x{7258}\x{7259}\x{725A}\x{725B}' .
          '\x{725C}\x{725D}\x{725E}\x{725F}\x{7260}\x{7261}\x{7262}\x{7263}\x{7264}' .
          '\x{7265}\x{7266}\x{7267}\x{7268}\x{7269}\x{726A}\x{726B}\x{726C}\x{726D}' .
          '\x{726E}\x{726F}\x{7270}\x{7271}\x{7272}\x{7273}\x{7274}\x{7275}\x{7276}' .
          '\x{7277}\x{7278}\x{7279}\x{727A}\x{727B}\x{727C}\x{727D}\x{727E}\x{727F}' .
          '\x{7280}\x{7281}\x{7282}\x{7283}\x{7284}\x{7285}\x{7286}\x{7287}\x{7288}' .
          '\x{7289}\x{728A}\x{728B}\x{728C}\x{728D}\x{728E}\x{728F}\x{7290}\x{7291}' .
          '\x{7292}\x{7293}\x{7294}\x{7295}\x{7296}\x{7297}\x{7298}\x{7299}\x{729A}' .
          '\x{729B}\x{729C}\x{729D}\x{729E}\x{729F}\x{72A1}\x{72A2}\x{72A3}\x{72A4}' .
          '\x{72A5}\x{72A6}\x{72A7}\x{72A8}\x{72A9}\x{72AA}\x{72AC}\x{72AD}\x{72AE}' .
          '\x{72AF}\x{72B0}\x{72B1}\x{72B2}\x{72B3}\x{72B4}\x{72B5}\x{72B6}\x{72B7}' .
          '\x{72B8}\x{72B9}\x{72BA}\x{72BB}\x{72BC}\x{72BD}\x{72BF}\x{72C0}\x{72C1}' .
          '\x{72C2}\x{72C3}\x{72C4}\x{72C5}\x{72C6}\x{72C7}\x{72C8}\x{72C9}\x{72CA}' .
          '\x{72CB}\x{72CC}\x{72CD}\x{72CE}\x{72CF}\x{72D0}\x{72D1}\x{72D2}\x{72D3}' .
          '\x{72D4}\x{72D5}\x{72D6}\x{72D7}\x{72D8}\x{72D9}\x{72DA}\x{72DB}\x{72DC}' .
          '\x{72DD}\x{72DE}\x{72DF}\x{72E0}\x{72E1}\x{72E2}\x{72E3}\x{72E4}\x{72E5}' .
          '\x{72E6}\x{72E7}\x{72E8}\x{72E9}\x{72EA}\x{72EB}\x{72EC}\x{72ED}\x{72EE}' .
          '\x{72EF}\x{72F0}\x{72F1}\x{72F2}\x{72F3}\x{72F4}\x{72F5}\x{72F6}\x{72F7}' .
          '\x{72F8}\x{72F9}\x{72FA}\x{72FB}\x{72FC}\x{72FD}\x{72FE}\x{72FF}\x{7300}' .
          '\x{7301}\x{7303}\x{7304}\x{7305}\x{7306}\x{7307}\x{7308}\x{7309}\x{730A}' .
          '\x{730B}\x{730C}\x{730D}\x{730E}\x{730F}\x{7311}\x{7312}\x{7313}\x{7314}' .
          '\x{7315}\x{7316}\x{7317}\x{7318}\x{7319}\x{731A}\x{731B}\x{731C}\x{731D}' .
          '\x{731E}\x{7320}\x{7321}\x{7322}\x{7323}\x{7324}\x{7325}\x{7326}\x{7327}' .
          '\x{7329}\x{732A}\x{732B}\x{732C}\x{732D}\x{732E}\x{7330}\x{7331}\x{7332}' .
          '\x{7333}\x{7334}\x{7335}\x{7336}\x{7337}\x{7338}\x{7339}\x{733A}\x{733B}' .
          '\x{733C}\x{733D}\x{733E}\x{733F}\x{7340}\x{7341}\x{7342}\x{7343}\x{7344}' .
          '\x{7345}\x{7346}\x{7347}\x{7348}\x{7349}\x{734A}\x{734B}\x{734C}\x{734D}' .
          '\x{734E}\x{7350}\x{7351}\x{7352}\x{7354}\x{7355}\x{7356}\x{7357}\x{7358}' .
          '\x{7359}\x{735A}\x{735B}\x{735C}\x{735D}\x{735E}\x{735F}\x{7360}\x{7361}' .
          '\x{7362}\x{7364}\x{7365}\x{7366}\x{7367}\x{7368}\x{7369}\x{736A}\x{736B}' .
          '\x{736C}\x{736D}\x{736E}\x{736F}\x{7370}\x{7371}\x{7372}\x{7373}\x{7374}' .
          '\x{7375}\x{7376}\x{7377}\x{7378}\x{7379}\x{737A}\x{737B}\x{737C}\x{737D}' .
          '\x{737E}\x{737F}\x{7380}\x{7381}\x{7382}\x{7383}\x{7384}\x{7385}\x{7386}' .
          '\x{7387}\x{7388}\x{7389}\x{738A}\x{738B}\x{738C}\x{738D}\x{738E}\x{738F}' .
          '\x{7390}\x{7391}\x{7392}\x{7393}\x{7394}\x{7395}\x{7396}\x{7397}\x{7398}' .
          '\x{7399}\x{739A}\x{739B}\x{739D}\x{739E}\x{739F}\x{73A0}\x{73A1}\x{73A2}' .
          '\x{73A3}\x{73A4}\x{73A5}\x{73A6}\x{73A7}\x{73A8}\x{73A9}\x{73AA}\x{73AB}' .
          '\x{73AC}\x{73AD}\x{73AE}\x{73AF}\x{73B0}\x{73B1}\x{73B2}\x{73B3}\x{73B4}' .
          '\x{73B5}\x{73B6}\x{73B7}\x{73B8}\x{73B9}\x{73BA}\x{73BB}\x{73BC}\x{73BD}' .
          '\x{73BE}\x{73BF}\x{73C0}\x{73C2}\x{73C3}\x{73C4}\x{73C5}\x{73C6}\x{73C7}' .
          '\x{73C8}\x{73C9}\x{73CA}\x{73CB}\x{73CC}\x{73CD}\x{73CE}\x{73CF}\x{73D0}' .
          '\x{73D1}\x{73D2}\x{73D3}\x{73D4}\x{73D5}\x{73D6}\x{73D7}\x{73D8}\x{73D9}' .
          '\x{73DA}\x{73DB}\x{73DC}\x{73DD}\x{73DE}\x{73DF}\x{73E0}\x{73E2}\x{73E3}' .
          '\x{73E5}\x{73E6}\x{73E7}\x{73E8}\x{73E9}\x{73EA}\x{73EB}\x{73EC}\x{73ED}' .
          '\x{73EE}\x{73EF}\x{73F0}\x{73F1}\x{73F2}\x{73F4}\x{73F5}\x{73F6}\x{73F7}' .
          '\x{73F8}\x{73F9}\x{73FA}\x{73FC}\x{73FD}\x{73FE}\x{73FF}\x{7400}\x{7401}' .
          '\x{7402}\x{7403}\x{7404}\x{7405}\x{7406}\x{7407}\x{7408}\x{7409}\x{740A}' .
          '\x{740B}\x{740C}\x{740D}\x{740E}\x{740F}\x{7410}\x{7411}\x{7412}\x{7413}' .
          '\x{7414}\x{7415}\x{7416}\x{7417}\x{7419}\x{741A}\x{741B}\x{741C}\x{741D}' .
          '\x{741E}\x{741F}\x{7420}\x{7421}\x{7422}\x{7423}\x{7424}\x{7425}\x{7426}' .
          '\x{7427}\x{7428}\x{7429}\x{742A}\x{742B}\x{742C}\x{742D}\x{742E}\x{742F}' .
          '\x{7430}\x{7431}\x{7432}\x{7433}\x{7434}\x{7435}\x{7436}\x{7437}\x{7438}' .
          '\x{743A}\x{743B}\x{743C}\x{743D}\x{743F}\x{7440}\x{7441}\x{7442}\x{7443}' .
          '\x{7444}\x{7445}\x{7446}\x{7448}\x{744A}\x{744B}\x{744C}\x{744D}\x{744E}' .
          '\x{744F}\x{7450}\x{7451}\x{7452}\x{7453}\x{7454}\x{7455}\x{7456}\x{7457}' .
          '\x{7459}\x{745A}\x{745B}\x{745C}\x{745D}\x{745E}\x{745F}\x{7461}\x{7462}' .
          '\x{7463}\x{7464}\x{7465}\x{7466}\x{7467}\x{7468}\x{7469}\x{746A}\x{746B}' .
          '\x{746C}\x{746D}\x{746E}\x{746F}\x{7470}\x{7471}\x{7472}\x{7473}\x{7474}' .
          '\x{7475}\x{7476}\x{7477}\x{7478}\x{7479}\x{747A}\x{747C}\x{747D}\x{747E}' .
          '\x{747F}\x{7480}\x{7481}\x{7482}\x{7483}\x{7485}\x{7486}\x{7487}\x{7488}' .
          '\x{7489}\x{748A}\x{748B}\x{748C}\x{748D}\x{748E}\x{748F}\x{7490}\x{7491}' .
          '\x{7492}\x{7493}\x{7494}\x{7495}\x{7497}\x{7498}\x{7499}\x{749A}\x{749B}' .
          '\x{749C}\x{749E}\x{749F}\x{74A0}\x{74A1}\x{74A3}\x{74A4}\x{74A5}\x{74A6}' .
          '\x{74A7}\x{74A8}\x{74A9}\x{74AA}\x{74AB}\x{74AC}\x{74AD}\x{74AE}\x{74AF}' .
          '\x{74B0}\x{74B1}\x{74B2}\x{74B3}\x{74B4}\x{74B5}\x{74B6}\x{74B7}\x{74B8}' .
          '\x{74B9}\x{74BA}\x{74BB}\x{74BC}\x{74BD}\x{74BE}\x{74BF}\x{74C0}\x{74C1}' .
          '\x{74C2}\x{74C3}\x{74C4}\x{74C5}\x{74C6}\x{74CA}\x{74CB}\x{74CD}\x{74CE}' .
          '\x{74CF}\x{74D0}\x{74D1}\x{74D2}\x{74D3}\x{74D4}\x{74D5}\x{74D6}\x{74D7}' .
          '\x{74D8}\x{74D9}\x{74DA}\x{74DB}\x{74DC}\x{74DD}\x{74DE}\x{74DF}\x{74E0}' .
          '\x{74E1}\x{74E2}\x{74E3}\x{74E4}\x{74E5}\x{74E6}\x{74E7}\x{74E8}\x{74E9}' .
          '\x{74EA}\x{74EC}\x{74ED}\x{74EE}\x{74EF}\x{74F0}\x{74F1}\x{74F2}\x{74F3}' .
          '\x{74F4}\x{74F5}\x{74F6}\x{74F7}\x{74F8}\x{74F9}\x{74FA}\x{74FB}\x{74FC}' .
          '\x{74FD}\x{74FE}\x{74FF}\x{7500}\x{7501}\x{7502}\x{7503}\x{7504}\x{7505}' .
          '\x{7506}\x{7507}\x{7508}\x{7509}\x{750A}\x{750B}\x{750C}\x{750D}\x{750F}' .
          '\x{7510}\x{7511}\x{7512}\x{7513}\x{7514}\x{7515}\x{7516}\x{7517}\x{7518}' .
          '\x{7519}\x{751A}\x{751B}\x{751C}\x{751D}\x{751E}\x{751F}\x{7521}\x{7522}' .
          '\x{7523}\x{7524}\x{7525}\x{7526}\x{7527}\x{7528}\x{7529}\x{752A}\x{752B}' .
          '\x{752C}\x{752D}\x{752E}\x{752F}\x{7530}\x{7531}\x{7532}\x{7533}\x{7535}' .
          '\x{7536}\x{7537}\x{7538}\x{7539}\x{753A}\x{753B}\x{753C}\x{753D}\x{753E}' .
          '\x{753F}\x{7540}\x{7542}\x{7543}\x{7544}\x{7545}\x{7546}\x{7547}\x{7548}' .
          '\x{7549}\x{754B}\x{754C}\x{754D}\x{754E}\x{754F}\x{7550}\x{7551}\x{7553}' .
          '\x{7554}\x{7556}\x{7557}\x{7558}\x{7559}\x{755A}\x{755B}\x{755C}\x{755D}' .
          '\x{755F}\x{7560}\x{7562}\x{7563}\x{7564}\x{7565}\x{7566}\x{7567}\x{7568}' .
          '\x{7569}\x{756A}\x{756B}\x{756C}\x{756D}\x{756E}\x{756F}\x{7570}\x{7572}' .
          '\x{7574}\x{7575}\x{7576}\x{7577}\x{7578}\x{7579}\x{757C}\x{757D}\x{757E}' .
          '\x{757F}\x{7580}\x{7581}\x{7582}\x{7583}\x{7584}\x{7586}\x{7587}\x{7588}' .
          '\x{7589}\x{758A}\x{758B}\x{758C}\x{758D}\x{758F}\x{7590}\x{7591}\x{7592}' .
          '\x{7593}\x{7594}\x{7595}\x{7596}\x{7597}\x{7598}\x{7599}\x{759A}\x{759B}' .
          '\x{759C}\x{759D}\x{759E}\x{759F}\x{75A0}\x{75A1}\x{75A2}\x{75A3}\x{75A4}' .
          '\x{75A5}\x{75A6}\x{75A7}\x{75A8}\x{75AA}\x{75AB}\x{75AC}\x{75AD}\x{75AE}' .
          '\x{75AF}\x{75B0}\x{75B1}\x{75B2}\x{75B3}\x{75B4}\x{75B5}\x{75B6}\x{75B8}' .
          '\x{75B9}\x{75BA}\x{75BB}\x{75BC}\x{75BD}\x{75BE}\x{75BF}\x{75C0}\x{75C1}' .
          '\x{75C2}\x{75C3}\x{75C4}\x{75C5}\x{75C6}\x{75C7}\x{75C8}\x{75C9}\x{75CA}' .
          '\x{75CB}\x{75CC}\x{75CD}\x{75CE}\x{75CF}\x{75D0}\x{75D1}\x{75D2}\x{75D3}' .
          '\x{75D4}\x{75D5}\x{75D6}\x{75D7}\x{75D8}\x{75D9}\x{75DA}\x{75DB}\x{75DD}' .
          '\x{75DE}\x{75DF}\x{75E0}\x{75E1}\x{75E2}\x{75E3}\x{75E4}\x{75E5}\x{75E6}' .
          '\x{75E7}\x{75E8}\x{75EA}\x{75EB}\x{75EC}\x{75ED}\x{75EF}\x{75F0}\x{75F1}' .
          '\x{75F2}\x{75F3}\x{75F4}\x{75F5}\x{75F6}\x{75F7}\x{75F8}\x{75F9}\x{75FA}' .
          '\x{75FB}\x{75FC}\x{75FD}\x{75FE}\x{75FF}\x{7600}\x{7601}\x{7602}\x{7603}' .
          '\x{7604}\x{7605}\x{7606}\x{7607}\x{7608}\x{7609}\x{760A}\x{760B}\x{760C}' .
          '\x{760D}\x{760E}\x{760F}\x{7610}\x{7611}\x{7612}\x{7613}\x{7614}\x{7615}' .
          '\x{7616}\x{7617}\x{7618}\x{7619}\x{761A}\x{761B}\x{761C}\x{761D}\x{761E}' .
          '\x{761F}\x{7620}\x{7621}\x{7622}\x{7623}\x{7624}\x{7625}\x{7626}\x{7627}' .
          '\x{7628}\x{7629}\x{762A}\x{762B}\x{762D}\x{762E}\x{762F}\x{7630}\x{7631}' .
          '\x{7632}\x{7633}\x{7634}\x{7635}\x{7636}\x{7637}\x{7638}\x{7639}\x{763A}' .
          '\x{763B}\x{763C}\x{763D}\x{763E}\x{763F}\x{7640}\x{7641}\x{7642}\x{7643}' .
          '\x{7646}\x{7647}\x{7648}\x{7649}\x{764A}\x{764B}\x{764C}\x{764D}\x{764F}' .
          '\x{7650}\x{7652}\x{7653}\x{7654}\x{7656}\x{7657}\x{7658}\x{7659}\x{765A}' .
          '\x{765B}\x{765C}\x{765D}\x{765E}\x{765F}\x{7660}\x{7661}\x{7662}\x{7663}' .
          '\x{7664}\x{7665}\x{7666}\x{7667}\x{7668}\x{7669}\x{766A}\x{766B}\x{766C}' .
          '\x{766D}\x{766E}\x{766F}\x{7670}\x{7671}\x{7672}\x{7674}\x{7675}\x{7676}' .
          '\x{7677}\x{7678}\x{7679}\x{767B}\x{767C}\x{767D}\x{767E}\x{767F}\x{7680}' .
          '\x{7681}\x{7682}\x{7683}\x{7684}\x{7685}\x{7686}\x{7687}\x{7688}\x{7689}' .
          '\x{768A}\x{768B}\x{768C}\x{768E}\x{768F}\x{7690}\x{7691}\x{7692}\x{7693}' .
          '\x{7694}\x{7695}\x{7696}\x{7697}\x{7698}\x{7699}\x{769A}\x{769B}\x{769C}' .
          '\x{769D}\x{769E}\x{769F}\x{76A0}\x{76A3}\x{76A4}\x{76A6}\x{76A7}\x{76A9}' .
          '\x{76AA}\x{76AB}\x{76AC}\x{76AD}\x{76AE}\x{76AF}\x{76B0}\x{76B1}\x{76B2}' .
          '\x{76B4}\x{76B5}\x{76B7}\x{76B8}\x{76BA}\x{76BB}\x{76BC}\x{76BD}\x{76BE}' .
          '\x{76BF}\x{76C0}\x{76C2}\x{76C3}\x{76C4}\x{76C5}\x{76C6}\x{76C7}\x{76C8}' .
          '\x{76C9}\x{76CA}\x{76CD}\x{76CE}\x{76CF}\x{76D0}\x{76D1}\x{76D2}\x{76D3}' .
          '\x{76D4}\x{76D5}\x{76D6}\x{76D7}\x{76D8}\x{76DA}\x{76DB}\x{76DC}\x{76DD}' .
          '\x{76DE}\x{76DF}\x{76E0}\x{76E1}\x{76E2}\x{76E3}\x{76E4}\x{76E5}\x{76E6}' .
          '\x{76E7}\x{76E8}\x{76E9}\x{76EA}\x{76EC}\x{76ED}\x{76EE}\x{76EF}\x{76F0}' .
          '\x{76F1}\x{76F2}\x{76F3}\x{76F4}\x{76F5}\x{76F6}\x{76F7}\x{76F8}\x{76F9}' .
          '\x{76FA}\x{76FB}\x{76FC}\x{76FD}\x{76FE}\x{76FF}\x{7701}\x{7703}\x{7704}' .
          '\x{7705}\x{7706}\x{7707}\x{7708}\x{7709}\x{770A}\x{770B}\x{770C}\x{770D}' .
          '\x{770F}\x{7710}\x{7711}\x{7712}\x{7713}\x{7714}\x{7715}\x{7716}\x{7717}' .
          '\x{7718}\x{7719}\x{771A}\x{771B}\x{771C}\x{771D}\x{771E}\x{771F}\x{7720}' .
          '\x{7722}\x{7723}\x{7725}\x{7726}\x{7727}\x{7728}\x{7729}\x{772A}\x{772C}' .
          '\x{772D}\x{772E}\x{772F}\x{7730}\x{7731}\x{7732}\x{7733}\x{7734}\x{7735}' .
          '\x{7736}\x{7737}\x{7738}\x{7739}\x{773A}\x{773B}\x{773C}\x{773D}\x{773E}' .
          '\x{7740}\x{7741}\x{7743}\x{7744}\x{7745}\x{7746}\x{7747}\x{7748}\x{7749}' .
          '\x{774A}\x{774B}\x{774C}\x{774D}\x{774E}\x{774F}\x{7750}\x{7751}\x{7752}' .
          '\x{7753}\x{7754}\x{7755}\x{7756}\x{7757}\x{7758}\x{7759}\x{775A}\x{775B}' .
          '\x{775C}\x{775D}\x{775E}\x{775F}\x{7760}\x{7761}\x{7762}\x{7763}\x{7765}' .
          '\x{7766}\x{7767}\x{7768}\x{7769}\x{776A}\x{776B}\x{776C}\x{776D}\x{776E}' .
          '\x{776F}\x{7770}\x{7771}\x{7772}\x{7773}\x{7774}\x{7775}\x{7776}\x{7777}' .
          '\x{7778}\x{7779}\x{777A}\x{777B}\x{777C}\x{777D}\x{777E}\x{777F}\x{7780}' .
          '\x{7781}\x{7782}\x{7783}\x{7784}\x{7785}\x{7786}\x{7787}\x{7788}\x{7789}' .
          '\x{778A}\x{778B}\x{778C}\x{778D}\x{778E}\x{778F}\x{7790}\x{7791}\x{7792}' .
          '\x{7793}\x{7794}\x{7795}\x{7797}\x{7798}\x{7799}\x{779A}\x{779B}\x{779C}' .
          '\x{779D}\x{779E}\x{779F}\x{77A0}\x{77A1}\x{77A2}\x{77A3}\x{77A5}\x{77A6}' .
          '\x{77A7}\x{77A8}\x{77A9}\x{77AA}\x{77AB}\x{77AC}\x{77AD}\x{77AE}\x{77AF}' .
          '\x{77B0}\x{77B1}\x{77B2}\x{77B3}\x{77B4}\x{77B5}\x{77B6}\x{77B7}\x{77B8}' .
          '\x{77B9}\x{77BA}\x{77BB}\x{77BC}\x{77BD}\x{77BF}\x{77C0}\x{77C2}\x{77C3}' .
          '\x{77C4}\x{77C5}\x{77C6}\x{77C7}\x{77C8}\x{77C9}\x{77CA}\x{77CB}\x{77CC}' .
          '\x{77CD}\x{77CE}\x{77CF}\x{77D0}\x{77D1}\x{77D3}\x{77D4}\x{77D5}\x{77D6}' .
          '\x{77D7}\x{77D8}\x{77D9}\x{77DA}\x{77DB}\x{77DC}\x{77DE}\x{77DF}\x{77E0}' .
          '\x{77E1}\x{77E2}\x{77E3}\x{77E5}\x{77E7}\x{77E8}\x{77E9}\x{77EA}\x{77EB}' .
          '\x{77EC}\x{77ED}\x{77EE}\x{77EF}\x{77F0}\x{77F1}\x{77F2}\x{77F3}\x{77F6}' .
          '\x{77F7}\x{77F8}\x{77F9}\x{77FA}\x{77FB}\x{77FC}\x{77FD}\x{77FE}\x{77FF}' .
          '\x{7800}\x{7801}\x{7802}\x{7803}\x{7804}\x{7805}\x{7806}\x{7808}\x{7809}' .
          '\x{780A}\x{780B}\x{780C}\x{780D}\x{780E}\x{780F}\x{7810}\x{7811}\x{7812}' .
          '\x{7813}\x{7814}\x{7815}\x{7816}\x{7817}\x{7818}\x{7819}\x{781A}\x{781B}' .
          '\x{781C}\x{781D}\x{781E}\x{781F}\x{7820}\x{7821}\x{7822}\x{7823}\x{7825}' .
          '\x{7826}\x{7827}\x{7828}\x{7829}\x{782A}\x{782B}\x{782C}\x{782D}\x{782E}' .
          '\x{782F}\x{7830}\x{7831}\x{7832}\x{7833}\x{7834}\x{7835}\x{7837}\x{7838}' .
          '\x{7839}\x{783A}\x{783B}\x{783C}\x{783D}\x{783E}\x{7840}\x{7841}\x{7843}' .
          '\x{7844}\x{7845}\x{7847}\x{7848}\x{7849}\x{784A}\x{784C}\x{784D}\x{784E}' .
          '\x{7850}\x{7851}\x{7852}\x{7853}\x{7854}\x{7855}\x{7856}\x{7857}\x{7858}' .
          '\x{7859}\x{785A}\x{785B}\x{785C}\x{785D}\x{785E}\x{785F}\x{7860}\x{7861}' .
          '\x{7862}\x{7863}\x{7864}\x{7865}\x{7866}\x{7867}\x{7868}\x{7869}\x{786A}' .
          '\x{786B}\x{786C}\x{786D}\x{786E}\x{786F}\x{7870}\x{7871}\x{7872}\x{7873}' .
          '\x{7874}\x{7875}\x{7877}\x{7878}\x{7879}\x{787A}\x{787B}\x{787C}\x{787D}' .
          '\x{787E}\x{787F}\x{7880}\x{7881}\x{7882}\x{7883}\x{7884}\x{7885}\x{7886}' .
          '\x{7887}\x{7889}\x{788A}\x{788B}\x{788C}\x{788D}\x{788E}\x{788F}\x{7890}' .
          '\x{7891}\x{7892}\x{7893}\x{7894}\x{7895}\x{7896}\x{7897}\x{7898}\x{7899}' .
          '\x{789A}\x{789B}\x{789C}\x{789D}\x{789E}\x{789F}\x{78A0}\x{78A1}\x{78A2}' .
          '\x{78A3}\x{78A4}\x{78A5}\x{78A6}\x{78A7}\x{78A8}\x{78A9}\x{78AA}\x{78AB}' .
          '\x{78AC}\x{78AD}\x{78AE}\x{78AF}\x{78B0}\x{78B1}\x{78B2}\x{78B3}\x{78B4}' .
          '\x{78B5}\x{78B6}\x{78B7}\x{78B8}\x{78B9}\x{78BA}\x{78BB}\x{78BC}\x{78BD}' .
          '\x{78BE}\x{78BF}\x{78C0}\x{78C1}\x{78C3}\x{78C4}\x{78C5}\x{78C6}\x{78C8}' .
          '\x{78C9}\x{78CA}\x{78CB}\x{78CC}\x{78CD}\x{78CE}\x{78CF}\x{78D0}\x{78D1}' .
          '\x{78D3}\x{78D4}\x{78D5}\x{78D6}\x{78D7}\x{78D8}\x{78D9}\x{78DA}\x{78DB}' .
          '\x{78DC}\x{78DD}\x{78DE}\x{78DF}\x{78E0}\x{78E1}\x{78E2}\x{78E3}\x{78E4}' .
          '\x{78E5}\x{78E6}\x{78E7}\x{78E8}\x{78E9}\x{78EA}\x{78EB}\x{78EC}\x{78ED}' .
          '\x{78EE}\x{78EF}\x{78F1}\x{78F2}\x{78F3}\x{78F4}\x{78F5}\x{78F6}\x{78F7}' .
          '\x{78F9}\x{78FA}\x{78FB}\x{78FC}\x{78FD}\x{78FE}\x{78FF}\x{7901}\x{7902}' .
          '\x{7903}\x{7904}\x{7905}\x{7906}\x{7907}\x{7909}\x{790A}\x{790B}\x{790C}' .
          '\x{790E}\x{790F}\x{7910}\x{7911}\x{7912}\x{7913}\x{7914}\x{7916}\x{7917}' .
          '\x{7918}\x{7919}\x{791A}\x{791B}\x{791C}\x{791D}\x{791E}\x{7921}\x{7922}' .
          '\x{7923}\x{7924}\x{7925}\x{7926}\x{7927}\x{7928}\x{7929}\x{792A}\x{792B}' .
          '\x{792C}\x{792D}\x{792E}\x{792F}\x{7930}\x{7931}\x{7933}\x{7934}\x{7935}' .
          '\x{7937}\x{7938}\x{7939}\x{793A}\x{793B}\x{793C}\x{793D}\x{793E}\x{793F}' .
          '\x{7940}\x{7941}\x{7942}\x{7943}\x{7944}\x{7945}\x{7946}\x{7947}\x{7948}' .
          '\x{7949}\x{794A}\x{794B}\x{794C}\x{794D}\x{794E}\x{794F}\x{7950}\x{7951}' .
          '\x{7952}\x{7953}\x{7954}\x{7955}\x{7956}\x{7957}\x{7958}\x{795A}\x{795B}' .
          '\x{795C}\x{795D}\x{795E}\x{795F}\x{7960}\x{7961}\x{7962}\x{7963}\x{7964}' .
          '\x{7965}\x{7966}\x{7967}\x{7968}\x{7969}\x{796A}\x{796B}\x{796D}\x{796F}' .
          '\x{7970}\x{7971}\x{7972}\x{7973}\x{7974}\x{7977}\x{7978}\x{7979}\x{797A}' .
          '\x{797B}\x{797C}\x{797D}\x{797E}\x{797F}\x{7980}\x{7981}\x{7982}\x{7983}' .
          '\x{7984}\x{7985}\x{7988}\x{7989}\x{798A}\x{798B}\x{798C}\x{798D}\x{798E}' .
          '\x{798F}\x{7990}\x{7991}\x{7992}\x{7993}\x{7994}\x{7995}\x{7996}\x{7997}' .
          '\x{7998}\x{7999}\x{799A}\x{799B}\x{799C}\x{799F}\x{79A0}\x{79A1}\x{79A2}' .
          '\x{79A3}\x{79A4}\x{79A5}\x{79A6}\x{79A7}\x{79A8}\x{79AA}\x{79AB}\x{79AC}' .
          '\x{79AD}\x{79AE}\x{79AF}\x{79B0}\x{79B1}\x{79B2}\x{79B3}\x{79B4}\x{79B5}' .
          '\x{79B6}\x{79B7}\x{79B8}\x{79B9}\x{79BA}\x{79BB}\x{79BD}\x{79BE}\x{79BF}' .
          '\x{79C0}\x{79C1}\x{79C2}\x{79C3}\x{79C5}\x{79C6}\x{79C8}\x{79C9}\x{79CA}' .
          '\x{79CB}\x{79CD}\x{79CE}\x{79CF}\x{79D0}\x{79D1}\x{79D2}\x{79D3}\x{79D5}' .
          '\x{79D6}\x{79D8}\x{79D9}\x{79DA}\x{79DB}\x{79DC}\x{79DD}\x{79DE}\x{79DF}' .
          '\x{79E0}\x{79E1}\x{79E2}\x{79E3}\x{79E4}\x{79E5}\x{79E6}\x{79E7}\x{79E8}' .
          '\x{79E9}\x{79EA}\x{79EB}\x{79EC}\x{79ED}\x{79EE}\x{79EF}\x{79F0}\x{79F1}' .
          '\x{79F2}\x{79F3}\x{79F4}\x{79F5}\x{79F6}\x{79F7}\x{79F8}\x{79F9}\x{79FA}' .
          '\x{79FB}\x{79FC}\x{79FD}\x{79FE}\x{79FF}\x{7A00}\x{7A02}\x{7A03}\x{7A04}' .
          '\x{7A05}\x{7A06}\x{7A08}\x{7A0A}\x{7A0B}\x{7A0C}\x{7A0D}\x{7A0E}\x{7A0F}' .
          '\x{7A10}\x{7A11}\x{7A12}\x{7A13}\x{7A14}\x{7A15}\x{7A16}\x{7A17}\x{7A18}' .
          '\x{7A19}\x{7A1A}\x{7A1B}\x{7A1C}\x{7A1D}\x{7A1E}\x{7A1F}\x{7A20}\x{7A21}' .
          '\x{7A22}\x{7A23}\x{7A24}\x{7A25}\x{7A26}\x{7A27}\x{7A28}\x{7A29}\x{7A2A}' .
          '\x{7A2B}\x{7A2D}\x{7A2E}\x{7A2F}\x{7A30}\x{7A31}\x{7A32}\x{7A33}\x{7A34}' .
          '\x{7A35}\x{7A37}\x{7A39}\x{7A3B}\x{7A3C}\x{7A3D}\x{7A3E}\x{7A3F}\x{7A40}' .
          '\x{7A41}\x{7A42}\x{7A43}\x{7A44}\x{7A45}\x{7A46}\x{7A47}\x{7A48}\x{7A49}' .
          '\x{7A4A}\x{7A4B}\x{7A4C}\x{7A4D}\x{7A4E}\x{7A50}\x{7A51}\x{7A52}\x{7A53}' .
          '\x{7A54}\x{7A55}\x{7A56}\x{7A57}\x{7A58}\x{7A59}\x{7A5A}\x{7A5B}\x{7A5C}' .
          '\x{7A5D}\x{7A5E}\x{7A5F}\x{7A60}\x{7A61}\x{7A62}\x{7A65}\x{7A66}\x{7A67}' .
          '\x{7A68}\x{7A69}\x{7A6B}\x{7A6C}\x{7A6D}\x{7A6E}\x{7A70}\x{7A71}\x{7A72}' .
          '\x{7A73}\x{7A74}\x{7A75}\x{7A76}\x{7A77}\x{7A78}\x{7A79}\x{7A7A}\x{7A7B}' .
          '\x{7A7C}\x{7A7D}\x{7A7E}\x{7A7F}\x{7A80}\x{7A81}\x{7A83}\x{7A84}\x{7A85}' .
          '\x{7A86}\x{7A87}\x{7A88}\x{7A89}\x{7A8A}\x{7A8B}\x{7A8C}\x{7A8D}\x{7A8E}' .
          '\x{7A8F}\x{7A90}\x{7A91}\x{7A92}\x{7A93}\x{7A94}\x{7A95}\x{7A96}\x{7A97}' .
          '\x{7A98}\x{7A99}\x{7A9C}\x{7A9D}\x{7A9E}\x{7A9F}\x{7AA0}\x{7AA1}\x{7AA2}' .
          '\x{7AA3}\x{7AA4}\x{7AA5}\x{7AA6}\x{7AA7}\x{7AA8}\x{7AA9}\x{7AAA}\x{7AAB}' .
          '\x{7AAC}\x{7AAD}\x{7AAE}\x{7AAF}\x{7AB0}\x{7AB1}\x{7AB2}\x{7AB3}\x{7AB4}' .
          '\x{7AB5}\x{7AB6}\x{7AB7}\x{7AB8}\x{7ABA}\x{7ABE}\x{7ABF}\x{7AC0}\x{7AC1}' .
          '\x{7AC4}\x{7AC5}\x{7AC7}\x{7AC8}\x{7AC9}\x{7ACA}\x{7ACB}\x{7ACC}\x{7ACD}' .
          '\x{7ACE}\x{7ACF}\x{7AD0}\x{7AD1}\x{7AD2}\x{7AD3}\x{7AD4}\x{7AD5}\x{7AD6}' .
          '\x{7AD8}\x{7AD9}\x{7ADB}\x{7ADC}\x{7ADD}\x{7ADE}\x{7ADF}\x{7AE0}\x{7AE1}' .
          '\x{7AE2}\x{7AE3}\x{7AE4}\x{7AE5}\x{7AE6}\x{7AE7}\x{7AE8}\x{7AEA}\x{7AEB}' .
          '\x{7AEC}\x{7AED}\x{7AEE}\x{7AEF}\x{7AF0}\x{7AF1}\x{7AF2}\x{7AF3}\x{7AF4}' .
          '\x{7AF6}\x{7AF7}\x{7AF8}\x{7AF9}\x{7AFA}\x{7AFB}\x{7AFD}\x{7AFE}\x{7AFF}' .
          '\x{7B00}\x{7B01}\x{7B02}\x{7B03}\x{7B04}\x{7B05}\x{7B06}\x{7B08}\x{7B09}' .
          '\x{7B0A}\x{7B0B}\x{7B0C}\x{7B0D}\x{7B0E}\x{7B0F}\x{7B10}\x{7B11}\x{7B12}' .
          '\x{7B13}\x{7B14}\x{7B15}\x{7B16}\x{7B17}\x{7B18}\x{7B19}\x{7B1A}\x{7B1B}' .
          '\x{7B1C}\x{7B1D}\x{7B1E}\x{7B20}\x{7B21}\x{7B22}\x{7B23}\x{7B24}\x{7B25}' .
          '\x{7B26}\x{7B28}\x{7B2A}\x{7B2B}\x{7B2C}\x{7B2D}\x{7B2E}\x{7B2F}\x{7B30}' .
          '\x{7B31}\x{7B32}\x{7B33}\x{7B34}\x{7B35}\x{7B36}\x{7B37}\x{7B38}\x{7B39}' .
          '\x{7B3A}\x{7B3B}\x{7B3C}\x{7B3D}\x{7B3E}\x{7B3F}\x{7B40}\x{7B41}\x{7B43}' .
          '\x{7B44}\x{7B45}\x{7B46}\x{7B47}\x{7B48}\x{7B49}\x{7B4A}\x{7B4B}\x{7B4C}' .
          '\x{7B4D}\x{7B4E}\x{7B4F}\x{7B50}\x{7B51}\x{7B52}\x{7B54}\x{7B55}\x{7B56}' .
          '\x{7B57}\x{7B58}\x{7B59}\x{7B5A}\x{7B5B}\x{7B5C}\x{7B5D}\x{7B5E}\x{7B5F}' .
          '\x{7B60}\x{7B61}\x{7B62}\x{7B63}\x{7B64}\x{7B65}\x{7B66}\x{7B67}\x{7B68}' .
          '\x{7B69}\x{7B6A}\x{7B6B}\x{7B6C}\x{7B6D}\x{7B6E}\x{7B70}\x{7B71}\x{7B72}' .
          '\x{7B73}\x{7B74}\x{7B75}\x{7B76}\x{7B77}\x{7B78}\x{7B79}\x{7B7B}\x{7B7C}' .
          '\x{7B7D}\x{7B7E}\x{7B7F}\x{7B80}\x{7B81}\x{7B82}\x{7B83}\x{7B84}\x{7B85}' .
          '\x{7B87}\x{7B88}\x{7B89}\x{7B8A}\x{7B8B}\x{7B8C}\x{7B8D}\x{7B8E}\x{7B8F}' .
          '\x{7B90}\x{7B91}\x{7B93}\x{7B94}\x{7B95}\x{7B96}\x{7B97}\x{7B98}\x{7B99}' .
          '\x{7B9A}\x{7B9B}\x{7B9C}\x{7B9D}\x{7B9E}\x{7B9F}\x{7BA0}\x{7BA1}\x{7BA2}' .
          '\x{7BA4}\x{7BA6}\x{7BA7}\x{7BA8}\x{7BA9}\x{7BAA}\x{7BAB}\x{7BAC}\x{7BAD}' .
          '\x{7BAE}\x{7BAF}\x{7BB1}\x{7BB3}\x{7BB4}\x{7BB5}\x{7BB6}\x{7BB7}\x{7BB8}' .
          '\x{7BB9}\x{7BBA}\x{7BBB}\x{7BBC}\x{7BBD}\x{7BBE}\x{7BBF}\x{7BC0}\x{7BC1}' .
          '\x{7BC2}\x{7BC3}\x{7BC4}\x{7BC5}\x{7BC6}\x{7BC7}\x{7BC8}\x{7BC9}\x{7BCA}' .
          '\x{7BCB}\x{7BCC}\x{7BCD}\x{7BCE}\x{7BD0}\x{7BD1}\x{7BD2}\x{7BD3}\x{7BD4}' .
          '\x{7BD5}\x{7BD6}\x{7BD7}\x{7BD8}\x{7BD9}\x{7BDA}\x{7BDB}\x{7BDC}\x{7BDD}' .
          '\x{7BDE}\x{7BDF}\x{7BE0}\x{7BE1}\x{7BE2}\x{7BE3}\x{7BE4}\x{7BE5}\x{7BE6}' .
          '\x{7BE7}\x{7BE8}\x{7BE9}\x{7BEA}\x{7BEB}\x{7BEC}\x{7BED}\x{7BEE}\x{7BEF}' .
          '\x{7BF0}\x{7BF1}\x{7BF2}\x{7BF3}\x{7BF4}\x{7BF5}\x{7BF6}\x{7BF7}\x{7BF8}' .
          '\x{7BF9}\x{7BFB}\x{7BFC}\x{7BFD}\x{7BFE}\x{7BFF}\x{7C00}\x{7C01}\x{7C02}' .
          '\x{7C03}\x{7C04}\x{7C05}\x{7C06}\x{7C07}\x{7C08}\x{7C09}\x{7C0A}\x{7C0B}' .
          '\x{7C0C}\x{7C0D}\x{7C0E}\x{7C0F}\x{7C10}\x{7C11}\x{7C12}\x{7C13}\x{7C15}' .
          '\x{7C16}\x{7C17}\x{7C18}\x{7C19}\x{7C1A}\x{7C1C}\x{7C1D}\x{7C1E}\x{7C1F}' .
          '\x{7C20}\x{7C21}\x{7C22}\x{7C23}\x{7C24}\x{7C25}\x{7C26}\x{7C27}\x{7C28}' .
          '\x{7C29}\x{7C2A}\x{7C2B}\x{7C2C}\x{7C2D}\x{7C30}\x{7C31}\x{7C32}\x{7C33}' .
          '\x{7C34}\x{7C35}\x{7C36}\x{7C37}\x{7C38}\x{7C39}\x{7C3A}\x{7C3B}\x{7C3C}' .
          '\x{7C3D}\x{7C3E}\x{7C3F}\x{7C40}\x{7C41}\x{7C42}\x{7C43}\x{7C44}\x{7C45}' .
          '\x{7C46}\x{7C47}\x{7C48}\x{7C49}\x{7C4A}\x{7C4B}\x{7C4C}\x{7C4D}\x{7C4E}' .
          '\x{7C50}\x{7C51}\x{7C53}\x{7C54}\x{7C56}\x{7C57}\x{7C58}\x{7C59}\x{7C5A}' .
          '\x{7C5B}\x{7C5C}\x{7C5E}\x{7C5F}\x{7C60}\x{7C61}\x{7C62}\x{7C63}\x{7C64}' .
          '\x{7C65}\x{7C66}\x{7C67}\x{7C68}\x{7C69}\x{7C6A}\x{7C6B}\x{7C6C}\x{7C6D}' .
          '\x{7C6E}\x{7C6F}\x{7C70}\x{7C71}\x{7C72}\x{7C73}\x{7C74}\x{7C75}\x{7C77}' .
          '\x{7C78}\x{7C79}\x{7C7A}\x{7C7B}\x{7C7C}\x{7C7D}\x{7C7E}\x{7C7F}\x{7C80}' .
          '\x{7C81}\x{7C82}\x{7C84}\x{7C85}\x{7C86}\x{7C88}\x{7C89}\x{7C8A}\x{7C8B}' .
          '\x{7C8C}\x{7C8D}\x{7C8E}\x{7C8F}\x{7C90}\x{7C91}\x{7C92}\x{7C94}\x{7C95}' .
          '\x{7C96}\x{7C97}\x{7C98}\x{7C99}\x{7C9B}\x{7C9C}\x{7C9D}\x{7C9E}\x{7C9F}' .
          '\x{7CA0}\x{7CA1}\x{7CA2}\x{7CA3}\x{7CA4}\x{7CA5}\x{7CA6}\x{7CA7}\x{7CA8}' .
          '\x{7CA9}\x{7CAA}\x{7CAD}\x{7CAE}\x{7CAF}\x{7CB0}\x{7CB1}\x{7CB2}\x{7CB3}' .
          '\x{7CB4}\x{7CB5}\x{7CB6}\x{7CB7}\x{7CB8}\x{7CB9}\x{7CBA}\x{7CBB}\x{7CBC}' .
          '\x{7CBD}\x{7CBE}\x{7CBF}\x{7CC0}\x{7CC1}\x{7CC2}\x{7CC3}\x{7CC4}\x{7CC5}' .
          '\x{7CC6}\x{7CC7}\x{7CC8}\x{7CC9}\x{7CCA}\x{7CCB}\x{7CCC}\x{7CCD}\x{7CCE}' .
          '\x{7CCF}\x{7CD0}\x{7CD1}\x{7CD2}\x{7CD4}\x{7CD5}\x{7CD6}\x{7CD7}\x{7CD8}' .
          '\x{7CD9}\x{7CDC}\x{7CDD}\x{7CDE}\x{7CDF}\x{7CE0}\x{7CE2}\x{7CE4}\x{7CE7}' .
          '\x{7CE8}\x{7CE9}\x{7CEA}\x{7CEB}\x{7CEC}\x{7CED}\x{7CEE}\x{7CEF}\x{7CF0}' .
          '\x{7CF1}\x{7CF2}\x{7CF3}\x{7CF4}\x{7CF5}\x{7CF6}\x{7CF7}\x{7CF8}\x{7CF9}' .
          '\x{7CFA}\x{7CFB}\x{7CFD}\x{7CFE}\x{7D00}\x{7D01}\x{7D02}\x{7D03}\x{7D04}' .
          '\x{7D05}\x{7D06}\x{7D07}\x{7D08}\x{7D09}\x{7D0A}\x{7D0B}\x{7D0C}\x{7D0D}' .
          '\x{7D0E}\x{7D0F}\x{7D10}\x{7D11}\x{7D12}\x{7D13}\x{7D14}\x{7D15}\x{7D16}' .
          '\x{7D17}\x{7D18}\x{7D19}\x{7D1A}\x{7D1B}\x{7D1C}\x{7D1D}\x{7D1E}\x{7D1F}' .
          '\x{7D20}\x{7D21}\x{7D22}\x{7D24}\x{7D25}\x{7D26}\x{7D27}\x{7D28}\x{7D29}' .
          '\x{7D2B}\x{7D2C}\x{7D2E}\x{7D2F}\x{7D30}\x{7D31}\x{7D32}\x{7D33}\x{7D34}' .
          '\x{7D35}\x{7D36}\x{7D37}\x{7D38}\x{7D39}\x{7D3A}\x{7D3B}\x{7D3C}\x{7D3D}' .
          '\x{7D3E}\x{7D3F}\x{7D40}\x{7D41}\x{7D42}\x{7D43}\x{7D44}\x{7D45}\x{7D46}' .
          '\x{7D47}\x{7D49}\x{7D4A}\x{7D4B}\x{7D4C}\x{7D4E}\x{7D4F}\x{7D50}\x{7D51}' .
          '\x{7D52}\x{7D53}\x{7D54}\x{7D55}\x{7D56}\x{7D57}\x{7D58}\x{7D59}\x{7D5B}' .
          '\x{7D5C}\x{7D5D}\x{7D5E}\x{7D5F}\x{7D60}\x{7D61}\x{7D62}\x{7D63}\x{7D65}' .
          '\x{7D66}\x{7D67}\x{7D68}\x{7D69}\x{7D6A}\x{7D6B}\x{7D6C}\x{7D6D}\x{7D6E}' .
          '\x{7D6F}\x{7D70}\x{7D71}\x{7D72}\x{7D73}\x{7D74}\x{7D75}\x{7D76}\x{7D77}' .
          '\x{7D79}\x{7D7A}\x{7D7B}\x{7D7C}\x{7D7D}\x{7D7E}\x{7D7F}\x{7D80}\x{7D81}' .
          '\x{7D83}\x{7D84}\x{7D85}\x{7D86}\x{7D87}\x{7D88}\x{7D89}\x{7D8A}\x{7D8B}' .
          '\x{7D8C}\x{7D8D}\x{7D8E}\x{7D8F}\x{7D90}\x{7D91}\x{7D92}\x{7D93}\x{7D94}' .
          '\x{7D96}\x{7D97}\x{7D99}\x{7D9B}\x{7D9C}\x{7D9D}\x{7D9E}\x{7D9F}\x{7DA0}' .
          '\x{7DA1}\x{7DA2}\x{7DA3}\x{7DA5}\x{7DA6}\x{7DA7}\x{7DA9}\x{7DAA}\x{7DAB}' .
          '\x{7DAC}\x{7DAD}\x{7DAE}\x{7DAF}\x{7DB0}\x{7DB1}\x{7DB2}\x{7DB3}\x{7DB4}' .
          '\x{7DB5}\x{7DB6}\x{7DB7}\x{7DB8}\x{7DB9}\x{7DBA}\x{7DBB}\x{7DBC}\x{7DBD}' .
          '\x{7DBE}\x{7DBF}\x{7DC0}\x{7DC1}\x{7DC2}\x{7DC3}\x{7DC4}\x{7DC5}\x{7DC6}' .
          '\x{7DC7}\x{7DC8}\x{7DC9}\x{7DCA}\x{7DCB}\x{7DCC}\x{7DCE}\x{7DCF}\x{7DD0}' .
          '\x{7DD1}\x{7DD2}\x{7DD4}\x{7DD5}\x{7DD6}\x{7DD7}\x{7DD8}\x{7DD9}\x{7DDA}' .
          '\x{7DDB}\x{7DDD}\x{7DDE}\x{7DDF}\x{7DE0}\x{7DE1}\x{7DE2}\x{7DE3}\x{7DE6}' .
          '\x{7DE7}\x{7DE8}\x{7DE9}\x{7DEA}\x{7DEC}\x{7DED}\x{7DEE}\x{7DEF}\x{7DF0}' .
          '\x{7DF1}\x{7DF2}\x{7DF3}\x{7DF4}\x{7DF5}\x{7DF6}\x{7DF7}\x{7DF8}\x{7DF9}' .
          '\x{7DFA}\x{7DFB}\x{7DFC}\x{7E00}\x{7E01}\x{7E02}\x{7E03}\x{7E04}\x{7E05}' .
          '\x{7E06}\x{7E07}\x{7E08}\x{7E09}\x{7E0A}\x{7E0B}\x{7E0C}\x{7E0D}\x{7E0E}' .
          '\x{7E0F}\x{7E10}\x{7E11}\x{7E12}\x{7E13}\x{7E14}\x{7E15}\x{7E16}\x{7E17}' .
          '\x{7E19}\x{7E1A}\x{7E1B}\x{7E1C}\x{7E1D}\x{7E1E}\x{7E1F}\x{7E20}\x{7E21}' .
          '\x{7E22}\x{7E23}\x{7E24}\x{7E25}\x{7E26}\x{7E27}\x{7E28}\x{7E29}\x{7E2A}' .
          '\x{7E2B}\x{7E2C}\x{7E2D}\x{7E2E}\x{7E2F}\x{7E30}\x{7E31}\x{7E32}\x{7E33}' .
          '\x{7E34}\x{7E35}\x{7E36}\x{7E37}\x{7E38}\x{7E39}\x{7E3A}\x{7E3B}\x{7E3C}' .
          '\x{7E3D}\x{7E3E}\x{7E3F}\x{7E40}\x{7E41}\x{7E42}\x{7E43}\x{7E44}\x{7E45}' .
          '\x{7E46}\x{7E47}\x{7E48}\x{7E49}\x{7E4C}\x{7E4D}\x{7E4E}\x{7E4F}\x{7E50}' .
          '\x{7E51}\x{7E52}\x{7E53}\x{7E54}\x{7E55}\x{7E56}\x{7E57}\x{7E58}\x{7E59}' .
          '\x{7E5A}\x{7E5C}\x{7E5D}\x{7E5E}\x{7E5F}\x{7E60}\x{7E61}\x{7E62}\x{7E63}' .
          '\x{7E65}\x{7E66}\x{7E67}\x{7E68}\x{7E69}\x{7E6A}\x{7E6B}\x{7E6C}\x{7E6D}' .
          '\x{7E6E}\x{7E6F}\x{7E70}\x{7E71}\x{7E72}\x{7E73}\x{7E74}\x{7E75}\x{7E76}' .
          '\x{7E77}\x{7E78}\x{7E79}\x{7E7A}\x{7E7B}\x{7E7C}\x{7E7D}\x{7E7E}\x{7E7F}' .
          '\x{7E80}\x{7E81}\x{7E82}\x{7E83}\x{7E84}\x{7E85}\x{7E86}\x{7E87}\x{7E88}' .
          '\x{7E89}\x{7E8A}\x{7E8B}\x{7E8C}\x{7E8D}\x{7E8E}\x{7E8F}\x{7E90}\x{7E91}' .
          '\x{7E92}\x{7E93}\x{7E94}\x{7E95}\x{7E96}\x{7E97}\x{7E98}\x{7E99}\x{7E9A}' .
          '\x{7E9B}\x{7E9C}\x{7E9E}\x{7E9F}\x{7EA0}\x{7EA1}\x{7EA2}\x{7EA3}\x{7EA4}' .
          '\x{7EA5}\x{7EA6}\x{7EA7}\x{7EA8}\x{7EA9}\x{7EAA}\x{7EAB}\x{7EAC}\x{7EAD}' .
          '\x{7EAE}\x{7EAF}\x{7EB0}\x{7EB1}\x{7EB2}\x{7EB3}\x{7EB4}\x{7EB5}\x{7EB6}' .
          '\x{7EB7}\x{7EB8}\x{7EB9}\x{7EBA}\x{7EBB}\x{7EBC}\x{7EBD}\x{7EBE}\x{7EBF}' .
          '\x{7EC0}\x{7EC1}\x{7EC2}\x{7EC3}\x{7EC4}\x{7EC5}\x{7EC6}\x{7EC7}\x{7EC8}' .
          '\x{7EC9}\x{7ECA}\x{7ECB}\x{7ECC}\x{7ECD}\x{7ECE}\x{7ECF}\x{7ED0}\x{7ED1}' .
          '\x{7ED2}\x{7ED3}\x{7ED4}\x{7ED5}\x{7ED6}\x{7ED7}\x{7ED8}\x{7ED9}\x{7EDA}' .
          '\x{7EDB}\x{7EDC}\x{7EDD}\x{7EDE}\x{7EDF}\x{7EE0}\x{7EE1}\x{7EE2}\x{7EE3}' .
          '\x{7EE4}\x{7EE5}\x{7EE6}\x{7EE7}\x{7EE8}\x{7EE9}\x{7EEA}\x{7EEB}\x{7EEC}' .
          '\x{7EED}\x{7EEE}\x{7EEF}\x{7EF0}\x{7EF1}\x{7EF2}\x{7EF3}\x{7EF4}\x{7EF5}' .
          '\x{7EF6}\x{7EF7}\x{7EF8}\x{7EF9}\x{7EFA}\x{7EFB}\x{7EFC}\x{7EFD}\x{7EFE}' .
          '\x{7EFF}\x{7F00}\x{7F01}\x{7F02}\x{7F03}\x{7F04}\x{7F05}\x{7F06}\x{7F07}' .
          '\x{7F08}\x{7F09}\x{7F0A}\x{7F0B}\x{7F0C}\x{7F0D}\x{7F0E}\x{7F0F}\x{7F10}' .
          '\x{7F11}\x{7F12}\x{7F13}\x{7F14}\x{7F15}\x{7F16}\x{7F17}\x{7F18}\x{7F19}' .
          '\x{7F1A}\x{7F1B}\x{7F1C}\x{7F1D}\x{7F1E}\x{7F1F}\x{7F20}\x{7F21}\x{7F22}' .
          '\x{7F23}\x{7F24}\x{7F25}\x{7F26}\x{7F27}\x{7F28}\x{7F29}\x{7F2A}\x{7F2B}' .
          '\x{7F2C}\x{7F2D}\x{7F2E}\x{7F2F}\x{7F30}\x{7F31}\x{7F32}\x{7F33}\x{7F34}' .
          '\x{7F35}\x{7F36}\x{7F37}\x{7F38}\x{7F39}\x{7F3A}\x{7F3D}\x{7F3E}\x{7F3F}' .
          '\x{7F40}\x{7F42}\x{7F43}\x{7F44}\x{7F45}\x{7F47}\x{7F48}\x{7F49}\x{7F4A}' .
          '\x{7F4B}\x{7F4C}\x{7F4D}\x{7F4E}\x{7F4F}\x{7F50}\x{7F51}\x{7F52}\x{7F53}' .
          '\x{7F54}\x{7F55}\x{7F56}\x{7F57}\x{7F58}\x{7F5A}\x{7F5B}\x{7F5C}\x{7F5D}' .
          '\x{7F5E}\x{7F5F}\x{7F60}\x{7F61}\x{7F62}\x{7F63}\x{7F64}\x{7F65}\x{7F66}' .
          '\x{7F67}\x{7F68}\x{7F69}\x{7F6A}\x{7F6B}\x{7F6C}\x{7F6D}\x{7F6E}\x{7F6F}' .
          '\x{7F70}\x{7F71}\x{7F72}\x{7F73}\x{7F74}\x{7F75}\x{7F76}\x{7F77}\x{7F78}' .
          '\x{7F79}\x{7F7A}\x{7F7B}\x{7F7C}\x{7F7D}\x{7F7E}\x{7F7F}\x{7F80}\x{7F81}' .
          '\x{7F82}\x{7F83}\x{7F85}\x{7F86}\x{7F87}\x{7F88}\x{7F89}\x{7F8A}\x{7F8B}' .
          '\x{7F8C}\x{7F8D}\x{7F8E}\x{7F8F}\x{7F91}\x{7F92}\x{7F93}\x{7F94}\x{7F95}' .
          '\x{7F96}\x{7F98}\x{7F9A}\x{7F9B}\x{7F9C}\x{7F9D}\x{7F9E}\x{7F9F}\x{7FA0}' .
          '\x{7FA1}\x{7FA2}\x{7FA3}\x{7FA4}\x{7FA5}\x{7FA6}\x{7FA7}\x{7FA8}\x{7FA9}' .
          '\x{7FAA}\x{7FAB}\x{7FAC}\x{7FAD}\x{7FAE}\x{7FAF}\x{7FB0}\x{7FB1}\x{7FB2}' .
          '\x{7FB3}\x{7FB5}\x{7FB6}\x{7FB7}\x{7FB8}\x{7FB9}\x{7FBA}\x{7FBB}\x{7FBC}' .
          '\x{7FBD}\x{7FBE}\x{7FBF}\x{7FC0}\x{7FC1}\x{7FC2}\x{7FC3}\x{7FC4}\x{7FC5}' .
          '\x{7FC6}\x{7FC7}\x{7FC8}\x{7FC9}\x{7FCA}\x{7FCB}\x{7FCC}\x{7FCD}\x{7FCE}' .
          '\x{7FCF}\x{7FD0}\x{7FD1}\x{7FD2}\x{7FD3}\x{7FD4}\x{7FD5}\x{7FD7}\x{7FD8}' .
          '\x{7FD9}\x{7FDA}\x{7FDB}\x{7FDC}\x{7FDE}\x{7FDF}\x{7FE0}\x{7FE1}\x{7FE2}' .
          '\x{7FE3}\x{7FE5}\x{7FE6}\x{7FE7}\x{7FE8}\x{7FE9}\x{7FEA}\x{7FEB}\x{7FEC}' .
          '\x{7FED}\x{7FEE}\x{7FEF}\x{7FF0}\x{7FF1}\x{7FF2}\x{7FF3}\x{7FF4}\x{7FF5}' .
          '\x{7FF6}\x{7FF7}\x{7FF8}\x{7FF9}\x{7FFA}\x{7FFB}\x{7FFC}\x{7FFD}\x{7FFE}' .
          '\x{7FFF}\x{8000}\x{8001}\x{8002}\x{8003}\x{8004}\x{8005}\x{8006}\x{8007}' .
          '\x{8008}\x{8009}\x{800B}\x{800C}\x{800D}\x{800E}\x{800F}\x{8010}\x{8011}' .
          '\x{8012}\x{8013}\x{8014}\x{8015}\x{8016}\x{8017}\x{8018}\x{8019}\x{801A}' .
          '\x{801B}\x{801C}\x{801D}\x{801E}\x{801F}\x{8020}\x{8021}\x{8022}\x{8023}' .
          '\x{8024}\x{8025}\x{8026}\x{8027}\x{8028}\x{8029}\x{802A}\x{802B}\x{802C}' .
          '\x{802D}\x{802E}\x{8030}\x{8031}\x{8032}\x{8033}\x{8034}\x{8035}\x{8036}' .
          '\x{8037}\x{8038}\x{8039}\x{803A}\x{803B}\x{803D}\x{803E}\x{803F}\x{8041}' .
          '\x{8042}\x{8043}\x{8044}\x{8045}\x{8046}\x{8047}\x{8048}\x{8049}\x{804A}' .
          '\x{804B}\x{804C}\x{804D}\x{804E}\x{804F}\x{8050}\x{8051}\x{8052}\x{8053}' .
          '\x{8054}\x{8055}\x{8056}\x{8057}\x{8058}\x{8059}\x{805A}\x{805B}\x{805C}' .
          '\x{805D}\x{805E}\x{805F}\x{8060}\x{8061}\x{8062}\x{8063}\x{8064}\x{8065}' .
          '\x{8067}\x{8068}\x{8069}\x{806A}\x{806B}\x{806C}\x{806D}\x{806E}\x{806F}' .
          '\x{8070}\x{8071}\x{8072}\x{8073}\x{8074}\x{8075}\x{8076}\x{8077}\x{8078}' .
          '\x{8079}\x{807A}\x{807B}\x{807C}\x{807D}\x{807E}\x{807F}\x{8080}\x{8081}' .
          '\x{8082}\x{8083}\x{8084}\x{8085}\x{8086}\x{8087}\x{8089}\x{808A}\x{808B}' .
          '\x{808C}\x{808D}\x{808F}\x{8090}\x{8091}\x{8092}\x{8093}\x{8095}\x{8096}' .
          '\x{8097}\x{8098}\x{8099}\x{809A}\x{809B}\x{809C}\x{809D}\x{809E}\x{809F}' .
          '\x{80A0}\x{80A1}\x{80A2}\x{80A3}\x{80A4}\x{80A5}\x{80A9}\x{80AA}\x{80AB}' .
          '\x{80AD}\x{80AE}\x{80AF}\x{80B0}\x{80B1}\x{80B2}\x{80B4}\x{80B5}\x{80B6}' .
          '\x{80B7}\x{80B8}\x{80BA}\x{80BB}\x{80BC}\x{80BD}\x{80BE}\x{80BF}\x{80C0}' .
          '\x{80C1}\x{80C2}\x{80C3}\x{80C4}\x{80C5}\x{80C6}\x{80C7}\x{80C8}\x{80C9}' .
          '\x{80CA}\x{80CB}\x{80CC}\x{80CD}\x{80CE}\x{80CF}\x{80D0}\x{80D1}\x{80D2}' .
          '\x{80D3}\x{80D4}\x{80D5}\x{80D6}\x{80D7}\x{80D8}\x{80D9}\x{80DA}\x{80DB}' .
          '\x{80DC}\x{80DD}\x{80DE}\x{80E0}\x{80E1}\x{80E2}\x{80E3}\x{80E4}\x{80E5}' .
          '\x{80E6}\x{80E7}\x{80E8}\x{80E9}\x{80EA}\x{80EB}\x{80EC}\x{80ED}\x{80EE}' .
          '\x{80EF}\x{80F0}\x{80F1}\x{80F2}\x{80F3}\x{80F4}\x{80F5}\x{80F6}\x{80F7}' .
          '\x{80F8}\x{80F9}\x{80FA}\x{80FB}\x{80FC}\x{80FD}\x{80FE}\x{80FF}\x{8100}' .
          '\x{8101}\x{8102}\x{8105}\x{8106}\x{8107}\x{8108}\x{8109}\x{810A}\x{810B}' .
          '\x{810C}\x{810D}\x{810E}\x{810F}\x{8110}\x{8111}\x{8112}\x{8113}\x{8114}' .
          '\x{8115}\x{8116}\x{8118}\x{8119}\x{811A}\x{811B}\x{811C}\x{811D}\x{811E}' .
          '\x{811F}\x{8120}\x{8121}\x{8122}\x{8123}\x{8124}\x{8125}\x{8126}\x{8127}' .
          '\x{8128}\x{8129}\x{812A}\x{812B}\x{812C}\x{812D}\x{812E}\x{812F}\x{8130}' .
          '\x{8131}\x{8132}\x{8136}\x{8137}\x{8138}\x{8139}\x{813A}\x{813B}\x{813C}' .
          '\x{813D}\x{813E}\x{813F}\x{8140}\x{8141}\x{8142}\x{8143}\x{8144}\x{8145}' .
          '\x{8146}\x{8147}\x{8148}\x{8149}\x{814A}\x{814B}\x{814C}\x{814D}\x{814E}' .
          '\x{814F}\x{8150}\x{8151}\x{8152}\x{8153}\x{8154}\x{8155}\x{8156}\x{8157}' .
          '\x{8158}\x{8159}\x{815A}\x{815B}\x{815C}\x{815D}\x{815E}\x{8160}\x{8161}' .
          '\x{8162}\x{8163}\x{8164}\x{8165}\x{8166}\x{8167}\x{8168}\x{8169}\x{816A}' .
          '\x{816B}\x{816C}\x{816D}\x{816E}\x{816F}\x{8170}\x{8171}\x{8172}\x{8173}' .
          '\x{8174}\x{8175}\x{8176}\x{8177}\x{8178}\x{8179}\x{817A}\x{817B}\x{817C}' .
          '\x{817D}\x{817E}\x{817F}\x{8180}\x{8181}\x{8182}\x{8183}\x{8185}\x{8186}' .
          '\x{8187}\x{8188}\x{8189}\x{818A}\x{818B}\x{818C}\x{818D}\x{818E}\x{818F}' .
          '\x{8191}\x{8192}\x{8193}\x{8194}\x{8195}\x{8197}\x{8198}\x{8199}\x{819A}' .
          '\x{819B}\x{819C}\x{819D}\x{819E}\x{819F}\x{81A0}\x{81A1}\x{81A2}\x{81A3}' .
          '\x{81A4}\x{81A5}\x{81A6}\x{81A7}\x{81A8}\x{81A9}\x{81AA}\x{81AB}\x{81AC}' .
          '\x{81AD}\x{81AE}\x{81AF}\x{81B0}\x{81B1}\x{81B2}\x{81B3}\x{81B4}\x{81B5}' .
          '\x{81B6}\x{81B7}\x{81B8}\x{81B9}\x{81BA}\x{81BB}\x{81BC}\x{81BD}\x{81BE}' .
          '\x{81BF}\x{81C0}\x{81C1}\x{81C2}\x{81C3}\x{81C4}\x{81C5}\x{81C6}\x{81C7}' .
          '\x{81C8}\x{81C9}\x{81CA}\x{81CC}\x{81CD}\x{81CE}\x{81CF}\x{81D0}\x{81D1}' .
          '\x{81D2}\x{81D4}\x{81D5}\x{81D6}\x{81D7}\x{81D8}\x{81D9}\x{81DA}\x{81DB}' .
          '\x{81DC}\x{81DD}\x{81DE}\x{81DF}\x{81E0}\x{81E1}\x{81E2}\x{81E3}\x{81E5}' .
          '\x{81E6}\x{81E7}\x{81E8}\x{81E9}\x{81EA}\x{81EB}\x{81EC}\x{81ED}\x{81EE}' .
          '\x{81F1}\x{81F2}\x{81F3}\x{81F4}\x{81F5}\x{81F6}\x{81F7}\x{81F8}\x{81F9}' .
          '\x{81FA}\x{81FB}\x{81FC}\x{81FD}\x{81FE}\x{81FF}\x{8200}\x{8201}\x{8202}' .
          '\x{8203}\x{8204}\x{8205}\x{8206}\x{8207}\x{8208}\x{8209}\x{820A}\x{820B}' .
          '\x{820C}\x{820D}\x{820E}\x{820F}\x{8210}\x{8211}\x{8212}\x{8214}\x{8215}' .
          '\x{8216}\x{8218}\x{8219}\x{821A}\x{821B}\x{821C}\x{821D}\x{821E}\x{821F}' .
          '\x{8220}\x{8221}\x{8222}\x{8223}\x{8225}\x{8226}\x{8227}\x{8228}\x{8229}' .
          '\x{822A}\x{822B}\x{822C}\x{822D}\x{822F}\x{8230}\x{8231}\x{8232}\x{8233}' .
          '\x{8234}\x{8235}\x{8236}\x{8237}\x{8238}\x{8239}\x{823A}\x{823B}\x{823C}' .
          '\x{823D}\x{823E}\x{823F}\x{8240}\x{8242}\x{8243}\x{8244}\x{8245}\x{8246}' .
          '\x{8247}\x{8248}\x{8249}\x{824A}\x{824B}\x{824C}\x{824D}\x{824E}\x{824F}' .
          '\x{8250}\x{8251}\x{8252}\x{8253}\x{8254}\x{8255}\x{8256}\x{8257}\x{8258}' .
          '\x{8259}\x{825A}\x{825B}\x{825C}\x{825D}\x{825E}\x{825F}\x{8260}\x{8261}' .
          '\x{8263}\x{8264}\x{8266}\x{8267}\x{8268}\x{8269}\x{826A}\x{826B}\x{826C}' .
          '\x{826D}\x{826E}\x{826F}\x{8270}\x{8271}\x{8272}\x{8273}\x{8274}\x{8275}' .
          '\x{8276}\x{8277}\x{8278}\x{8279}\x{827A}\x{827B}\x{827C}\x{827D}\x{827E}' .
          '\x{827F}\x{8280}\x{8281}\x{8282}\x{8283}\x{8284}\x{8285}\x{8286}\x{8287}' .
          '\x{8288}\x{8289}\x{828A}\x{828B}\x{828D}\x{828E}\x{828F}\x{8290}\x{8291}' .
          '\x{8292}\x{8293}\x{8294}\x{8295}\x{8296}\x{8297}\x{8298}\x{8299}\x{829A}' .
          '\x{829B}\x{829C}\x{829D}\x{829E}\x{829F}\x{82A0}\x{82A1}\x{82A2}\x{82A3}' .
          '\x{82A4}\x{82A5}\x{82A6}\x{82A7}\x{82A8}\x{82A9}\x{82AA}\x{82AB}\x{82AC}' .
          '\x{82AD}\x{82AE}\x{82AF}\x{82B0}\x{82B1}\x{82B3}\x{82B4}\x{82B5}\x{82B6}' .
          '\x{82B7}\x{82B8}\x{82B9}\x{82BA}\x{82BB}\x{82BC}\x{82BD}\x{82BE}\x{82BF}' .
          '\x{82C0}\x{82C1}\x{82C2}\x{82C3}\x{82C4}\x{82C5}\x{82C6}\x{82C7}\x{82C8}' .
          '\x{82C9}\x{82CA}\x{82CB}\x{82CC}\x{82CD}\x{82CE}\x{82CF}\x{82D0}\x{82D1}' .
          '\x{82D2}\x{82D3}\x{82D4}\x{82D5}\x{82D6}\x{82D7}\x{82D8}\x{82D9}\x{82DA}' .
          '\x{82DB}\x{82DC}\x{82DD}\x{82DE}\x{82DF}\x{82E0}\x{82E1}\x{82E3}\x{82E4}' .
          '\x{82E5}\x{82E6}\x{82E7}\x{82E8}\x{82E9}\x{82EA}\x{82EB}\x{82EC}\x{82ED}' .
          '\x{82EE}\x{82EF}\x{82F0}\x{82F1}\x{82F2}\x{82F3}\x{82F4}\x{82F5}\x{82F6}' .
          '\x{82F7}\x{82F8}\x{82F9}\x{82FA}\x{82FB}\x{82FD}\x{82FE}\x{82FF}\x{8300}' .
          '\x{8301}\x{8302}\x{8303}\x{8304}\x{8305}\x{8306}\x{8307}\x{8308}\x{8309}' .
          '\x{830B}\x{830C}\x{830D}\x{830E}\x{830F}\x{8311}\x{8312}\x{8313}\x{8314}' .
          '\x{8315}\x{8316}\x{8317}\x{8318}\x{8319}\x{831A}\x{831B}\x{831C}\x{831D}' .
          '\x{831E}\x{831F}\x{8320}\x{8321}\x{8322}\x{8323}\x{8324}\x{8325}\x{8326}' .
          '\x{8327}\x{8328}\x{8329}\x{832A}\x{832B}\x{832C}\x{832D}\x{832E}\x{832F}' .
          '\x{8331}\x{8332}\x{8333}\x{8334}\x{8335}\x{8336}\x{8337}\x{8338}\x{8339}' .
          '\x{833A}\x{833B}\x{833C}\x{833D}\x{833E}\x{833F}\x{8340}\x{8341}\x{8342}' .
          '\x{8343}\x{8344}\x{8345}\x{8346}\x{8347}\x{8348}\x{8349}\x{834A}\x{834B}' .
          '\x{834C}\x{834D}\x{834E}\x{834F}\x{8350}\x{8351}\x{8352}\x{8353}\x{8354}' .
          '\x{8356}\x{8357}\x{8358}\x{8359}\x{835A}\x{835B}\x{835C}\x{835D}\x{835E}' .
          '\x{835F}\x{8360}\x{8361}\x{8362}\x{8363}\x{8364}\x{8365}\x{8366}\x{8367}' .
          '\x{8368}\x{8369}\x{836A}\x{836B}\x{836C}\x{836D}\x{836E}\x{836F}\x{8370}' .
          '\x{8371}\x{8372}\x{8373}\x{8374}\x{8375}\x{8376}\x{8377}\x{8378}\x{8379}' .
          '\x{837A}\x{837B}\x{837C}\x{837D}\x{837E}\x{837F}\x{8380}\x{8381}\x{8382}' .
          '\x{8383}\x{8384}\x{8385}\x{8386}\x{8387}\x{8388}\x{8389}\x{838A}\x{838B}' .
          '\x{838C}\x{838D}\x{838E}\x{838F}\x{8390}\x{8391}\x{8392}\x{8393}\x{8394}' .
          '\x{8395}\x{8396}\x{8397}\x{8398}\x{8399}\x{839A}\x{839B}\x{839C}\x{839D}' .
          '\x{839E}\x{83A0}\x{83A1}\x{83A2}\x{83A3}\x{83A4}\x{83A5}\x{83A6}\x{83A7}' .
          '\x{83A8}\x{83A9}\x{83AA}\x{83AB}\x{83AC}\x{83AD}\x{83AE}\x{83AF}\x{83B0}' .
          '\x{83B1}\x{83B2}\x{83B3}\x{83B4}\x{83B6}\x{83B7}\x{83B8}\x{83B9}\x{83BA}' .
          '\x{83BB}\x{83BC}\x{83BD}\x{83BF}\x{83C0}\x{83C1}\x{83C2}\x{83C3}\x{83C4}' .
          '\x{83C5}\x{83C6}\x{83C7}\x{83C8}\x{83C9}\x{83CA}\x{83CB}\x{83CC}\x{83CD}' .
          '\x{83CE}\x{83CF}\x{83D0}\x{83D1}\x{83D2}\x{83D3}\x{83D4}\x{83D5}\x{83D6}' .
          '\x{83D7}\x{83D8}\x{83D9}\x{83DA}\x{83DB}\x{83DC}\x{83DD}\x{83DE}\x{83DF}' .
          '\x{83E0}\x{83E1}\x{83E2}\x{83E3}\x{83E4}\x{83E5}\x{83E7}\x{83E8}\x{83E9}' .
          '\x{83EA}\x{83EB}\x{83EC}\x{83EE}\x{83EF}\x{83F0}\x{83F1}\x{83F2}\x{83F3}' .
          '\x{83F4}\x{83F5}\x{83F6}\x{83F7}\x{83F8}\x{83F9}\x{83FA}\x{83FB}\x{83FC}' .
          '\x{83FD}\x{83FE}\x{83FF}\x{8400}\x{8401}\x{8402}\x{8403}\x{8404}\x{8405}' .
          '\x{8406}\x{8407}\x{8408}\x{8409}\x{840A}\x{840B}\x{840C}\x{840D}\x{840E}' .
          '\x{840F}\x{8410}\x{8411}\x{8412}\x{8413}\x{8415}\x{8418}\x{8419}\x{841A}' .
          '\x{841B}\x{841C}\x{841D}\x{841E}\x{8421}\x{8422}\x{8423}\x{8424}\x{8425}' .
          '\x{8426}\x{8427}\x{8428}\x{8429}\x{842A}\x{842B}\x{842C}\x{842D}\x{842E}' .
          '\x{842F}\x{8430}\x{8431}\x{8432}\x{8433}\x{8434}\x{8435}\x{8436}\x{8437}' .
          '\x{8438}\x{8439}\x{843A}\x{843B}\x{843C}\x{843D}\x{843E}\x{843F}\x{8440}' .
          '\x{8441}\x{8442}\x{8443}\x{8444}\x{8445}\x{8446}\x{8447}\x{8448}\x{8449}' .
          '\x{844A}\x{844B}\x{844C}\x{844D}\x{844E}\x{844F}\x{8450}\x{8451}\x{8452}' .
          '\x{8453}\x{8454}\x{8455}\x{8456}\x{8457}\x{8459}\x{845A}\x{845B}\x{845C}' .
          '\x{845D}\x{845E}\x{845F}\x{8460}\x{8461}\x{8462}\x{8463}\x{8464}\x{8465}' .
          '\x{8466}\x{8467}\x{8468}\x{8469}\x{846A}\x{846B}\x{846C}\x{846D}\x{846E}' .
          '\x{846F}\x{8470}\x{8471}\x{8472}\x{8473}\x{8474}\x{8475}\x{8476}\x{8477}' .
          '\x{8478}\x{8479}\x{847A}\x{847B}\x{847C}\x{847D}\x{847E}\x{847F}\x{8480}' .
          '\x{8481}\x{8482}\x{8484}\x{8485}\x{8486}\x{8487}\x{8488}\x{8489}\x{848A}' .
          '\x{848B}\x{848C}\x{848D}\x{848E}\x{848F}\x{8490}\x{8491}\x{8492}\x{8493}' .
          '\x{8494}\x{8496}\x{8497}\x{8498}\x{8499}\x{849A}\x{849B}\x{849C}\x{849D}' .
          '\x{849E}\x{849F}\x{84A0}\x{84A1}\x{84A2}\x{84A3}\x{84A4}\x{84A5}\x{84A6}' .
          '\x{84A7}\x{84A8}\x{84A9}\x{84AA}\x{84AB}\x{84AC}\x{84AE}\x{84AF}\x{84B0}' .
          '\x{84B1}\x{84B2}\x{84B3}\x{84B4}\x{84B5}\x{84B6}\x{84B8}\x{84B9}\x{84BA}' .
          '\x{84BB}\x{84BC}\x{84BD}\x{84BE}\x{84BF}\x{84C0}\x{84C1}\x{84C2}\x{84C4}' .
          '\x{84C5}\x{84C6}\x{84C7}\x{84C8}\x{84C9}\x{84CA}\x{84CB}\x{84CC}\x{84CD}' .
          '\x{84CE}\x{84CF}\x{84D0}\x{84D1}\x{84D2}\x{84D3}\x{84D4}\x{84D5}\x{84D6}' .
          '\x{84D7}\x{84D8}\x{84D9}\x{84DB}\x{84DC}\x{84DD}\x{84DE}\x{84DF}\x{84E0}' .
          '\x{84E1}\x{84E2}\x{84E3}\x{84E4}\x{84E5}\x{84E6}\x{84E7}\x{84E8}\x{84E9}' .
          '\x{84EA}\x{84EB}\x{84EC}\x{84EE}\x{84EF}\x{84F0}\x{84F1}\x{84F2}\x{84F3}' .
          '\x{84F4}\x{84F5}\x{84F6}\x{84F7}\x{84F8}\x{84F9}\x{84FA}\x{84FB}\x{84FC}' .
          '\x{84FD}\x{84FE}\x{84FF}\x{8500}\x{8501}\x{8502}\x{8503}\x{8504}\x{8506}' .
          '\x{8507}\x{8508}\x{8509}\x{850A}\x{850B}\x{850C}\x{850D}\x{850E}\x{850F}' .
          '\x{8511}\x{8512}\x{8513}\x{8514}\x{8515}\x{8516}\x{8517}\x{8518}\x{8519}' .
          '\x{851A}\x{851B}\x{851C}\x{851D}\x{851E}\x{851F}\x{8520}\x{8521}\x{8522}' .
          '\x{8523}\x{8524}\x{8525}\x{8526}\x{8527}\x{8528}\x{8529}\x{852A}\x{852B}' .
          '\x{852C}\x{852D}\x{852E}\x{852F}\x{8530}\x{8531}\x{8534}\x{8535}\x{8536}' .
          '\x{8537}\x{8538}\x{8539}\x{853A}\x{853B}\x{853C}\x{853D}\x{853E}\x{853F}' .
          '\x{8540}\x{8541}\x{8542}\x{8543}\x{8544}\x{8545}\x{8546}\x{8547}\x{8548}' .
          '\x{8549}\x{854A}\x{854B}\x{854D}\x{854E}\x{854F}\x{8551}\x{8552}\x{8553}' .
          '\x{8554}\x{8555}\x{8556}\x{8557}\x{8558}\x{8559}\x{855A}\x{855B}\x{855C}' .
          '\x{855D}\x{855E}\x{855F}\x{8560}\x{8561}\x{8562}\x{8563}\x{8564}\x{8565}' .
          '\x{8566}\x{8567}\x{8568}\x{8569}\x{856A}\x{856B}\x{856C}\x{856D}\x{856E}' .
          '\x{856F}\x{8570}\x{8571}\x{8572}\x{8573}\x{8574}\x{8575}\x{8576}\x{8577}' .
          '\x{8578}\x{8579}\x{857A}\x{857B}\x{857C}\x{857D}\x{857E}\x{8580}\x{8581}' .
          '\x{8582}\x{8583}\x{8584}\x{8585}\x{8586}\x{8587}\x{8588}\x{8589}\x{858A}' .
          '\x{858B}\x{858C}\x{858D}\x{858E}\x{858F}\x{8590}\x{8591}\x{8592}\x{8594}' .
          '\x{8595}\x{8596}\x{8598}\x{8599}\x{859A}\x{859B}\x{859C}\x{859D}\x{859E}' .
          '\x{859F}\x{85A0}\x{85A1}\x{85A2}\x{85A3}\x{85A4}\x{85A5}\x{85A6}\x{85A7}' .
          '\x{85A8}\x{85A9}\x{85AA}\x{85AB}\x{85AC}\x{85AD}\x{85AE}\x{85AF}\x{85B0}' .
          '\x{85B1}\x{85B3}\x{85B4}\x{85B5}\x{85B6}\x{85B7}\x{85B8}\x{85B9}\x{85BA}' .
          '\x{85BC}\x{85BD}\x{85BE}\x{85BF}\x{85C0}\x{85C1}\x{85C2}\x{85C3}\x{85C4}' .
          '\x{85C5}\x{85C6}\x{85C7}\x{85C8}\x{85C9}\x{85CA}\x{85CB}\x{85CD}\x{85CE}' .
          '\x{85CF}\x{85D0}\x{85D1}\x{85D2}\x{85D3}\x{85D4}\x{85D5}\x{85D6}\x{85D7}' .
          '\x{85D8}\x{85D9}\x{85DA}\x{85DB}\x{85DC}\x{85DD}\x{85DE}\x{85DF}\x{85E0}' .
          '\x{85E1}\x{85E2}\x{85E3}\x{85E4}\x{85E5}\x{85E6}\x{85E7}\x{85E8}\x{85E9}' .
          '\x{85EA}\x{85EB}\x{85EC}\x{85ED}\x{85EF}\x{85F0}\x{85F1}\x{85F2}\x{85F4}' .
          '\x{85F5}\x{85F6}\x{85F7}\x{85F8}\x{85F9}\x{85FA}\x{85FB}\x{85FD}\x{85FE}' .
          '\x{85FF}\x{8600}\x{8601}\x{8602}\x{8604}\x{8605}\x{8606}\x{8607}\x{8608}' .
          '\x{8609}\x{860A}\x{860B}\x{860C}\x{860F}\x{8611}\x{8612}\x{8613}\x{8614}' .
          '\x{8616}\x{8617}\x{8618}\x{8619}\x{861A}\x{861B}\x{861C}\x{861E}\x{861F}' .
          '\x{8620}\x{8621}\x{8622}\x{8623}\x{8624}\x{8625}\x{8626}\x{8627}\x{8628}' .
          '\x{8629}\x{862A}\x{862B}\x{862C}\x{862D}\x{862E}\x{862F}\x{8630}\x{8631}' .
          '\x{8632}\x{8633}\x{8634}\x{8635}\x{8636}\x{8638}\x{8639}\x{863A}\x{863B}' .
          '\x{863C}\x{863D}\x{863E}\x{863F}\x{8640}\x{8641}\x{8642}\x{8643}\x{8644}' .
          '\x{8645}\x{8646}\x{8647}\x{8648}\x{8649}\x{864A}\x{864B}\x{864C}\x{864D}' .
          '\x{864E}\x{864F}\x{8650}\x{8651}\x{8652}\x{8653}\x{8654}\x{8655}\x{8656}' .
          '\x{8658}\x{8659}\x{865A}\x{865B}\x{865C}\x{865D}\x{865E}\x{865F}\x{8660}' .
          '\x{8661}\x{8662}\x{8663}\x{8664}\x{8665}\x{8666}\x{8667}\x{8668}\x{8669}' .
          '\x{866A}\x{866B}\x{866C}\x{866D}\x{866E}\x{866F}\x{8670}\x{8671}\x{8672}' .
          '\x{8673}\x{8674}\x{8676}\x{8677}\x{8678}\x{8679}\x{867A}\x{867B}\x{867C}' .
          '\x{867D}\x{867E}\x{867F}\x{8680}\x{8681}\x{8682}\x{8683}\x{8684}\x{8685}' .
          '\x{8686}\x{8687}\x{8688}\x{868A}\x{868B}\x{868C}\x{868D}\x{868E}\x{868F}' .
          '\x{8690}\x{8691}\x{8693}\x{8694}\x{8695}\x{8696}\x{8697}\x{8698}\x{8699}' .
          '\x{869A}\x{869B}\x{869C}\x{869D}\x{869E}\x{869F}\x{86A1}\x{86A2}\x{86A3}' .
          '\x{86A4}\x{86A5}\x{86A7}\x{86A8}\x{86A9}\x{86AA}\x{86AB}\x{86AC}\x{86AD}' .
          '\x{86AE}\x{86AF}\x{86B0}\x{86B1}\x{86B2}\x{86B3}\x{86B4}\x{86B5}\x{86B6}' .
          '\x{86B7}\x{86B8}\x{86B9}\x{86BA}\x{86BB}\x{86BC}\x{86BD}\x{86BE}\x{86BF}' .
          '\x{86C0}\x{86C1}\x{86C2}\x{86C3}\x{86C4}\x{86C5}\x{86C6}\x{86C7}\x{86C8}' .
          '\x{86C9}\x{86CA}\x{86CB}\x{86CC}\x{86CE}\x{86CF}\x{86D0}\x{86D1}\x{86D2}' .
          '\x{86D3}\x{86D4}\x{86D6}\x{86D7}\x{86D8}\x{86D9}\x{86DA}\x{86DB}\x{86DC}' .
          '\x{86DD}\x{86DE}\x{86DF}\x{86E1}\x{86E2}\x{86E3}\x{86E4}\x{86E5}\x{86E6}' .
          '\x{86E8}\x{86E9}\x{86EA}\x{86EB}\x{86EC}\x{86ED}\x{86EE}\x{86EF}\x{86F0}' .
          '\x{86F1}\x{86F2}\x{86F3}\x{86F4}\x{86F5}\x{86F6}\x{86F7}\x{86F8}\x{86F9}' .
          '\x{86FA}\x{86FB}\x{86FC}\x{86FE}\x{86FF}\x{8700}\x{8701}\x{8702}\x{8703}' .
          '\x{8704}\x{8705}\x{8706}\x{8707}\x{8708}\x{8709}\x{870A}\x{870B}\x{870C}' .
          '\x{870D}\x{870E}\x{870F}\x{8710}\x{8711}\x{8712}\x{8713}\x{8714}\x{8715}' .
          '\x{8716}\x{8717}\x{8718}\x{8719}\x{871A}\x{871B}\x{871C}\x{871E}\x{871F}' .
          '\x{8720}\x{8721}\x{8722}\x{8723}\x{8724}\x{8725}\x{8726}\x{8727}\x{8728}' .
          '\x{8729}\x{872A}\x{872B}\x{872C}\x{872D}\x{872E}\x{8730}\x{8731}\x{8732}' .
          '\x{8733}\x{8734}\x{8735}\x{8736}\x{8737}\x{8738}\x{8739}\x{873A}\x{873B}' .
          '\x{873C}\x{873E}\x{873F}\x{8740}\x{8741}\x{8742}\x{8743}\x{8744}\x{8746}' .
          '\x{8747}\x{8748}\x{8749}\x{874A}\x{874C}\x{874D}\x{874E}\x{874F}\x{8750}' .
          '\x{8751}\x{8752}\x{8753}\x{8754}\x{8755}\x{8756}\x{8757}\x{8758}\x{8759}' .
          '\x{875A}\x{875B}\x{875C}\x{875D}\x{875E}\x{875F}\x{8760}\x{8761}\x{8762}' .
          '\x{8763}\x{8764}\x{8765}\x{8766}\x{8767}\x{8768}\x{8769}\x{876A}\x{876B}' .
          '\x{876C}\x{876D}\x{876E}\x{876F}\x{8770}\x{8772}\x{8773}\x{8774}\x{8775}' .
          '\x{8776}\x{8777}\x{8778}\x{8779}\x{877A}\x{877B}\x{877C}\x{877D}\x{877E}' .
          '\x{8780}\x{8781}\x{8782}\x{8783}\x{8784}\x{8785}\x{8786}\x{8787}\x{8788}' .
          '\x{8789}\x{878A}\x{878B}\x{878C}\x{878D}\x{878F}\x{8790}\x{8791}\x{8792}' .
          '\x{8793}\x{8794}\x{8795}\x{8796}\x{8797}\x{8798}\x{879A}\x{879B}\x{879C}' .
          '\x{879D}\x{879E}\x{879F}\x{87A0}\x{87A1}\x{87A2}\x{87A3}\x{87A4}\x{87A5}' .
          '\x{87A6}\x{87A7}\x{87A8}\x{87A9}\x{87AA}\x{87AB}\x{87AC}\x{87AD}\x{87AE}' .
          '\x{87AF}\x{87B0}\x{87B1}\x{87B2}\x{87B3}\x{87B4}\x{87B5}\x{87B6}\x{87B7}' .
          '\x{87B8}\x{87B9}\x{87BA}\x{87BB}\x{87BC}\x{87BD}\x{87BE}\x{87BF}\x{87C0}' .
          '\x{87C1}\x{87C2}\x{87C3}\x{87C4}\x{87C5}\x{87C6}\x{87C7}\x{87C8}\x{87C9}' .
          '\x{87CA}\x{87CB}\x{87CC}\x{87CD}\x{87CE}\x{87CF}\x{87D0}\x{87D1}\x{87D2}' .
          '\x{87D3}\x{87D4}\x{87D5}\x{87D6}\x{87D7}\x{87D8}\x{87D9}\x{87DB}\x{87DC}' .
          '\x{87DD}\x{87DE}\x{87DF}\x{87E0}\x{87E1}\x{87E2}\x{87E3}\x{87E4}\x{87E5}' .
          '\x{87E6}\x{87E7}\x{87E8}\x{87E9}\x{87EA}\x{87EB}\x{87EC}\x{87ED}\x{87EE}' .
          '\x{87EF}\x{87F1}\x{87F2}\x{87F3}\x{87F4}\x{87F5}\x{87F6}\x{87F7}\x{87F8}' .
          '\x{87F9}\x{87FA}\x{87FB}\x{87FC}\x{87FD}\x{87FE}\x{87FF}\x{8800}\x{8801}' .
          '\x{8802}\x{8803}\x{8804}\x{8805}\x{8806}\x{8808}\x{8809}\x{880A}\x{880B}' .
          '\x{880C}\x{880D}\x{880E}\x{880F}\x{8810}\x{8811}\x{8813}\x{8814}\x{8815}' .
          '\x{8816}\x{8817}\x{8818}\x{8819}\x{881A}\x{881B}\x{881C}\x{881D}\x{881E}' .
          '\x{881F}\x{8820}\x{8821}\x{8822}\x{8823}\x{8824}\x{8825}\x{8826}\x{8827}' .
          '\x{8828}\x{8829}\x{882A}\x{882B}\x{882C}\x{882E}\x{882F}\x{8830}\x{8831}' .
          '\x{8832}\x{8833}\x{8834}\x{8835}\x{8836}\x{8837}\x{8838}\x{8839}\x{883B}' .
          '\x{883C}\x{883D}\x{883E}\x{883F}\x{8840}\x{8841}\x{8842}\x{8843}\x{8844}' .
          '\x{8845}\x{8846}\x{8848}\x{8849}\x{884A}\x{884B}\x{884C}\x{884D}\x{884E}' .
          '\x{884F}\x{8850}\x{8851}\x{8852}\x{8853}\x{8854}\x{8855}\x{8856}\x{8857}' .
          '\x{8859}\x{885A}\x{885B}\x{885D}\x{885E}\x{8860}\x{8861}\x{8862}\x{8863}' .
          '\x{8864}\x{8865}\x{8866}\x{8867}\x{8868}\x{8869}\x{886A}\x{886B}\x{886C}' .
          '\x{886D}\x{886E}\x{886F}\x{8870}\x{8871}\x{8872}\x{8873}\x{8874}\x{8875}' .
          '\x{8876}\x{8877}\x{8878}\x{8879}\x{887B}\x{887C}\x{887D}\x{887E}\x{887F}' .
          '\x{8880}\x{8881}\x{8882}\x{8883}\x{8884}\x{8885}\x{8886}\x{8887}\x{8888}' .
          '\x{8889}\x{888A}\x{888B}\x{888C}\x{888D}\x{888E}\x{888F}\x{8890}\x{8891}' .
          '\x{8892}\x{8893}\x{8894}\x{8895}\x{8896}\x{8897}\x{8898}\x{8899}\x{889A}' .
          '\x{889B}\x{889C}\x{889D}\x{889E}\x{889F}\x{88A0}\x{88A1}\x{88A2}\x{88A3}' .
          '\x{88A4}\x{88A5}\x{88A6}\x{88A7}\x{88A8}\x{88A9}\x{88AA}\x{88AB}\x{88AC}' .
          '\x{88AD}\x{88AE}\x{88AF}\x{88B0}\x{88B1}\x{88B2}\x{88B3}\x{88B4}\x{88B6}' .
          '\x{88B7}\x{88B8}\x{88B9}\x{88BA}\x{88BB}\x{88BC}\x{88BD}\x{88BE}\x{88BF}' .
          '\x{88C0}\x{88C1}\x{88C2}\x{88C3}\x{88C4}\x{88C5}\x{88C6}\x{88C7}\x{88C8}' .
          '\x{88C9}\x{88CA}\x{88CB}\x{88CC}\x{88CD}\x{88CE}\x{88CF}\x{88D0}\x{88D1}' .
          '\x{88D2}\x{88D3}\x{88D4}\x{88D5}\x{88D6}\x{88D7}\x{88D8}\x{88D9}\x{88DA}' .
          '\x{88DB}\x{88DC}\x{88DD}\x{88DE}\x{88DF}\x{88E0}\x{88E1}\x{88E2}\x{88E3}' .
          '\x{88E4}\x{88E5}\x{88E7}\x{88E8}\x{88EA}\x{88EB}\x{88EC}\x{88EE}\x{88EF}' .
          '\x{88F0}\x{88F1}\x{88F2}\x{88F3}\x{88F4}\x{88F5}\x{88F6}\x{88F7}\x{88F8}' .
          '\x{88F9}\x{88FA}\x{88FB}\x{88FC}\x{88FD}\x{88FE}\x{88FF}\x{8900}\x{8901}' .
          '\x{8902}\x{8904}\x{8905}\x{8906}\x{8907}\x{8908}\x{8909}\x{890A}\x{890B}' .
          '\x{890C}\x{890D}\x{890E}\x{8910}\x{8911}\x{8912}\x{8913}\x{8914}\x{8915}' .
          '\x{8916}\x{8917}\x{8918}\x{8919}\x{891A}\x{891B}\x{891C}\x{891D}\x{891E}' .
          '\x{891F}\x{8920}\x{8921}\x{8922}\x{8923}\x{8925}\x{8926}\x{8927}\x{8928}' .
          '\x{8929}\x{892A}\x{892B}\x{892C}\x{892D}\x{892E}\x{892F}\x{8930}\x{8931}' .
          '\x{8932}\x{8933}\x{8934}\x{8935}\x{8936}\x{8937}\x{8938}\x{8939}\x{893A}' .
          '\x{893B}\x{893C}\x{893D}\x{893E}\x{893F}\x{8940}\x{8941}\x{8942}\x{8943}' .
          '\x{8944}\x{8945}\x{8946}\x{8947}\x{8948}\x{8949}\x{894A}\x{894B}\x{894C}' .
          '\x{894E}\x{894F}\x{8950}\x{8951}\x{8952}\x{8953}\x{8954}\x{8955}\x{8956}' .
          '\x{8957}\x{8958}\x{8959}\x{895A}\x{895B}\x{895C}\x{895D}\x{895E}\x{895F}' .
          '\x{8960}\x{8961}\x{8962}\x{8963}\x{8964}\x{8966}\x{8967}\x{8968}\x{8969}' .
          '\x{896A}\x{896B}\x{896C}\x{896D}\x{896E}\x{896F}\x{8970}\x{8971}\x{8972}' .
          '\x{8973}\x{8974}\x{8976}\x{8977}\x{8978}\x{8979}\x{897A}\x{897B}\x{897C}' .
          '\x{897E}\x{897F}\x{8980}\x{8981}\x{8982}\x{8983}\x{8984}\x{8985}\x{8986}' .
          '\x{8987}\x{8988}\x{8989}\x{898A}\x{898B}\x{898C}\x{898E}\x{898F}\x{8991}' .
          '\x{8992}\x{8993}\x{8995}\x{8996}\x{8997}\x{8998}\x{899A}\x{899B}\x{899C}' .
          '\x{899D}\x{899E}\x{899F}\x{89A0}\x{89A1}\x{89A2}\x{89A3}\x{89A4}\x{89A5}' .
          '\x{89A6}\x{89A7}\x{89A8}\x{89AA}\x{89AB}\x{89AC}\x{89AD}\x{89AE}\x{89AF}' .
          '\x{89B1}\x{89B2}\x{89B3}\x{89B5}\x{89B6}\x{89B7}\x{89B8}\x{89B9}\x{89BA}' .
          '\x{89BD}\x{89BE}\x{89BF}\x{89C0}\x{89C1}\x{89C2}\x{89C3}\x{89C4}\x{89C5}' .
          '\x{89C6}\x{89C7}\x{89C8}\x{89C9}\x{89CA}\x{89CB}\x{89CC}\x{89CD}\x{89CE}' .
          '\x{89CF}\x{89D0}\x{89D1}\x{89D2}\x{89D3}\x{89D4}\x{89D5}\x{89D6}\x{89D7}' .
          '\x{89D8}\x{89D9}\x{89DA}\x{89DB}\x{89DC}\x{89DD}\x{89DE}\x{89DF}\x{89E0}' .
          '\x{89E1}\x{89E2}\x{89E3}\x{89E4}\x{89E5}\x{89E6}\x{89E7}\x{89E8}\x{89E9}' .
          '\x{89EA}\x{89EB}\x{89EC}\x{89ED}\x{89EF}\x{89F0}\x{89F1}\x{89F2}\x{89F3}' .
          '\x{89F4}\x{89F6}\x{89F7}\x{89F8}\x{89FA}\x{89FB}\x{89FC}\x{89FE}\x{89FF}' .
          '\x{8A00}\x{8A01}\x{8A02}\x{8A03}\x{8A04}\x{8A07}\x{8A08}\x{8A09}\x{8A0A}' .
          '\x{8A0B}\x{8A0C}\x{8A0D}\x{8A0E}\x{8A0F}\x{8A10}\x{8A11}\x{8A12}\x{8A13}' .
          '\x{8A15}\x{8A16}\x{8A17}\x{8A18}\x{8A1A}\x{8A1B}\x{8A1C}\x{8A1D}\x{8A1E}' .
          '\x{8A1F}\x{8A22}\x{8A23}\x{8A24}\x{8A25}\x{8A26}\x{8A27}\x{8A28}\x{8A29}' .
          '\x{8A2A}\x{8A2C}\x{8A2D}\x{8A2E}\x{8A2F}\x{8A30}\x{8A31}\x{8A32}\x{8A34}' .
          '\x{8A35}\x{8A36}\x{8A37}\x{8A38}\x{8A39}\x{8A3A}\x{8A3B}\x{8A3C}\x{8A3E}' .
          '\x{8A3F}\x{8A40}\x{8A41}\x{8A42}\x{8A43}\x{8A44}\x{8A45}\x{8A46}\x{8A47}' .
          '\x{8A48}\x{8A49}\x{8A4A}\x{8A4C}\x{8A4D}\x{8A4E}\x{8A4F}\x{8A50}\x{8A51}' .
          '\x{8A52}\x{8A53}\x{8A54}\x{8A55}\x{8A56}\x{8A57}\x{8A58}\x{8A59}\x{8A5A}' .
          '\x{8A5B}\x{8A5C}\x{8A5D}\x{8A5E}\x{8A5F}\x{8A60}\x{8A61}\x{8A62}\x{8A63}' .
          '\x{8A65}\x{8A66}\x{8A67}\x{8A68}\x{8A69}\x{8A6A}\x{8A6B}\x{8A6C}\x{8A6D}' .
          '\x{8A6E}\x{8A6F}\x{8A70}\x{8A71}\x{8A72}\x{8A73}\x{8A74}\x{8A75}\x{8A76}' .
          '\x{8A77}\x{8A79}\x{8A7A}\x{8A7B}\x{8A7C}\x{8A7E}\x{8A7F}\x{8A80}\x{8A81}' .
          '\x{8A82}\x{8A83}\x{8A84}\x{8A85}\x{8A86}\x{8A87}\x{8A89}\x{8A8A}\x{8A8B}' .
          '\x{8A8C}\x{8A8D}\x{8A8E}\x{8A8F}\x{8A90}\x{8A91}\x{8A92}\x{8A93}\x{8A94}' .
          '\x{8A95}\x{8A96}\x{8A97}\x{8A98}\x{8A99}\x{8A9A}\x{8A9B}\x{8A9C}\x{8A9D}' .
          '\x{8A9E}\x{8AA0}\x{8AA1}\x{8AA2}\x{8AA3}\x{8AA4}\x{8AA5}\x{8AA6}\x{8AA7}' .
          '\x{8AA8}\x{8AA9}\x{8AAA}\x{8AAB}\x{8AAC}\x{8AAE}\x{8AB0}\x{8AB1}\x{8AB2}' .
          '\x{8AB3}\x{8AB4}\x{8AB5}\x{8AB6}\x{8AB8}\x{8AB9}\x{8ABA}\x{8ABB}\x{8ABC}' .
          '\x{8ABD}\x{8ABE}\x{8ABF}\x{8AC0}\x{8AC1}\x{8AC2}\x{8AC3}\x{8AC4}\x{8AC5}' .
          '\x{8AC6}\x{8AC7}\x{8AC8}\x{8AC9}\x{8ACA}\x{8ACB}\x{8ACC}\x{8ACD}\x{8ACE}' .
          '\x{8ACF}\x{8AD1}\x{8AD2}\x{8AD3}\x{8AD4}\x{8AD5}\x{8AD6}\x{8AD7}\x{8AD8}' .
          '\x{8AD9}\x{8ADA}\x{8ADB}\x{8ADC}\x{8ADD}\x{8ADE}\x{8ADF}\x{8AE0}\x{8AE1}' .
          '\x{8AE2}\x{8AE3}\x{8AE4}\x{8AE5}\x{8AE6}\x{8AE7}\x{8AE8}\x{8AE9}\x{8AEA}' .
          '\x{8AEB}\x{8AED}\x{8AEE}\x{8AEF}\x{8AF0}\x{8AF1}\x{8AF2}\x{8AF3}\x{8AF4}' .
          '\x{8AF5}\x{8AF6}\x{8AF7}\x{8AF8}\x{8AF9}\x{8AFA}\x{8AFB}\x{8AFC}\x{8AFD}' .
          '\x{8AFE}\x{8AFF}\x{8B00}\x{8B01}\x{8B02}\x{8B03}\x{8B04}\x{8B05}\x{8B06}' .
          '\x{8B07}\x{8B08}\x{8B09}\x{8B0A}\x{8B0B}\x{8B0D}\x{8B0E}\x{8B0F}\x{8B10}' .
          '\x{8B11}\x{8B12}\x{8B13}\x{8B14}\x{8B15}\x{8B16}\x{8B17}\x{8B18}\x{8B19}' .
          '\x{8B1A}\x{8B1B}\x{8B1C}\x{8B1D}\x{8B1E}\x{8B1F}\x{8B20}\x{8B21}\x{8B22}' .
          '\x{8B23}\x{8B24}\x{8B25}\x{8B26}\x{8B27}\x{8B28}\x{8B2A}\x{8B2B}\x{8B2C}' .
          '\x{8B2D}\x{8B2E}\x{8B2F}\x{8B30}\x{8B31}\x{8B33}\x{8B34}\x{8B35}\x{8B36}' .
          '\x{8B37}\x{8B39}\x{8B3A}\x{8B3B}\x{8B3C}\x{8B3D}\x{8B3E}\x{8B40}\x{8B41}' .
          '\x{8B42}\x{8B43}\x{8B44}\x{8B45}\x{8B46}\x{8B47}\x{8B48}\x{8B49}\x{8B4A}' .
          '\x{8B4B}\x{8B4C}\x{8B4D}\x{8B4E}\x{8B4F}\x{8B50}\x{8B51}\x{8B52}\x{8B53}' .
          '\x{8B54}\x{8B55}\x{8B56}\x{8B57}\x{8B58}\x{8B59}\x{8B5A}\x{8B5B}\x{8B5C}' .
          '\x{8B5D}\x{8B5E}\x{8B5F}\x{8B60}\x{8B63}\x{8B64}\x{8B65}\x{8B66}\x{8B67}' .
          '\x{8B68}\x{8B6A}\x{8B6B}\x{8B6C}\x{8B6D}\x{8B6E}\x{8B6F}\x{8B70}\x{8B71}' .
          '\x{8B73}\x{8B74}\x{8B76}\x{8B77}\x{8B78}\x{8B79}\x{8B7A}\x{8B7B}\x{8B7D}' .
          '\x{8B7E}\x{8B7F}\x{8B80}\x{8B82}\x{8B83}\x{8B84}\x{8B85}\x{8B86}\x{8B88}' .
          '\x{8B89}\x{8B8A}\x{8B8B}\x{8B8C}\x{8B8E}\x{8B90}\x{8B91}\x{8B92}\x{8B93}' .
          '\x{8B94}\x{8B95}\x{8B96}\x{8B97}\x{8B98}\x{8B99}\x{8B9A}\x{8B9C}\x{8B9D}' .
          '\x{8B9E}\x{8B9F}\x{8BA0}\x{8BA1}\x{8BA2}\x{8BA3}\x{8BA4}\x{8BA5}\x{8BA6}' .
          '\x{8BA7}\x{8BA8}\x{8BA9}\x{8BAA}\x{8BAB}\x{8BAC}\x{8BAD}\x{8BAE}\x{8BAF}' .
          '\x{8BB0}\x{8BB1}\x{8BB2}\x{8BB3}\x{8BB4}\x{8BB5}\x{8BB6}\x{8BB7}\x{8BB8}' .
          '\x{8BB9}\x{8BBA}\x{8BBB}\x{8BBC}\x{8BBD}\x{8BBE}\x{8BBF}\x{8BC0}\x{8BC1}' .
          '\x{8BC2}\x{8BC3}\x{8BC4}\x{8BC5}\x{8BC6}\x{8BC7}\x{8BC8}\x{8BC9}\x{8BCA}' .
          '\x{8BCB}\x{8BCC}\x{8BCD}\x{8BCE}\x{8BCF}\x{8BD0}\x{8BD1}\x{8BD2}\x{8BD3}' .
          '\x{8BD4}\x{8BD5}\x{8BD6}\x{8BD7}\x{8BD8}\x{8BD9}\x{8BDA}\x{8BDB}\x{8BDC}' .
          '\x{8BDD}\x{8BDE}\x{8BDF}\x{8BE0}\x{8BE1}\x{8BE2}\x{8BE3}\x{8BE4}\x{8BE5}' .
          '\x{8BE6}\x{8BE7}\x{8BE8}\x{8BE9}\x{8BEA}\x{8BEB}\x{8BEC}\x{8BED}\x{8BEE}' .
          '\x{8BEF}\x{8BF0}\x{8BF1}\x{8BF2}\x{8BF3}\x{8BF4}\x{8BF5}\x{8BF6}\x{8BF7}' .
          '\x{8BF8}\x{8BF9}\x{8BFA}\x{8BFB}\x{8BFC}\x{8BFD}\x{8BFE}\x{8BFF}\x{8C00}' .
          '\x{8C01}\x{8C02}\x{8C03}\x{8C04}\x{8C05}\x{8C06}\x{8C07}\x{8C08}\x{8C09}' .
          '\x{8C0A}\x{8C0B}\x{8C0C}\x{8C0D}\x{8C0E}\x{8C0F}\x{8C10}\x{8C11}\x{8C12}' .
          '\x{8C13}\x{8C14}\x{8C15}\x{8C16}\x{8C17}\x{8C18}\x{8C19}\x{8C1A}\x{8C1B}' .
          '\x{8C1C}\x{8C1D}\x{8C1E}\x{8C1F}\x{8C20}\x{8C21}\x{8C22}\x{8C23}\x{8C24}' .
          '\x{8C25}\x{8C26}\x{8C27}\x{8C28}\x{8C29}\x{8C2A}\x{8C2B}\x{8C2C}\x{8C2D}' .
          '\x{8C2E}\x{8C2F}\x{8C30}\x{8C31}\x{8C32}\x{8C33}\x{8C34}\x{8C35}\x{8C36}' .
          '\x{8C37}\x{8C39}\x{8C3A}\x{8C3B}\x{8C3C}\x{8C3D}\x{8C3E}\x{8C3F}\x{8C41}' .
          '\x{8C42}\x{8C43}\x{8C45}\x{8C46}\x{8C47}\x{8C48}\x{8C49}\x{8C4A}\x{8C4B}' .
          '\x{8C4C}\x{8C4D}\x{8C4E}\x{8C4F}\x{8C50}\x{8C54}\x{8C55}\x{8C56}\x{8C57}' .
          '\x{8C59}\x{8C5A}\x{8C5B}\x{8C5C}\x{8C5D}\x{8C5E}\x{8C5F}\x{8C60}\x{8C61}' .
          '\x{8C62}\x{8C63}\x{8C64}\x{8C65}\x{8C66}\x{8C67}\x{8C68}\x{8C69}\x{8C6A}' .
          '\x{8C6B}\x{8C6C}\x{8C6D}\x{8C6E}\x{8C6F}\x{8C70}\x{8C71}\x{8C72}\x{8C73}' .
          '\x{8C75}\x{8C76}\x{8C77}\x{8C78}\x{8C79}\x{8C7A}\x{8C7B}\x{8C7D}\x{8C7E}' .
          '\x{8C80}\x{8C81}\x{8C82}\x{8C84}\x{8C85}\x{8C86}\x{8C88}\x{8C89}\x{8C8A}' .
          '\x{8C8C}\x{8C8D}\x{8C8F}\x{8C90}\x{8C91}\x{8C92}\x{8C93}\x{8C94}\x{8C95}' .
          '\x{8C96}\x{8C97}\x{8C98}\x{8C99}\x{8C9A}\x{8C9C}\x{8C9D}\x{8C9E}\x{8C9F}' .
          '\x{8CA0}\x{8CA1}\x{8CA2}\x{8CA3}\x{8CA4}\x{8CA5}\x{8CA7}\x{8CA8}\x{8CA9}' .
          '\x{8CAA}\x{8CAB}\x{8CAC}\x{8CAD}\x{8CAE}\x{8CAF}\x{8CB0}\x{8CB1}\x{8CB2}' .
          '\x{8CB3}\x{8CB4}\x{8CB5}\x{8CB6}\x{8CB7}\x{8CB8}\x{8CB9}\x{8CBA}\x{8CBB}' .
          '\x{8CBC}\x{8CBD}\x{8CBE}\x{8CBF}\x{8CC0}\x{8CC1}\x{8CC2}\x{8CC3}\x{8CC4}' .
          '\x{8CC5}\x{8CC6}\x{8CC7}\x{8CC8}\x{8CC9}\x{8CCA}\x{8CCC}\x{8CCE}\x{8CCF}' .
          '\x{8CD0}\x{8CD1}\x{8CD2}\x{8CD3}\x{8CD4}\x{8CD5}\x{8CD7}\x{8CD9}\x{8CDA}' .
          '\x{8CDB}\x{8CDC}\x{8CDD}\x{8CDE}\x{8CDF}\x{8CE0}\x{8CE1}\x{8CE2}\x{8CE3}' .
          '\x{8CE4}\x{8CE5}\x{8CE6}\x{8CE7}\x{8CE8}\x{8CEA}\x{8CEB}\x{8CEC}\x{8CED}' .
          '\x{8CEE}\x{8CEF}\x{8CF0}\x{8CF1}\x{8CF2}\x{8CF3}\x{8CF4}\x{8CF5}\x{8CF6}' .
          '\x{8CF8}\x{8CF9}\x{8CFA}\x{8CFB}\x{8CFC}\x{8CFD}\x{8CFE}\x{8CFF}\x{8D00}' .
          '\x{8D02}\x{8D03}\x{8D04}\x{8D05}\x{8D06}\x{8D07}\x{8D08}\x{8D09}\x{8D0A}' .
          '\x{8D0B}\x{8D0C}\x{8D0D}\x{8D0E}\x{8D0F}\x{8D10}\x{8D13}\x{8D14}\x{8D15}' .
          '\x{8D16}\x{8D17}\x{8D18}\x{8D19}\x{8D1A}\x{8D1B}\x{8D1C}\x{8D1D}\x{8D1E}' .
          '\x{8D1F}\x{8D20}\x{8D21}\x{8D22}\x{8D23}\x{8D24}\x{8D25}\x{8D26}\x{8D27}' .
          '\x{8D28}\x{8D29}\x{8D2A}\x{8D2B}\x{8D2C}\x{8D2D}\x{8D2E}\x{8D2F}\x{8D30}' .
          '\x{8D31}\x{8D32}\x{8D33}\x{8D34}\x{8D35}\x{8D36}\x{8D37}\x{8D38}\x{8D39}' .
          '\x{8D3A}\x{8D3B}\x{8D3C}\x{8D3D}\x{8D3E}\x{8D3F}\x{8D40}\x{8D41}\x{8D42}' .
          '\x{8D43}\x{8D44}\x{8D45}\x{8D46}\x{8D47}\x{8D48}\x{8D49}\x{8D4A}\x{8D4B}' .
          '\x{8D4C}\x{8D4D}\x{8D4E}\x{8D4F}\x{8D50}\x{8D51}\x{8D52}\x{8D53}\x{8D54}' .
          '\x{8D55}\x{8D56}\x{8D57}\x{8D58}\x{8D59}\x{8D5A}\x{8D5B}\x{8D5C}\x{8D5D}' .
          '\x{8D5E}\x{8D5F}\x{8D60}\x{8D61}\x{8D62}\x{8D63}\x{8D64}\x{8D65}\x{8D66}' .
          '\x{8D67}\x{8D68}\x{8D69}\x{8D6A}\x{8D6B}\x{8D6C}\x{8D6D}\x{8D6E}\x{8D6F}' .
          '\x{8D70}\x{8D71}\x{8D72}\x{8D73}\x{8D74}\x{8D75}\x{8D76}\x{8D77}\x{8D78}' .
          '\x{8D79}\x{8D7A}\x{8D7B}\x{8D7D}\x{8D7E}\x{8D7F}\x{8D80}\x{8D81}\x{8D82}' .
          '\x{8D83}\x{8D84}\x{8D85}\x{8D86}\x{8D87}\x{8D88}\x{8D89}\x{8D8A}\x{8D8B}' .
          '\x{8D8C}\x{8D8D}\x{8D8E}\x{8D8F}\x{8D90}\x{8D91}\x{8D92}\x{8D93}\x{8D94}' .
          '\x{8D95}\x{8D96}\x{8D97}\x{8D98}\x{8D99}\x{8D9A}\x{8D9B}\x{8D9C}\x{8D9D}' .
          '\x{8D9E}\x{8D9F}\x{8DA0}\x{8DA1}\x{8DA2}\x{8DA3}\x{8DA4}\x{8DA5}\x{8DA7}' .
          '\x{8DA8}\x{8DA9}\x{8DAA}\x{8DAB}\x{8DAC}\x{8DAD}\x{8DAE}\x{8DAF}\x{8DB0}' .
          '\x{8DB1}\x{8DB2}\x{8DB3}\x{8DB4}\x{8DB5}\x{8DB6}\x{8DB7}\x{8DB8}\x{8DB9}' .
          '\x{8DBA}\x{8DBB}\x{8DBC}\x{8DBD}\x{8DBE}\x{8DBF}\x{8DC1}\x{8DC2}\x{8DC3}' .
          '\x{8DC4}\x{8DC5}\x{8DC6}\x{8DC7}\x{8DC8}\x{8DC9}\x{8DCA}\x{8DCB}\x{8DCC}' .
          '\x{8DCD}\x{8DCE}\x{8DCF}\x{8DD0}\x{8DD1}\x{8DD2}\x{8DD3}\x{8DD4}\x{8DD5}' .
          '\x{8DD6}\x{8DD7}\x{8DD8}\x{8DD9}\x{8DDA}\x{8DDB}\x{8DDC}\x{8DDD}\x{8DDE}' .
          '\x{8DDF}\x{8DE0}\x{8DE1}\x{8DE2}\x{8DE3}\x{8DE4}\x{8DE6}\x{8DE7}\x{8DE8}' .
          '\x{8DE9}\x{8DEA}\x{8DEB}\x{8DEC}\x{8DED}\x{8DEE}\x{8DEF}\x{8DF0}\x{8DF1}' .
          '\x{8DF2}\x{8DF3}\x{8DF4}\x{8DF5}\x{8DF6}\x{8DF7}\x{8DF8}\x{8DF9}\x{8DFA}' .
          '\x{8DFB}\x{8DFC}\x{8DFD}\x{8DFE}\x{8DFF}\x{8E00}\x{8E02}\x{8E03}\x{8E04}' .
          '\x{8E05}\x{8E06}\x{8E07}\x{8E08}\x{8E09}\x{8E0A}\x{8E0C}\x{8E0D}\x{8E0E}' .
          '\x{8E0F}\x{8E10}\x{8E11}\x{8E12}\x{8E13}\x{8E14}\x{8E15}\x{8E16}\x{8E17}' .
          '\x{8E18}\x{8E19}\x{8E1A}\x{8E1B}\x{8E1C}\x{8E1D}\x{8E1E}\x{8E1F}\x{8E20}' .
          '\x{8E21}\x{8E22}\x{8E23}\x{8E24}\x{8E25}\x{8E26}\x{8E27}\x{8E28}\x{8E29}' .
          '\x{8E2A}\x{8E2B}\x{8E2C}\x{8E2D}\x{8E2E}\x{8E2F}\x{8E30}\x{8E31}\x{8E33}' .
          '\x{8E34}\x{8E35}\x{8E36}\x{8E37}\x{8E38}\x{8E39}\x{8E3A}\x{8E3B}\x{8E3C}' .
          '\x{8E3D}\x{8E3E}\x{8E3F}\x{8E40}\x{8E41}\x{8E42}\x{8E43}\x{8E44}\x{8E45}' .
          '\x{8E47}\x{8E48}\x{8E49}\x{8E4A}\x{8E4B}\x{8E4C}\x{8E4D}\x{8E4E}\x{8E50}' .
          '\x{8E51}\x{8E52}\x{8E53}\x{8E54}\x{8E55}\x{8E56}\x{8E57}\x{8E58}\x{8E59}' .
          '\x{8E5A}\x{8E5B}\x{8E5C}\x{8E5D}\x{8E5E}\x{8E5F}\x{8E60}\x{8E61}\x{8E62}' .
          '\x{8E63}\x{8E64}\x{8E65}\x{8E66}\x{8E67}\x{8E68}\x{8E69}\x{8E6A}\x{8E6B}' .
          '\x{8E6C}\x{8E6D}\x{8E6F}\x{8E70}\x{8E71}\x{8E72}\x{8E73}\x{8E74}\x{8E76}' .
          '\x{8E78}\x{8E7A}\x{8E7B}\x{8E7C}\x{8E7D}\x{8E7E}\x{8E7F}\x{8E80}\x{8E81}' .
          '\x{8E82}\x{8E83}\x{8E84}\x{8E85}\x{8E86}\x{8E87}\x{8E88}\x{8E89}\x{8E8A}' .
          '\x{8E8B}\x{8E8C}\x{8E8D}\x{8E8E}\x{8E8F}\x{8E90}\x{8E91}\x{8E92}\x{8E93}' .
          '\x{8E94}\x{8E95}\x{8E96}\x{8E97}\x{8E98}\x{8E9A}\x{8E9C}\x{8E9D}\x{8E9E}' .
          '\x{8E9F}\x{8EA0}\x{8EA1}\x{8EA3}\x{8EA4}\x{8EA5}\x{8EA6}\x{8EA7}\x{8EA8}' .
          '\x{8EA9}\x{8EAA}\x{8EAB}\x{8EAC}\x{8EAD}\x{8EAE}\x{8EAF}\x{8EB0}\x{8EB1}' .
          '\x{8EB2}\x{8EB4}\x{8EB5}\x{8EB8}\x{8EB9}\x{8EBA}\x{8EBB}\x{8EBC}\x{8EBD}' .
          '\x{8EBE}\x{8EBF}\x{8EC0}\x{8EC2}\x{8EC3}\x{8EC5}\x{8EC6}\x{8EC7}\x{8EC8}' .
          '\x{8EC9}\x{8ECA}\x{8ECB}\x{8ECC}\x{8ECD}\x{8ECE}\x{8ECF}\x{8ED0}\x{8ED1}' .
          '\x{8ED2}\x{8ED3}\x{8ED4}\x{8ED5}\x{8ED6}\x{8ED7}\x{8ED8}\x{8EDA}\x{8EDB}' .
          '\x{8EDC}\x{8EDD}\x{8EDE}\x{8EDF}\x{8EE0}\x{8EE1}\x{8EE4}\x{8EE5}\x{8EE6}' .
          '\x{8EE7}\x{8EE8}\x{8EE9}\x{8EEA}\x{8EEB}\x{8EEC}\x{8EED}\x{8EEE}\x{8EEF}' .
          '\x{8EF1}\x{8EF2}\x{8EF3}\x{8EF4}\x{8EF5}\x{8EF6}\x{8EF7}\x{8EF8}\x{8EF9}' .
          '\x{8EFA}\x{8EFB}\x{8EFC}\x{8EFD}\x{8EFE}\x{8EFF}\x{8F00}\x{8F01}\x{8F02}' .
          '\x{8F03}\x{8F04}\x{8F05}\x{8F06}\x{8F07}\x{8F08}\x{8F09}\x{8F0A}\x{8F0B}' .
          '\x{8F0D}\x{8F0E}\x{8F10}\x{8F11}\x{8F12}\x{8F13}\x{8F14}\x{8F15}\x{8F16}' .
          '\x{8F17}\x{8F18}\x{8F1A}\x{8F1B}\x{8F1C}\x{8F1D}\x{8F1E}\x{8F1F}\x{8F20}' .
          '\x{8F21}\x{8F22}\x{8F23}\x{8F24}\x{8F25}\x{8F26}\x{8F27}\x{8F28}\x{8F29}' .
          '\x{8F2A}\x{8F2B}\x{8F2C}\x{8F2E}\x{8F2F}\x{8F30}\x{8F31}\x{8F32}\x{8F33}' .
          '\x{8F34}\x{8F35}\x{8F36}\x{8F37}\x{8F38}\x{8F39}\x{8F3B}\x{8F3C}\x{8F3D}' .
          '\x{8F3E}\x{8F3F}\x{8F40}\x{8F42}\x{8F43}\x{8F44}\x{8F45}\x{8F46}\x{8F47}' .
          '\x{8F48}\x{8F49}\x{8F4A}\x{8F4B}\x{8F4C}\x{8F4D}\x{8F4E}\x{8F4F}\x{8F50}' .
          '\x{8F51}\x{8F52}\x{8F53}\x{8F54}\x{8F55}\x{8F56}\x{8F57}\x{8F58}\x{8F59}' .
          '\x{8F5A}\x{8F5B}\x{8F5D}\x{8F5E}\x{8F5F}\x{8F60}\x{8F61}\x{8F62}\x{8F63}' .
          '\x{8F64}\x{8F65}\x{8F66}\x{8F67}\x{8F68}\x{8F69}\x{8F6A}\x{8F6B}\x{8F6C}' .
          '\x{8F6D}\x{8F6E}\x{8F6F}\x{8F70}\x{8F71}\x{8F72}\x{8F73}\x{8F74}\x{8F75}' .
          '\x{8F76}\x{8F77}\x{8F78}\x{8F79}\x{8F7A}\x{8F7B}\x{8F7C}\x{8F7D}\x{8F7E}' .
          '\x{8F7F}\x{8F80}\x{8F81}\x{8F82}\x{8F83}\x{8F84}\x{8F85}\x{8F86}\x{8F87}' .
          '\x{8F88}\x{8F89}\x{8F8A}\x{8F8B}\x{8F8C}\x{8F8D}\x{8F8E}\x{8F8F}\x{8F90}' .
          '\x{8F91}\x{8F92}\x{8F93}\x{8F94}\x{8F95}\x{8F96}\x{8F97}\x{8F98}\x{8F99}' .
          '\x{8F9A}\x{8F9B}\x{8F9C}\x{8F9E}\x{8F9F}\x{8FA0}\x{8FA1}\x{8FA2}\x{8FA3}' .
          '\x{8FA5}\x{8FA6}\x{8FA7}\x{8FA8}\x{8FA9}\x{8FAA}\x{8FAB}\x{8FAC}\x{8FAD}' .
          '\x{8FAE}\x{8FAF}\x{8FB0}\x{8FB1}\x{8FB2}\x{8FB4}\x{8FB5}\x{8FB6}\x{8FB7}' .
          '\x{8FB8}\x{8FB9}\x{8FBB}\x{8FBC}\x{8FBD}\x{8FBE}\x{8FBF}\x{8FC0}\x{8FC1}' .
          '\x{8FC2}\x{8FC4}\x{8FC5}\x{8FC6}\x{8FC7}\x{8FC8}\x{8FC9}\x{8FCB}\x{8FCC}' .
          '\x{8FCD}\x{8FCE}\x{8FCF}\x{8FD0}\x{8FD1}\x{8FD2}\x{8FD3}\x{8FD4}\x{8FD5}' .
          '\x{8FD6}\x{8FD7}\x{8FD8}\x{8FD9}\x{8FDA}\x{8FDB}\x{8FDC}\x{8FDD}\x{8FDE}' .
          '\x{8FDF}\x{8FE0}\x{8FE1}\x{8FE2}\x{8FE3}\x{8FE4}\x{8FE5}\x{8FE6}\x{8FE8}' .
          '\x{8FE9}\x{8FEA}\x{8FEB}\x{8FEC}\x{8FED}\x{8FEE}\x{8FEF}\x{8FF0}\x{8FF1}' .
          '\x{8FF2}\x{8FF3}\x{8FF4}\x{8FF5}\x{8FF6}\x{8FF7}\x{8FF8}\x{8FF9}\x{8FFA}' .
          '\x{8FFB}\x{8FFC}\x{8FFD}\x{8FFE}\x{8FFF}\x{9000}\x{9001}\x{9002}\x{9003}' .
          '\x{9004}\x{9005}\x{9006}\x{9007}\x{9008}\x{9009}\x{900A}\x{900B}\x{900C}' .
          '\x{900D}\x{900F}\x{9010}\x{9011}\x{9012}\x{9013}\x{9014}\x{9015}\x{9016}' .
          '\x{9017}\x{9018}\x{9019}\x{901A}\x{901B}\x{901C}\x{901D}\x{901E}\x{901F}' .
          '\x{9020}\x{9021}\x{9022}\x{9023}\x{9024}\x{9025}\x{9026}\x{9027}\x{9028}' .
          '\x{9029}\x{902B}\x{902D}\x{902E}\x{902F}\x{9030}\x{9031}\x{9032}\x{9033}' .
          '\x{9034}\x{9035}\x{9036}\x{9038}\x{903A}\x{903B}\x{903C}\x{903D}\x{903E}' .
          '\x{903F}\x{9041}\x{9042}\x{9043}\x{9044}\x{9045}\x{9047}\x{9048}\x{9049}' .
          '\x{904A}\x{904B}\x{904C}\x{904D}\x{904E}\x{904F}\x{9050}\x{9051}\x{9052}' .
          '\x{9053}\x{9054}\x{9055}\x{9056}\x{9057}\x{9058}\x{9059}\x{905A}\x{905B}' .
          '\x{905C}\x{905D}\x{905E}\x{905F}\x{9060}\x{9061}\x{9062}\x{9063}\x{9064}' .
          '\x{9065}\x{9066}\x{9067}\x{9068}\x{9069}\x{906A}\x{906B}\x{906C}\x{906D}' .
          '\x{906E}\x{906F}\x{9070}\x{9071}\x{9072}\x{9073}\x{9074}\x{9075}\x{9076}' .
          '\x{9077}\x{9078}\x{9079}\x{907A}\x{907B}\x{907C}\x{907D}\x{907E}\x{907F}' .
          '\x{9080}\x{9081}\x{9082}\x{9083}\x{9084}\x{9085}\x{9086}\x{9087}\x{9088}' .
          '\x{9089}\x{908A}\x{908B}\x{908C}\x{908D}\x{908E}\x{908F}\x{9090}\x{9091}' .
          '\x{9092}\x{9093}\x{9094}\x{9095}\x{9096}\x{9097}\x{9098}\x{9099}\x{909A}' .
          '\x{909B}\x{909C}\x{909D}\x{909E}\x{909F}\x{90A0}\x{90A1}\x{90A2}\x{90A3}' .
          '\x{90A4}\x{90A5}\x{90A6}\x{90A7}\x{90A8}\x{90A9}\x{90AA}\x{90AC}\x{90AD}' .
          '\x{90AE}\x{90AF}\x{90B0}\x{90B1}\x{90B2}\x{90B3}\x{90B4}\x{90B5}\x{90B6}' .
          '\x{90B7}\x{90B8}\x{90B9}\x{90BA}\x{90BB}\x{90BC}\x{90BD}\x{90BE}\x{90BF}' .
          '\x{90C0}\x{90C1}\x{90C2}\x{90C3}\x{90C4}\x{90C5}\x{90C6}\x{90C7}\x{90C8}' .
          '\x{90C9}\x{90CA}\x{90CB}\x{90CE}\x{90CF}\x{90D0}\x{90D1}\x{90D3}\x{90D4}' .
          '\x{90D5}\x{90D6}\x{90D7}\x{90D8}\x{90D9}\x{90DA}\x{90DB}\x{90DC}\x{90DD}' .
          '\x{90DE}\x{90DF}\x{90E0}\x{90E1}\x{90E2}\x{90E3}\x{90E4}\x{90E5}\x{90E6}' .
          '\x{90E7}\x{90E8}\x{90E9}\x{90EA}\x{90EB}\x{90EC}\x{90ED}\x{90EE}\x{90EF}' .
          '\x{90F0}\x{90F1}\x{90F2}\x{90F3}\x{90F4}\x{90F5}\x{90F7}\x{90F8}\x{90F9}' .
          '\x{90FA}\x{90FB}\x{90FC}\x{90FD}\x{90FE}\x{90FF}\x{9100}\x{9101}\x{9102}' .
          '\x{9103}\x{9104}\x{9105}\x{9106}\x{9107}\x{9108}\x{9109}\x{910B}\x{910C}' .
          '\x{910D}\x{910E}\x{910F}\x{9110}\x{9111}\x{9112}\x{9113}\x{9114}\x{9115}' .
          '\x{9116}\x{9117}\x{9118}\x{9119}\x{911A}\x{911B}\x{911C}\x{911D}\x{911E}' .
          '\x{911F}\x{9120}\x{9121}\x{9122}\x{9123}\x{9124}\x{9125}\x{9126}\x{9127}' .
          '\x{9128}\x{9129}\x{912A}\x{912B}\x{912C}\x{912D}\x{912E}\x{912F}\x{9130}' .
          '\x{9131}\x{9132}\x{9133}\x{9134}\x{9135}\x{9136}\x{9137}\x{9138}\x{9139}' .
          '\x{913A}\x{913B}\x{913E}\x{913F}\x{9140}\x{9141}\x{9142}\x{9143}\x{9144}' .
          '\x{9145}\x{9146}\x{9147}\x{9148}\x{9149}\x{914A}\x{914B}\x{914C}\x{914D}' .
          '\x{914E}\x{914F}\x{9150}\x{9151}\x{9152}\x{9153}\x{9154}\x{9155}\x{9156}' .
          '\x{9157}\x{9158}\x{915A}\x{915B}\x{915C}\x{915D}\x{915E}\x{915F}\x{9160}' .
          '\x{9161}\x{9162}\x{9163}\x{9164}\x{9165}\x{9166}\x{9167}\x{9168}\x{9169}' .
          '\x{916A}\x{916B}\x{916C}\x{916D}\x{916E}\x{916F}\x{9170}\x{9171}\x{9172}' .
          '\x{9173}\x{9174}\x{9175}\x{9176}\x{9177}\x{9178}\x{9179}\x{917A}\x{917C}' .
          '\x{917D}\x{917E}\x{917F}\x{9180}\x{9181}\x{9182}\x{9183}\x{9184}\x{9185}' .
          '\x{9186}\x{9187}\x{9188}\x{9189}\x{918A}\x{918B}\x{918C}\x{918D}\x{918E}' .
          '\x{918F}\x{9190}\x{9191}\x{9192}\x{9193}\x{9194}\x{9196}\x{9199}\x{919A}' .
          '\x{919B}\x{919C}\x{919D}\x{919E}\x{919F}\x{91A0}\x{91A1}\x{91A2}\x{91A3}' .
          '\x{91A5}\x{91A6}\x{91A7}\x{91A8}\x{91AA}\x{91AB}\x{91AC}\x{91AD}\x{91AE}' .
          '\x{91AF}\x{91B0}\x{91B1}\x{91B2}\x{91B3}\x{91B4}\x{91B5}\x{91B6}\x{91B7}' .
          '\x{91B9}\x{91BA}\x{91BB}\x{91BC}\x{91BD}\x{91BE}\x{91C0}\x{91C1}\x{91C2}' .
          '\x{91C3}\x{91C5}\x{91C6}\x{91C7}\x{91C9}\x{91CA}\x{91CB}\x{91CC}\x{91CD}' .
          '\x{91CE}\x{91CF}\x{91D0}\x{91D1}\x{91D2}\x{91D3}\x{91D4}\x{91D5}\x{91D7}' .
          '\x{91D8}\x{91D9}\x{91DA}\x{91DB}\x{91DC}\x{91DD}\x{91DE}\x{91DF}\x{91E2}' .
          '\x{91E3}\x{91E4}\x{91E5}\x{91E6}\x{91E7}\x{91E8}\x{91E9}\x{91EA}\x{91EB}' .
          '\x{91EC}\x{91ED}\x{91EE}\x{91F0}\x{91F1}\x{91F2}\x{91F3}\x{91F4}\x{91F5}' .
          '\x{91F7}\x{91F8}\x{91F9}\x{91FA}\x{91FB}\x{91FD}\x{91FE}\x{91FF}\x{9200}' .
          '\x{9201}\x{9202}\x{9203}\x{9204}\x{9205}\x{9206}\x{9207}\x{9208}\x{9209}' .
          '\x{920A}\x{920B}\x{920C}\x{920D}\x{920E}\x{920F}\x{9210}\x{9211}\x{9212}' .
          '\x{9214}\x{9215}\x{9216}\x{9217}\x{9218}\x{9219}\x{921A}\x{921B}\x{921C}' .
          '\x{921D}\x{921E}\x{9220}\x{9221}\x{9223}\x{9224}\x{9225}\x{9226}\x{9227}' .
          '\x{9228}\x{9229}\x{922A}\x{922B}\x{922D}\x{922E}\x{922F}\x{9230}\x{9231}' .
          '\x{9232}\x{9233}\x{9234}\x{9235}\x{9236}\x{9237}\x{9238}\x{9239}\x{923A}' .
          '\x{923B}\x{923C}\x{923D}\x{923E}\x{923F}\x{9240}\x{9241}\x{9242}\x{9245}' .
          '\x{9246}\x{9247}\x{9248}\x{9249}\x{924A}\x{924B}\x{924C}\x{924D}\x{924E}' .
          '\x{924F}\x{9250}\x{9251}\x{9252}\x{9253}\x{9254}\x{9255}\x{9256}\x{9257}' .
          '\x{9258}\x{9259}\x{925A}\x{925B}\x{925C}\x{925D}\x{925E}\x{925F}\x{9260}' .
          '\x{9261}\x{9262}\x{9263}\x{9264}\x{9265}\x{9266}\x{9267}\x{9268}\x{926B}' .
          '\x{926C}\x{926D}\x{926E}\x{926F}\x{9270}\x{9272}\x{9273}\x{9274}\x{9275}' .
          '\x{9276}\x{9277}\x{9278}\x{9279}\x{927A}\x{927B}\x{927C}\x{927D}\x{927E}' .
          '\x{927F}\x{9280}\x{9282}\x{9283}\x{9285}\x{9286}\x{9287}\x{9288}\x{9289}' .
          '\x{928A}\x{928B}\x{928C}\x{928D}\x{928E}\x{928F}\x{9290}\x{9291}\x{9292}' .
          '\x{9293}\x{9294}\x{9295}\x{9296}\x{9297}\x{9298}\x{9299}\x{929A}\x{929B}' .
          '\x{929C}\x{929D}\x{929F}\x{92A0}\x{92A1}\x{92A2}\x{92A3}\x{92A4}\x{92A5}' .
          '\x{92A6}\x{92A7}\x{92A8}\x{92A9}\x{92AA}\x{92AB}\x{92AC}\x{92AD}\x{92AE}' .
          '\x{92AF}\x{92B0}\x{92B1}\x{92B2}\x{92B3}\x{92B4}\x{92B5}\x{92B6}\x{92B7}' .
          '\x{92B8}\x{92B9}\x{92BA}\x{92BB}\x{92BC}\x{92BE}\x{92BF}\x{92C0}\x{92C1}' .
          '\x{92C2}\x{92C3}\x{92C4}\x{92C5}\x{92C6}\x{92C7}\x{92C8}\x{92C9}\x{92CA}' .
          '\x{92CB}\x{92CC}\x{92CD}\x{92CE}\x{92CF}\x{92D0}\x{92D1}\x{92D2}\x{92D3}' .
          '\x{92D5}\x{92D6}\x{92D7}\x{92D8}\x{92D9}\x{92DA}\x{92DC}\x{92DD}\x{92DE}' .
          '\x{92DF}\x{92E0}\x{92E1}\x{92E3}\x{92E4}\x{92E5}\x{92E6}\x{92E7}\x{92E8}' .
          '\x{92E9}\x{92EA}\x{92EB}\x{92EC}\x{92ED}\x{92EE}\x{92EF}\x{92F0}\x{92F1}' .
          '\x{92F2}\x{92F3}\x{92F4}\x{92F5}\x{92F6}\x{92F7}\x{92F8}\x{92F9}\x{92FA}' .
          '\x{92FB}\x{92FC}\x{92FD}\x{92FE}\x{92FF}\x{9300}\x{9301}\x{9302}\x{9303}' .
          '\x{9304}\x{9305}\x{9306}\x{9307}\x{9308}\x{9309}\x{930A}\x{930B}\x{930C}' .
          '\x{930D}\x{930E}\x{930F}\x{9310}\x{9311}\x{9312}\x{9313}\x{9314}\x{9315}' .
          '\x{9316}\x{9317}\x{9318}\x{9319}\x{931A}\x{931B}\x{931D}\x{931E}\x{931F}' .
          '\x{9320}\x{9321}\x{9322}\x{9323}\x{9324}\x{9325}\x{9326}\x{9327}\x{9328}' .
          '\x{9329}\x{932A}\x{932B}\x{932D}\x{932E}\x{932F}\x{9332}\x{9333}\x{9334}' .
          '\x{9335}\x{9336}\x{9337}\x{9338}\x{9339}\x{933A}\x{933B}\x{933C}\x{933D}' .
          '\x{933E}\x{933F}\x{9340}\x{9341}\x{9342}\x{9343}\x{9344}\x{9345}\x{9346}' .
          '\x{9347}\x{9348}\x{9349}\x{934A}\x{934B}\x{934C}\x{934D}\x{934E}\x{934F}' .
          '\x{9350}\x{9351}\x{9352}\x{9353}\x{9354}\x{9355}\x{9356}\x{9357}\x{9358}' .
          '\x{9359}\x{935A}\x{935B}\x{935C}\x{935D}\x{935E}\x{935F}\x{9360}\x{9361}' .
          '\x{9363}\x{9364}\x{9365}\x{9366}\x{9367}\x{9369}\x{936A}\x{936C}\x{936D}' .
          '\x{936E}\x{9370}\x{9371}\x{9372}\x{9374}\x{9375}\x{9376}\x{9377}\x{9379}' .
          '\x{937A}\x{937B}\x{937C}\x{937D}\x{937E}\x{9380}\x{9382}\x{9383}\x{9384}' .
          '\x{9385}\x{9386}\x{9387}\x{9388}\x{9389}\x{938A}\x{938C}\x{938D}\x{938E}' .
          '\x{938F}\x{9390}\x{9391}\x{9392}\x{9393}\x{9394}\x{9395}\x{9396}\x{9397}' .
          '\x{9398}\x{9399}\x{939A}\x{939B}\x{939D}\x{939E}\x{939F}\x{93A1}\x{93A2}' .
          '\x{93A3}\x{93A4}\x{93A5}\x{93A6}\x{93A7}\x{93A8}\x{93A9}\x{93AA}\x{93AC}' .
          '\x{93AD}\x{93AE}\x{93AF}\x{93B0}\x{93B1}\x{93B2}\x{93B3}\x{93B4}\x{93B5}' .
          '\x{93B6}\x{93B7}\x{93B8}\x{93B9}\x{93BA}\x{93BC}\x{93BD}\x{93BE}\x{93BF}' .
          '\x{93C0}\x{93C1}\x{93C2}\x{93C3}\x{93C4}\x{93C5}\x{93C6}\x{93C7}\x{93C8}' .
          '\x{93C9}\x{93CA}\x{93CB}\x{93CC}\x{93CD}\x{93CE}\x{93CF}\x{93D0}\x{93D1}' .
          '\x{93D2}\x{93D3}\x{93D4}\x{93D5}\x{93D6}\x{93D7}\x{93D8}\x{93D9}\x{93DA}' .
          '\x{93DB}\x{93DC}\x{93DD}\x{93DE}\x{93DF}\x{93E1}\x{93E2}\x{93E3}\x{93E4}' .
          '\x{93E6}\x{93E7}\x{93E8}\x{93E9}\x{93EA}\x{93EB}\x{93EC}\x{93ED}\x{93EE}' .
          '\x{93EF}\x{93F0}\x{93F1}\x{93F2}\x{93F4}\x{93F5}\x{93F6}\x{93F7}\x{93F8}' .
          '\x{93F9}\x{93FA}\x{93FB}\x{93FC}\x{93FD}\x{93FE}\x{93FF}\x{9400}\x{9401}' .
          '\x{9403}\x{9404}\x{9405}\x{9406}\x{9407}\x{9408}\x{9409}\x{940A}\x{940B}' .
          '\x{940C}\x{940D}\x{940E}\x{940F}\x{9410}\x{9411}\x{9412}\x{9413}\x{9414}' .
          '\x{9415}\x{9416}\x{9418}\x{9419}\x{941B}\x{941D}\x{9420}\x{9422}\x{9423}' .
          '\x{9425}\x{9426}\x{9427}\x{9428}\x{9429}\x{942A}\x{942B}\x{942C}\x{942D}' .
          '\x{942E}\x{942F}\x{9430}\x{9431}\x{9432}\x{9433}\x{9434}\x{9435}\x{9436}' .
          '\x{9437}\x{9438}\x{9439}\x{943A}\x{943B}\x{943C}\x{943D}\x{943E}\x{943F}' .
          '\x{9440}\x{9441}\x{9442}\x{9444}\x{9445}\x{9446}\x{9447}\x{9448}\x{9449}' .
          '\x{944A}\x{944B}\x{944C}\x{944D}\x{944F}\x{9450}\x{9451}\x{9452}\x{9453}' .
          '\x{9454}\x{9455}\x{9456}\x{9457}\x{9458}\x{9459}\x{945B}\x{945C}\x{945D}' .
          '\x{945E}\x{945F}\x{9460}\x{9461}\x{9462}\x{9463}\x{9464}\x{9465}\x{9466}' .
          '\x{9467}\x{9468}\x{9469}\x{946A}\x{946B}\x{946D}\x{946E}\x{946F}\x{9470}' .
          '\x{9471}\x{9472}\x{9473}\x{9474}\x{9475}\x{9476}\x{9477}\x{9478}\x{9479}' .
          '\x{947A}\x{947C}\x{947D}\x{947E}\x{947F}\x{9480}\x{9481}\x{9482}\x{9483}' .
          '\x{9484}\x{9485}\x{9486}\x{9487}\x{9488}\x{9489}\x{948A}\x{948B}\x{948C}' .
          '\x{948D}\x{948E}\x{948F}\x{9490}\x{9491}\x{9492}\x{9493}\x{9494}\x{9495}' .
          '\x{9496}\x{9497}\x{9498}\x{9499}\x{949A}\x{949B}\x{949C}\x{949D}\x{949E}' .
          '\x{949F}\x{94A0}\x{94A1}\x{94A2}\x{94A3}\x{94A4}\x{94A5}\x{94A6}\x{94A7}' .
          '\x{94A8}\x{94A9}\x{94AA}\x{94AB}\x{94AC}\x{94AD}\x{94AE}\x{94AF}\x{94B0}' .
          '\x{94B1}\x{94B2}\x{94B3}\x{94B4}\x{94B5}\x{94B6}\x{94B7}\x{94B8}\x{94B9}' .
          '\x{94BA}\x{94BB}\x{94BC}\x{94BD}\x{94BE}\x{94BF}\x{94C0}\x{94C1}\x{94C2}' .
          '\x{94C3}\x{94C4}\x{94C5}\x{94C6}\x{94C7}\x{94C8}\x{94C9}\x{94CA}\x{94CB}' .
          '\x{94CC}\x{94CD}\x{94CE}\x{94CF}\x{94D0}\x{94D1}\x{94D2}\x{94D3}\x{94D4}' .
          '\x{94D5}\x{94D6}\x{94D7}\x{94D8}\x{94D9}\x{94DA}\x{94DB}\x{94DC}\x{94DD}' .
          '\x{94DE}\x{94DF}\x{94E0}\x{94E1}\x{94E2}\x{94E3}\x{94E4}\x{94E5}\x{94E6}' .
          '\x{94E7}\x{94E8}\x{94E9}\x{94EA}\x{94EB}\x{94EC}\x{94ED}\x{94EE}\x{94EF}' .
          '\x{94F0}\x{94F1}\x{94F2}\x{94F3}\x{94F4}\x{94F5}\x{94F6}\x{94F7}\x{94F8}' .
          '\x{94F9}\x{94FA}\x{94FB}\x{94FC}\x{94FD}\x{94FE}\x{94FF}\x{9500}\x{9501}' .
          '\x{9502}\x{9503}\x{9504}\x{9505}\x{9506}\x{9507}\x{9508}\x{9509}\x{950A}' .
          '\x{950B}\x{950C}\x{950D}\x{950E}\x{950F}\x{9510}\x{9511}\x{9512}\x{9513}' .
          '\x{9514}\x{9515}\x{9516}\x{9517}\x{9518}\x{9519}\x{951A}\x{951B}\x{951C}' .
          '\x{951D}\x{951E}\x{951F}\x{9520}\x{9521}\x{9522}\x{9523}\x{9524}\x{9525}' .
          '\x{9526}\x{9527}\x{9528}\x{9529}\x{952A}\x{952B}\x{952C}\x{952D}\x{952E}' .
          '\x{952F}\x{9530}\x{9531}\x{9532}\x{9533}\x{9534}\x{9535}\x{9536}\x{9537}' .
          '\x{9538}\x{9539}\x{953A}\x{953B}\x{953C}\x{953D}\x{953E}\x{953F}\x{9540}' .
          '\x{9541}\x{9542}\x{9543}\x{9544}\x{9545}\x{9546}\x{9547}\x{9548}\x{9549}' .
          '\x{954A}\x{954B}\x{954C}\x{954D}\x{954E}\x{954F}\x{9550}\x{9551}\x{9552}' .
          '\x{9553}\x{9554}\x{9555}\x{9556}\x{9557}\x{9558}\x{9559}\x{955A}\x{955B}' .
          '\x{955C}\x{955D}\x{955E}\x{955F}\x{9560}\x{9561}\x{9562}\x{9563}\x{9564}' .
          '\x{9565}\x{9566}\x{9567}\x{9568}\x{9569}\x{956A}\x{956B}\x{956C}\x{956D}' .
          '\x{956E}\x{956F}\x{9570}\x{9571}\x{9572}\x{9573}\x{9574}\x{9575}\x{9576}' .
          '\x{9577}\x{957A}\x{957B}\x{957C}\x{957D}\x{957F}\x{9580}\x{9581}\x{9582}' .
          '\x{9583}\x{9584}\x{9586}\x{9587}\x{9588}\x{9589}\x{958A}\x{958B}\x{958C}' .
          '\x{958D}\x{958E}\x{958F}\x{9590}\x{9591}\x{9592}\x{9593}\x{9594}\x{9595}' .
          '\x{9596}\x{9598}\x{9599}\x{959A}\x{959B}\x{959C}\x{959D}\x{959E}\x{959F}' .
          '\x{95A1}\x{95A2}\x{95A3}\x{95A4}\x{95A5}\x{95A6}\x{95A7}\x{95A8}\x{95A9}' .
          '\x{95AA}\x{95AB}\x{95AC}\x{95AD}\x{95AE}\x{95AF}\x{95B0}\x{95B1}\x{95B2}' .
          '\x{95B5}\x{95B6}\x{95B7}\x{95B9}\x{95BA}\x{95BB}\x{95BC}\x{95BD}\x{95BE}' .
          '\x{95BF}\x{95C0}\x{95C2}\x{95C3}\x{95C4}\x{95C5}\x{95C6}\x{95C7}\x{95C8}' .
          '\x{95C9}\x{95CA}\x{95CB}\x{95CC}\x{95CD}\x{95CE}\x{95CF}\x{95D0}\x{95D1}' .
          '\x{95D2}\x{95D3}\x{95D4}\x{95D5}\x{95D6}\x{95D7}\x{95D8}\x{95DA}\x{95DB}' .
          '\x{95DC}\x{95DE}\x{95DF}\x{95E0}\x{95E1}\x{95E2}\x{95E3}\x{95E4}\x{95E5}' .
          '\x{95E6}\x{95E7}\x{95E8}\x{95E9}\x{95EA}\x{95EB}\x{95EC}\x{95ED}\x{95EE}' .
          '\x{95EF}\x{95F0}\x{95F1}\x{95F2}\x{95F3}\x{95F4}\x{95F5}\x{95F6}\x{95F7}' .
          '\x{95F8}\x{95F9}\x{95FA}\x{95FB}\x{95FC}\x{95FD}\x{95FE}\x{95FF}\x{9600}' .
          '\x{9601}\x{9602}\x{9603}\x{9604}\x{9605}\x{9606}\x{9607}\x{9608}\x{9609}' .
          '\x{960A}\x{960B}\x{960C}\x{960D}\x{960E}\x{960F}\x{9610}\x{9611}\x{9612}' .
          '\x{9613}\x{9614}\x{9615}\x{9616}\x{9617}\x{9618}\x{9619}\x{961A}\x{961B}' .
          '\x{961C}\x{961D}\x{961E}\x{961F}\x{9620}\x{9621}\x{9622}\x{9623}\x{9624}' .
          '\x{9627}\x{9628}\x{962A}\x{962B}\x{962C}\x{962D}\x{962E}\x{962F}\x{9630}' .
          '\x{9631}\x{9632}\x{9633}\x{9634}\x{9635}\x{9636}\x{9637}\x{9638}\x{9639}' .
          '\x{963A}\x{963B}\x{963C}\x{963D}\x{963F}\x{9640}\x{9641}\x{9642}\x{9643}' .
          '\x{9644}\x{9645}\x{9646}\x{9647}\x{9648}\x{9649}\x{964A}\x{964B}\x{964C}' .
          '\x{964D}\x{964E}\x{964F}\x{9650}\x{9651}\x{9652}\x{9653}\x{9654}\x{9655}' .
          '\x{9658}\x{9659}\x{965A}\x{965B}\x{965C}\x{965D}\x{965E}\x{965F}\x{9660}' .
          '\x{9661}\x{9662}\x{9663}\x{9664}\x{9666}\x{9667}\x{9668}\x{9669}\x{966A}' .
          '\x{966B}\x{966C}\x{966D}\x{966E}\x{966F}\x{9670}\x{9671}\x{9672}\x{9673}' .
          '\x{9674}\x{9675}\x{9676}\x{9677}\x{9678}\x{967C}\x{967D}\x{967E}\x{9680}' .
          '\x{9683}\x{9684}\x{9685}\x{9686}\x{9687}\x{9688}\x{9689}\x{968A}\x{968B}' .
          '\x{968D}\x{968E}\x{968F}\x{9690}\x{9691}\x{9692}\x{9693}\x{9694}\x{9695}' .
          '\x{9697}\x{9698}\x{9699}\x{969B}\x{969C}\x{969E}\x{96A0}\x{96A1}\x{96A2}' .
          '\x{96A3}\x{96A4}\x{96A5}\x{96A6}\x{96A7}\x{96A8}\x{96A9}\x{96AA}\x{96AC}' .
          '\x{96AD}\x{96AE}\x{96B0}\x{96B1}\x{96B3}\x{96B4}\x{96B6}\x{96B7}\x{96B8}' .
          '\x{96B9}\x{96BA}\x{96BB}\x{96BC}\x{96BD}\x{96BE}\x{96BF}\x{96C0}\x{96C1}' .
          '\x{96C2}\x{96C3}\x{96C4}\x{96C5}\x{96C6}\x{96C7}\x{96C8}\x{96C9}\x{96CA}' .
          '\x{96CB}\x{96CC}\x{96CD}\x{96CE}\x{96CF}\x{96D0}\x{96D1}\x{96D2}\x{96D3}' .
          '\x{96D4}\x{96D5}\x{96D6}\x{96D7}\x{96D8}\x{96D9}\x{96DA}\x{96DB}\x{96DC}' .
          '\x{96DD}\x{96DE}\x{96DF}\x{96E0}\x{96E1}\x{96E2}\x{96E3}\x{96E5}\x{96E8}' .
          '\x{96E9}\x{96EA}\x{96EB}\x{96EC}\x{96ED}\x{96EE}\x{96EF}\x{96F0}\x{96F1}' .
          '\x{96F2}\x{96F3}\x{96F4}\x{96F5}\x{96F6}\x{96F7}\x{96F8}\x{96F9}\x{96FA}' .
          '\x{96FB}\x{96FD}\x{96FE}\x{96FF}\x{9700}\x{9701}\x{9702}\x{9703}\x{9704}' .
          '\x{9705}\x{9706}\x{9707}\x{9708}\x{9709}\x{970A}\x{970B}\x{970C}\x{970D}' .
          '\x{970E}\x{970F}\x{9710}\x{9711}\x{9712}\x{9713}\x{9715}\x{9716}\x{9718}' .
          '\x{9719}\x{971C}\x{971D}\x{971E}\x{971F}\x{9720}\x{9721}\x{9722}\x{9723}' .
          '\x{9724}\x{9725}\x{9726}\x{9727}\x{9728}\x{9729}\x{972A}\x{972B}\x{972C}' .
          '\x{972D}\x{972E}\x{972F}\x{9730}\x{9731}\x{9732}\x{9735}\x{9736}\x{9738}' .
          '\x{9739}\x{973A}\x{973B}\x{973C}\x{973D}\x{973E}\x{973F}\x{9742}\x{9743}' .
          '\x{9744}\x{9745}\x{9746}\x{9747}\x{9748}\x{9749}\x{974A}\x{974B}\x{974C}' .
          '\x{974E}\x{974F}\x{9750}\x{9751}\x{9752}\x{9753}\x{9754}\x{9755}\x{9756}' .
          '\x{9758}\x{9759}\x{975A}\x{975B}\x{975C}\x{975D}\x{975E}\x{975F}\x{9760}' .
          '\x{9761}\x{9762}\x{9765}\x{9766}\x{9767}\x{9768}\x{9769}\x{976A}\x{976B}' .
          '\x{976C}\x{976D}\x{976E}\x{976F}\x{9770}\x{9772}\x{9773}\x{9774}\x{9776}' .
          '\x{9777}\x{9778}\x{9779}\x{977A}\x{977B}\x{977C}\x{977D}\x{977E}\x{977F}' .
          '\x{9780}\x{9781}\x{9782}\x{9783}\x{9784}\x{9785}\x{9786}\x{9788}\x{978A}' .
          '\x{978B}\x{978C}\x{978D}\x{978E}\x{978F}\x{9790}\x{9791}\x{9792}\x{9793}' .
          '\x{9794}\x{9795}\x{9796}\x{9797}\x{9798}\x{9799}\x{979A}\x{979C}\x{979D}' .
          '\x{979E}\x{979F}\x{97A0}\x{97A1}\x{97A2}\x{97A3}\x{97A4}\x{97A5}\x{97A6}' .
          '\x{97A7}\x{97A8}\x{97AA}\x{97AB}\x{97AC}\x{97AD}\x{97AE}\x{97AF}\x{97B2}' .
          '\x{97B3}\x{97B4}\x{97B6}\x{97B7}\x{97B8}\x{97B9}\x{97BA}\x{97BB}\x{97BC}' .
          '\x{97BD}\x{97BF}\x{97C1}\x{97C2}\x{97C3}\x{97C4}\x{97C5}\x{97C6}\x{97C7}' .
          '\x{97C8}\x{97C9}\x{97CA}\x{97CB}\x{97CC}\x{97CD}\x{97CE}\x{97CF}\x{97D0}' .
          '\x{97D1}\x{97D3}\x{97D4}\x{97D5}\x{97D6}\x{97D7}\x{97D8}\x{97D9}\x{97DA}' .
          '\x{97DB}\x{97DC}\x{97DD}\x{97DE}\x{97DF}\x{97E0}\x{97E1}\x{97E2}\x{97E3}' .
          '\x{97E4}\x{97E5}\x{97E6}\x{97E7}\x{97E8}\x{97E9}\x{97EA}\x{97EB}\x{97EC}' .
          '\x{97ED}\x{97EE}\x{97EF}\x{97F0}\x{97F1}\x{97F2}\x{97F3}\x{97F4}\x{97F5}' .
          '\x{97F6}\x{97F7}\x{97F8}\x{97F9}\x{97FA}\x{97FB}\x{97FD}\x{97FE}\x{97FF}' .
          '\x{9800}\x{9801}\x{9802}\x{9803}\x{9804}\x{9805}\x{9806}\x{9807}\x{9808}' .
          '\x{9809}\x{980A}\x{980B}\x{980C}\x{980D}\x{980E}\x{980F}\x{9810}\x{9811}' .
          '\x{9812}\x{9813}\x{9814}\x{9815}\x{9816}\x{9817}\x{9818}\x{9819}\x{981A}' .
          '\x{981B}\x{981C}\x{981D}\x{981E}\x{9820}\x{9821}\x{9822}\x{9823}\x{9824}' .
          '\x{9826}\x{9827}\x{9828}\x{9829}\x{982B}\x{982D}\x{982E}\x{982F}\x{9830}' .
          '\x{9831}\x{9832}\x{9834}\x{9835}\x{9836}\x{9837}\x{9838}\x{9839}\x{983B}' .
          '\x{983C}\x{983D}\x{983F}\x{9840}\x{9841}\x{9843}\x{9844}\x{9845}\x{9846}' .
          '\x{9848}\x{9849}\x{984A}\x{984C}\x{984D}\x{984E}\x{984F}\x{9850}\x{9851}' .
          '\x{9852}\x{9853}\x{9854}\x{9855}\x{9857}\x{9858}\x{9859}\x{985A}\x{985B}' .
          '\x{985C}\x{985D}\x{985E}\x{985F}\x{9860}\x{9861}\x{9862}\x{9863}\x{9864}' .
          '\x{9865}\x{9867}\x{9869}\x{986A}\x{986B}\x{986C}\x{986D}\x{986E}\x{986F}' .
          '\x{9870}\x{9871}\x{9872}\x{9873}\x{9874}\x{9875}\x{9876}\x{9877}\x{9878}' .
          '\x{9879}\x{987A}\x{987B}\x{987C}\x{987D}\x{987E}\x{987F}\x{9880}\x{9881}' .
          '\x{9882}\x{9883}\x{9884}\x{9885}\x{9886}\x{9887}\x{9888}\x{9889}\x{988A}' .
          '\x{988B}\x{988C}\x{988D}\x{988E}\x{988F}\x{9890}\x{9891}\x{9892}\x{9893}' .
          '\x{9894}\x{9895}\x{9896}\x{9897}\x{9898}\x{9899}\x{989A}\x{989B}\x{989C}' .
          '\x{989D}\x{989E}\x{989F}\x{98A0}\x{98A1}\x{98A2}\x{98A3}\x{98A4}\x{98A5}' .
          '\x{98A6}\x{98A7}\x{98A8}\x{98A9}\x{98AA}\x{98AB}\x{98AC}\x{98AD}\x{98AE}' .
          '\x{98AF}\x{98B0}\x{98B1}\x{98B2}\x{98B3}\x{98B4}\x{98B5}\x{98B6}\x{98B8}' .
          '\x{98B9}\x{98BA}\x{98BB}\x{98BC}\x{98BD}\x{98BE}\x{98BF}\x{98C0}\x{98C1}' .
          '\x{98C2}\x{98C3}\x{98C4}\x{98C5}\x{98C6}\x{98C8}\x{98C9}\x{98CB}\x{98CC}' .
          '\x{98CD}\x{98CE}\x{98CF}\x{98D0}\x{98D1}\x{98D2}\x{98D3}\x{98D4}\x{98D5}' .
          '\x{98D6}\x{98D7}\x{98D8}\x{98D9}\x{98DA}\x{98DB}\x{98DC}\x{98DD}\x{98DE}' .
          '\x{98DF}\x{98E0}\x{98E2}\x{98E3}\x{98E5}\x{98E6}\x{98E7}\x{98E8}\x{98E9}' .
          '\x{98EA}\x{98EB}\x{98ED}\x{98EF}\x{98F0}\x{98F2}\x{98F3}\x{98F4}\x{98F5}' .
          '\x{98F6}\x{98F7}\x{98F9}\x{98FA}\x{98FC}\x{98FD}\x{98FE}\x{98FF}\x{9900}' .
          '\x{9901}\x{9902}\x{9903}\x{9904}\x{9905}\x{9906}\x{9907}\x{9908}\x{9909}' .
          '\x{990A}\x{990B}\x{990C}\x{990D}\x{990E}\x{990F}\x{9910}\x{9911}\x{9912}' .
          '\x{9913}\x{9914}\x{9915}\x{9916}\x{9917}\x{9918}\x{991A}\x{991B}\x{991C}' .
          '\x{991D}\x{991E}\x{991F}\x{9920}\x{9921}\x{9922}\x{9923}\x{9924}\x{9925}' .
          '\x{9926}\x{9927}\x{9928}\x{9929}\x{992A}\x{992B}\x{992C}\x{992D}\x{992E}' .
          '\x{992F}\x{9930}\x{9931}\x{9932}\x{9933}\x{9934}\x{9935}\x{9936}\x{9937}' .
          '\x{9938}\x{9939}\x{993A}\x{993C}\x{993D}\x{993E}\x{993F}\x{9940}\x{9941}' .
          '\x{9942}\x{9943}\x{9945}\x{9946}\x{9947}\x{9948}\x{9949}\x{994A}\x{994B}' .
          '\x{994C}\x{994E}\x{994F}\x{9950}\x{9951}\x{9952}\x{9953}\x{9954}\x{9955}' .
          '\x{9956}\x{9957}\x{9958}\x{9959}\x{995B}\x{995C}\x{995E}\x{995F}\x{9960}' .
          '\x{9961}\x{9962}\x{9963}\x{9964}\x{9965}\x{9966}\x{9967}\x{9968}\x{9969}' .
          '\x{996A}\x{996B}\x{996C}\x{996D}\x{996E}\x{996F}\x{9970}\x{9971}\x{9972}' .
          '\x{9973}\x{9974}\x{9975}\x{9976}\x{9977}\x{9978}\x{9979}\x{997A}\x{997B}' .
          '\x{997C}\x{997D}\x{997E}\x{997F}\x{9980}\x{9981}\x{9982}\x{9983}\x{9984}' .
          '\x{9985}\x{9986}\x{9987}\x{9988}\x{9989}\x{998A}\x{998B}\x{998C}\x{998D}' .
          '\x{998E}\x{998F}\x{9990}\x{9991}\x{9992}\x{9993}\x{9994}\x{9995}\x{9996}' .
          '\x{9997}\x{9998}\x{9999}\x{999A}\x{999B}\x{999C}\x{999D}\x{999E}\x{999F}' .
          '\x{99A0}\x{99A1}\x{99A2}\x{99A3}\x{99A4}\x{99A5}\x{99A6}\x{99A7}\x{99A8}' .
          '\x{99A9}\x{99AA}\x{99AB}\x{99AC}\x{99AD}\x{99AE}\x{99AF}\x{99B0}\x{99B1}' .
          '\x{99B2}\x{99B3}\x{99B4}\x{99B5}\x{99B6}\x{99B7}\x{99B8}\x{99B9}\x{99BA}' .
          '\x{99BB}\x{99BC}\x{99BD}\x{99BE}\x{99C0}\x{99C1}\x{99C2}\x{99C3}\x{99C4}' .
          '\x{99C6}\x{99C7}\x{99C8}\x{99C9}\x{99CA}\x{99CB}\x{99CC}\x{99CD}\x{99CE}' .
          '\x{99CF}\x{99D0}\x{99D1}\x{99D2}\x{99D3}\x{99D4}\x{99D5}\x{99D6}\x{99D7}' .
          '\x{99D8}\x{99D9}\x{99DA}\x{99DB}\x{99DC}\x{99DD}\x{99DE}\x{99DF}\x{99E1}' .
          '\x{99E2}\x{99E3}\x{99E4}\x{99E5}\x{99E7}\x{99E8}\x{99E9}\x{99EA}\x{99EC}' .
          '\x{99ED}\x{99EE}\x{99EF}\x{99F0}\x{99F1}\x{99F2}\x{99F3}\x{99F4}\x{99F6}' .
          '\x{99F7}\x{99F8}\x{99F9}\x{99FA}\x{99FB}\x{99FC}\x{99FD}\x{99FE}\x{99FF}' .
          '\x{9A00}\x{9A01}\x{9A02}\x{9A03}\x{9A04}\x{9A05}\x{9A06}\x{9A07}\x{9A08}' .
          '\x{9A09}\x{9A0A}\x{9A0B}\x{9A0C}\x{9A0D}\x{9A0E}\x{9A0F}\x{9A11}\x{9A14}' .
          '\x{9A15}\x{9A16}\x{9A19}\x{9A1A}\x{9A1B}\x{9A1C}\x{9A1D}\x{9A1E}\x{9A1F}' .
          '\x{9A20}\x{9A21}\x{9A22}\x{9A23}\x{9A24}\x{9A25}\x{9A26}\x{9A27}\x{9A29}' .
          '\x{9A2A}\x{9A2B}\x{9A2C}\x{9A2D}\x{9A2E}\x{9A2F}\x{9A30}\x{9A31}\x{9A32}' .
          '\x{9A33}\x{9A34}\x{9A35}\x{9A36}\x{9A37}\x{9A38}\x{9A39}\x{9A3A}\x{9A3C}' .
          '\x{9A3D}\x{9A3E}\x{9A3F}\x{9A40}\x{9A41}\x{9A42}\x{9A43}\x{9A44}\x{9A45}' .
          '\x{9A46}\x{9A47}\x{9A48}\x{9A49}\x{9A4A}\x{9A4B}\x{9A4C}\x{9A4D}\x{9A4E}' .
          '\x{9A4F}\x{9A50}\x{9A52}\x{9A53}\x{9A54}\x{9A55}\x{9A56}\x{9A57}\x{9A59}' .
          '\x{9A5A}\x{9A5B}\x{9A5C}\x{9A5E}\x{9A5F}\x{9A60}\x{9A61}\x{9A62}\x{9A64}' .
          '\x{9A65}\x{9A66}\x{9A67}\x{9A68}\x{9A69}\x{9A6A}\x{9A6B}\x{9A6C}\x{9A6D}' .
          '\x{9A6E}\x{9A6F}\x{9A70}\x{9A71}\x{9A72}\x{9A73}\x{9A74}\x{9A75}\x{9A76}' .
          '\x{9A77}\x{9A78}\x{9A79}\x{9A7A}\x{9A7B}\x{9A7C}\x{9A7D}\x{9A7E}\x{9A7F}' .
          '\x{9A80}\x{9A81}\x{9A82}\x{9A83}\x{9A84}\x{9A85}\x{9A86}\x{9A87}\x{9A88}' .
          '\x{9A89}\x{9A8A}\x{9A8B}\x{9A8C}\x{9A8D}\x{9A8E}\x{9A8F}\x{9A90}\x{9A91}' .
          '\x{9A92}\x{9A93}\x{9A94}\x{9A95}\x{9A96}\x{9A97}\x{9A98}\x{9A99}\x{9A9A}' .
          '\x{9A9B}\x{9A9C}\x{9A9D}\x{9A9E}\x{9A9F}\x{9AA0}\x{9AA1}\x{9AA2}\x{9AA3}' .
          '\x{9AA4}\x{9AA5}\x{9AA6}\x{9AA7}\x{9AA8}\x{9AAA}\x{9AAB}\x{9AAC}\x{9AAD}' .
          '\x{9AAE}\x{9AAF}\x{9AB0}\x{9AB1}\x{9AB2}\x{9AB3}\x{9AB4}\x{9AB5}\x{9AB6}' .
          '\x{9AB7}\x{9AB8}\x{9AB9}\x{9ABA}\x{9ABB}\x{9ABC}\x{9ABE}\x{9ABF}\x{9AC0}' .
          '\x{9AC1}\x{9AC2}\x{9AC3}\x{9AC4}\x{9AC5}\x{9AC6}\x{9AC7}\x{9AC9}\x{9ACA}' .
          '\x{9ACB}\x{9ACC}\x{9ACD}\x{9ACE}\x{9ACF}\x{9AD0}\x{9AD1}\x{9AD2}\x{9AD3}' .
          '\x{9AD4}\x{9AD5}\x{9AD6}\x{9AD8}\x{9AD9}\x{9ADA}\x{9ADB}\x{9ADC}\x{9ADD}' .
          '\x{9ADE}\x{9ADF}\x{9AE1}\x{9AE2}\x{9AE3}\x{9AE5}\x{9AE6}\x{9AE7}\x{9AEA}' .
          '\x{9AEB}\x{9AEC}\x{9AED}\x{9AEE}\x{9AEF}\x{9AF1}\x{9AF2}\x{9AF3}\x{9AF4}' .
          '\x{9AF5}\x{9AF6}\x{9AF7}\x{9AF8}\x{9AF9}\x{9AFA}\x{9AFB}\x{9AFC}\x{9AFD}' .
          '\x{9AFE}\x{9AFF}\x{9B01}\x{9B03}\x{9B04}\x{9B05}\x{9B06}\x{9B07}\x{9B08}' .
          '\x{9B0A}\x{9B0B}\x{9B0C}\x{9B0D}\x{9B0E}\x{9B0F}\x{9B10}\x{9B11}\x{9B12}' .
          '\x{9B13}\x{9B15}\x{9B16}\x{9B17}\x{9B18}\x{9B19}\x{9B1A}\x{9B1C}\x{9B1D}' .
          '\x{9B1E}\x{9B1F}\x{9B20}\x{9B21}\x{9B22}\x{9B23}\x{9B24}\x{9B25}\x{9B26}' .
          '\x{9B27}\x{9B28}\x{9B29}\x{9B2A}\x{9B2B}\x{9B2C}\x{9B2D}\x{9B2E}\x{9B2F}' .
          '\x{9B30}\x{9B31}\x{9B32}\x{9B33}\x{9B35}\x{9B36}\x{9B37}\x{9B38}\x{9B39}' .
          '\x{9B3A}\x{9B3B}\x{9B3C}\x{9B3E}\x{9B3F}\x{9B41}\x{9B42}\x{9B43}\x{9B44}' .
          '\x{9B45}\x{9B46}\x{9B47}\x{9B48}\x{9B49}\x{9B4A}\x{9B4B}\x{9B4C}\x{9B4D}' .
          '\x{9B4E}\x{9B4F}\x{9B51}\x{9B52}\x{9B53}\x{9B54}\x{9B55}\x{9B56}\x{9B58}' .
          '\x{9B59}\x{9B5A}\x{9B5B}\x{9B5C}\x{9B5D}\x{9B5E}\x{9B5F}\x{9B60}\x{9B61}' .
          '\x{9B63}\x{9B64}\x{9B65}\x{9B66}\x{9B67}\x{9B68}\x{9B69}\x{9B6A}\x{9B6B}' .
          '\x{9B6C}\x{9B6D}\x{9B6E}\x{9B6F}\x{9B70}\x{9B71}\x{9B73}\x{9B74}\x{9B75}' .
          '\x{9B76}\x{9B77}\x{9B78}\x{9B79}\x{9B7A}\x{9B7B}\x{9B7C}\x{9B7D}\x{9B7E}' .
          '\x{9B7F}\x{9B80}\x{9B81}\x{9B82}\x{9B83}\x{9B84}\x{9B85}\x{9B86}\x{9B87}' .
          '\x{9B88}\x{9B8A}\x{9B8B}\x{9B8D}\x{9B8E}\x{9B8F}\x{9B90}\x{9B91}\x{9B92}' .
          '\x{9B93}\x{9B94}\x{9B95}\x{9B96}\x{9B97}\x{9B98}\x{9B9A}\x{9B9B}\x{9B9C}' .
          '\x{9B9D}\x{9B9E}\x{9B9F}\x{9BA0}\x{9BA1}\x{9BA2}\x{9BA3}\x{9BA4}\x{9BA5}' .
          '\x{9BA6}\x{9BA7}\x{9BA8}\x{9BA9}\x{9BAA}\x{9BAB}\x{9BAC}\x{9BAD}\x{9BAE}' .
          '\x{9BAF}\x{9BB0}\x{9BB1}\x{9BB2}\x{9BB3}\x{9BB4}\x{9BB5}\x{9BB6}\x{9BB7}' .
          '\x{9BB8}\x{9BB9}\x{9BBA}\x{9BBB}\x{9BBC}\x{9BBD}\x{9BBE}\x{9BBF}\x{9BC0}' .
          '\x{9BC1}\x{9BC3}\x{9BC4}\x{9BC5}\x{9BC6}\x{9BC7}\x{9BC8}\x{9BC9}\x{9BCA}' .
          '\x{9BCB}\x{9BCC}\x{9BCD}\x{9BCE}\x{9BCF}\x{9BD0}\x{9BD1}\x{9BD2}\x{9BD3}' .
          '\x{9BD4}\x{9BD5}\x{9BD6}\x{9BD7}\x{9BD8}\x{9BD9}\x{9BDA}\x{9BDB}\x{9BDC}' .
          '\x{9BDD}\x{9BDE}\x{9BDF}\x{9BE0}\x{9BE1}\x{9BE2}\x{9BE3}\x{9BE4}\x{9BE5}' .
          '\x{9BE6}\x{9BE7}\x{9BE8}\x{9BE9}\x{9BEA}\x{9BEB}\x{9BEC}\x{9BED}\x{9BEE}' .
          '\x{9BEF}\x{9BF0}\x{9BF1}\x{9BF2}\x{9BF3}\x{9BF4}\x{9BF5}\x{9BF7}\x{9BF8}' .
          '\x{9BF9}\x{9BFA}\x{9BFB}\x{9BFC}\x{9BFD}\x{9BFE}\x{9BFF}\x{9C02}\x{9C05}' .
          '\x{9C06}\x{9C07}\x{9C08}\x{9C09}\x{9C0A}\x{9C0B}\x{9C0C}\x{9C0D}\x{9C0E}' .
          '\x{9C0F}\x{9C10}\x{9C11}\x{9C12}\x{9C13}\x{9C14}\x{9C15}\x{9C16}\x{9C17}' .
          '\x{9C18}\x{9C19}\x{9C1A}\x{9C1B}\x{9C1C}\x{9C1D}\x{9C1E}\x{9C1F}\x{9C20}' .
          '\x{9C21}\x{9C22}\x{9C23}\x{9C24}\x{9C25}\x{9C26}\x{9C27}\x{9C28}\x{9C29}' .
          '\x{9C2A}\x{9C2B}\x{9C2C}\x{9C2D}\x{9C2F}\x{9C30}\x{9C31}\x{9C32}\x{9C33}' .
          '\x{9C34}\x{9C35}\x{9C36}\x{9C37}\x{9C38}\x{9C39}\x{9C3A}\x{9C3B}\x{9C3C}' .
          '\x{9C3D}\x{9C3E}\x{9C3F}\x{9C40}\x{9C41}\x{9C43}\x{9C44}\x{9C45}\x{9C46}' .
          '\x{9C47}\x{9C48}\x{9C49}\x{9C4A}\x{9C4B}\x{9C4C}\x{9C4D}\x{9C4E}\x{9C50}' .
          '\x{9C52}\x{9C53}\x{9C54}\x{9C55}\x{9C56}\x{9C57}\x{9C58}\x{9C59}\x{9C5A}' .
          '\x{9C5B}\x{9C5C}\x{9C5D}\x{9C5E}\x{9C5F}\x{9C60}\x{9C62}\x{9C63}\x{9C65}' .
          '\x{9C66}\x{9C67}\x{9C68}\x{9C69}\x{9C6A}\x{9C6B}\x{9C6C}\x{9C6D}\x{9C6E}' .
          '\x{9C6F}\x{9C70}\x{9C71}\x{9C72}\x{9C73}\x{9C74}\x{9C75}\x{9C77}\x{9C78}' .
          '\x{9C79}\x{9C7A}\x{9C7C}\x{9C7D}\x{9C7E}\x{9C7F}\x{9C80}\x{9C81}\x{9C82}' .
          '\x{9C83}\x{9C84}\x{9C85}\x{9C86}\x{9C87}\x{9C88}\x{9C89}\x{9C8A}\x{9C8B}' .
          '\x{9C8C}\x{9C8D}\x{9C8E}\x{9C8F}\x{9C90}\x{9C91}\x{9C92}\x{9C93}\x{9C94}' .
          '\x{9C95}\x{9C96}\x{9C97}\x{9C98}\x{9C99}\x{9C9A}\x{9C9B}\x{9C9C}\x{9C9D}' .
          '\x{9C9E}\x{9C9F}\x{9CA0}\x{9CA1}\x{9CA2}\x{9CA3}\x{9CA4}\x{9CA5}\x{9CA6}' .
          '\x{9CA7}\x{9CA8}\x{9CA9}\x{9CAA}\x{9CAB}\x{9CAC}\x{9CAD}\x{9CAE}\x{9CAF}' .
          '\x{9CB0}\x{9CB1}\x{9CB2}\x{9CB3}\x{9CB4}\x{9CB5}\x{9CB6}\x{9CB7}\x{9CB8}' .
          '\x{9CB9}\x{9CBA}\x{9CBB}\x{9CBC}\x{9CBD}\x{9CBE}\x{9CBF}\x{9CC0}\x{9CC1}' .
          '\x{9CC2}\x{9CC3}\x{9CC4}\x{9CC5}\x{9CC6}\x{9CC7}\x{9CC8}\x{9CC9}\x{9CCA}' .
          '\x{9CCB}\x{9CCC}\x{9CCD}\x{9CCE}\x{9CCF}\x{9CD0}\x{9CD1}\x{9CD2}\x{9CD3}' .
          '\x{9CD4}\x{9CD5}\x{9CD6}\x{9CD7}\x{9CD8}\x{9CD9}\x{9CDA}\x{9CDB}\x{9CDC}' .
          '\x{9CDD}\x{9CDE}\x{9CDF}\x{9CE0}\x{9CE1}\x{9CE2}\x{9CE3}\x{9CE4}\x{9CE5}' .
          '\x{9CE6}\x{9CE7}\x{9CE8}\x{9CE9}\x{9CEA}\x{9CEB}\x{9CEC}\x{9CED}\x{9CEE}' .
          '\x{9CEF}\x{9CF0}\x{9CF1}\x{9CF2}\x{9CF3}\x{9CF4}\x{9CF5}\x{9CF6}\x{9CF7}' .
          '\x{9CF8}\x{9CF9}\x{9CFA}\x{9CFB}\x{9CFC}\x{9CFD}\x{9CFE}\x{9CFF}\x{9D00}' .
          '\x{9D01}\x{9D02}\x{9D03}\x{9D04}\x{9D05}\x{9D06}\x{9D07}\x{9D08}\x{9D09}' .
          '\x{9D0A}\x{9D0B}\x{9D0F}\x{9D10}\x{9D12}\x{9D13}\x{9D14}\x{9D15}\x{9D16}' .
          '\x{9D17}\x{9D18}\x{9D19}\x{9D1A}\x{9D1B}\x{9D1C}\x{9D1D}\x{9D1E}\x{9D1F}' .
          '\x{9D20}\x{9D21}\x{9D22}\x{9D23}\x{9D24}\x{9D25}\x{9D26}\x{9D28}\x{9D29}' .
          '\x{9D2B}\x{9D2D}\x{9D2E}\x{9D2F}\x{9D30}\x{9D31}\x{9D32}\x{9D33}\x{9D34}' .
          '\x{9D36}\x{9D37}\x{9D38}\x{9D39}\x{9D3A}\x{9D3B}\x{9D3D}\x{9D3E}\x{9D3F}' .
          '\x{9D40}\x{9D41}\x{9D42}\x{9D43}\x{9D45}\x{9D46}\x{9D47}\x{9D48}\x{9D49}' .
          '\x{9D4A}\x{9D4B}\x{9D4C}\x{9D4D}\x{9D4E}\x{9D4F}\x{9D50}\x{9D51}\x{9D52}' .
          '\x{9D53}\x{9D54}\x{9D55}\x{9D56}\x{9D57}\x{9D58}\x{9D59}\x{9D5A}\x{9D5B}' .
          '\x{9D5C}\x{9D5D}\x{9D5E}\x{9D5F}\x{9D60}\x{9D61}\x{9D62}\x{9D63}\x{9D64}' .
          '\x{9D65}\x{9D66}\x{9D67}\x{9D68}\x{9D69}\x{9D6A}\x{9D6B}\x{9D6C}\x{9D6E}' .
          '\x{9D6F}\x{9D70}\x{9D71}\x{9D72}\x{9D73}\x{9D74}\x{9D75}\x{9D76}\x{9D77}' .
          '\x{9D78}\x{9D79}\x{9D7A}\x{9D7B}\x{9D7C}\x{9D7D}\x{9D7E}\x{9D7F}\x{9D80}' .
          '\x{9D81}\x{9D82}\x{9D83}\x{9D84}\x{9D85}\x{9D86}\x{9D87}\x{9D88}\x{9D89}' .
          '\x{9D8A}\x{9D8B}\x{9D8C}\x{9D8D}\x{9D8E}\x{9D90}\x{9D91}\x{9D92}\x{9D93}' .
          '\x{9D94}\x{9D96}\x{9D97}\x{9D98}\x{9D99}\x{9D9A}\x{9D9B}\x{9D9C}\x{9D9D}' .
          '\x{9D9E}\x{9D9F}\x{9DA0}\x{9DA1}\x{9DA2}\x{9DA3}\x{9DA4}\x{9DA5}\x{9DA6}' .
          '\x{9DA7}\x{9DA8}\x{9DA9}\x{9DAA}\x{9DAB}\x{9DAC}\x{9DAD}\x{9DAF}\x{9DB0}' .
          '\x{9DB1}\x{9DB2}\x{9DB3}\x{9DB4}\x{9DB5}\x{9DB6}\x{9DB7}\x{9DB8}\x{9DB9}' .
          '\x{9DBA}\x{9DBB}\x{9DBC}\x{9DBE}\x{9DBF}\x{9DC1}\x{9DC2}\x{9DC3}\x{9DC4}' .
          '\x{9DC5}\x{9DC7}\x{9DC8}\x{9DC9}\x{9DCA}\x{9DCB}\x{9DCC}\x{9DCD}\x{9DCE}' .
          '\x{9DCF}\x{9DD0}\x{9DD1}\x{9DD2}\x{9DD3}\x{9DD4}\x{9DD5}\x{9DD6}\x{9DD7}' .
          '\x{9DD8}\x{9DD9}\x{9DDA}\x{9DDB}\x{9DDC}\x{9DDD}\x{9DDE}\x{9DDF}\x{9DE0}' .
          '\x{9DE1}\x{9DE2}\x{9DE3}\x{9DE4}\x{9DE5}\x{9DE6}\x{9DE7}\x{9DE8}\x{9DE9}' .
          '\x{9DEB}\x{9DEC}\x{9DED}\x{9DEE}\x{9DEF}\x{9DF0}\x{9DF1}\x{9DF2}\x{9DF3}' .
          '\x{9DF4}\x{9DF5}\x{9DF6}\x{9DF7}\x{9DF8}\x{9DF9}\x{9DFA}\x{9DFB}\x{9DFD}' .
          '\x{9DFE}\x{9DFF}\x{9E00}\x{9E01}\x{9E02}\x{9E03}\x{9E04}\x{9E05}\x{9E06}' .
          '\x{9E07}\x{9E08}\x{9E09}\x{9E0A}\x{9E0B}\x{9E0C}\x{9E0D}\x{9E0F}\x{9E10}' .
          '\x{9E11}\x{9E12}\x{9E13}\x{9E14}\x{9E15}\x{9E17}\x{9E18}\x{9E19}\x{9E1A}' .
          '\x{9E1B}\x{9E1D}\x{9E1E}\x{9E1F}\x{9E20}\x{9E21}\x{9E22}\x{9E23}\x{9E24}' .
          '\x{9E25}\x{9E26}\x{9E27}\x{9E28}\x{9E29}\x{9E2A}\x{9E2B}\x{9E2C}\x{9E2D}' .
          '\x{9E2E}\x{9E2F}\x{9E30}\x{9E31}\x{9E32}\x{9E33}\x{9E34}\x{9E35}\x{9E36}' .
          '\x{9E37}\x{9E38}\x{9E39}\x{9E3A}\x{9E3B}\x{9E3C}\x{9E3D}\x{9E3E}\x{9E3F}' .
          '\x{9E40}\x{9E41}\x{9E42}\x{9E43}\x{9E44}\x{9E45}\x{9E46}\x{9E47}\x{9E48}' .
          '\x{9E49}\x{9E4A}\x{9E4B}\x{9E4C}\x{9E4D}\x{9E4E}\x{9E4F}\x{9E50}\x{9E51}' .
          '\x{9E52}\x{9E53}\x{9E54}\x{9E55}\x{9E56}\x{9E57}\x{9E58}\x{9E59}\x{9E5A}' .
          '\x{9E5B}\x{9E5C}\x{9E5D}\x{9E5E}\x{9E5F}\x{9E60}\x{9E61}\x{9E62}\x{9E63}' .
          '\x{9E64}\x{9E65}\x{9E66}\x{9E67}\x{9E68}\x{9E69}\x{9E6A}\x{9E6B}\x{9E6C}' .
          '\x{9E6D}\x{9E6E}\x{9E6F}\x{9E70}\x{9E71}\x{9E72}\x{9E73}\x{9E74}\x{9E75}' .
          '\x{9E76}\x{9E77}\x{9E79}\x{9E7A}\x{9E7C}\x{9E7D}\x{9E7E}\x{9E7F}\x{9E80}' .
          '\x{9E81}\x{9E82}\x{9E83}\x{9E84}\x{9E85}\x{9E86}\x{9E87}\x{9E88}\x{9E89}' .
          '\x{9E8A}\x{9E8B}\x{9E8C}\x{9E8D}\x{9E8E}\x{9E91}\x{9E92}\x{9E93}\x{9E94}' .
          '\x{9E96}\x{9E97}\x{9E99}\x{9E9A}\x{9E9B}\x{9E9C}\x{9E9D}\x{9E9F}\x{9EA0}' .
          '\x{9EA1}\x{9EA3}\x{9EA4}\x{9EA5}\x{9EA6}\x{9EA7}\x{9EA8}\x{9EA9}\x{9EAA}' .
          '\x{9EAD}\x{9EAE}\x{9EAF}\x{9EB0}\x{9EB2}\x{9EB3}\x{9EB4}\x{9EB5}\x{9EB6}' .
          '\x{9EB7}\x{9EB8}\x{9EBB}\x{9EBC}\x{9EBD}\x{9EBE}\x{9EBF}\x{9EC0}\x{9EC1}' .
          '\x{9EC2}\x{9EC3}\x{9EC4}\x{9EC5}\x{9EC6}\x{9EC7}\x{9EC8}\x{9EC9}\x{9ECA}' .
          '\x{9ECB}\x{9ECC}\x{9ECD}\x{9ECE}\x{9ECF}\x{9ED0}\x{9ED1}\x{9ED2}\x{9ED3}' .
          '\x{9ED4}\x{9ED5}\x{9ED6}\x{9ED7}\x{9ED8}\x{9ED9}\x{9EDA}\x{9EDB}\x{9EDC}' .
          '\x{9EDD}\x{9EDE}\x{9EDF}\x{9EE0}\x{9EE1}\x{9EE2}\x{9EE3}\x{9EE4}\x{9EE5}' .
          '\x{9EE6}\x{9EE7}\x{9EE8}\x{9EE9}\x{9EEA}\x{9EEB}\x{9EED}\x{9EEE}\x{9EEF}' .
          '\x{9EF0}\x{9EF2}\x{9EF3}\x{9EF4}\x{9EF5}\x{9EF6}\x{9EF7}\x{9EF8}\x{9EF9}' .
          '\x{9EFA}\x{9EFB}\x{9EFC}\x{9EFD}\x{9EFE}\x{9EFF}\x{9F00}\x{9F01}\x{9F02}' .
          '\x{9F04}\x{9F05}\x{9F06}\x{9F07}\x{9F08}\x{9F09}\x{9F0A}\x{9F0B}\x{9F0C}' .
          '\x{9F0D}\x{9F0E}\x{9F0F}\x{9F10}\x{9F12}\x{9F13}\x{9F15}\x{9F16}\x{9F17}' .
          '\x{9F18}\x{9F19}\x{9F1A}\x{9F1B}\x{9F1C}\x{9F1D}\x{9F1E}\x{9F1F}\x{9F20}' .
          '\x{9F22}\x{9F23}\x{9F24}\x{9F25}\x{9F27}\x{9F28}\x{9F29}\x{9F2A}\x{9F2B}' .
          '\x{9F2C}\x{9F2D}\x{9F2E}\x{9F2F}\x{9F30}\x{9F31}\x{9F32}\x{9F33}\x{9F34}' .
          '\x{9F35}\x{9F36}\x{9F37}\x{9F38}\x{9F39}\x{9F3A}\x{9F3B}\x{9F3C}\x{9F3D}' .
          '\x{9F3E}\x{9F3F}\x{9F40}\x{9F41}\x{9F42}\x{9F43}\x{9F44}\x{9F46}\x{9F47}' .
          '\x{9F48}\x{9F49}\x{9F4A}\x{9F4B}\x{9F4C}\x{9F4D}\x{9F4E}\x{9F4F}\x{9F50}' .
          '\x{9F51}\x{9F52}\x{9F54}\x{9F55}\x{9F56}\x{9F57}\x{9F58}\x{9F59}\x{9F5A}' .
          '\x{9F5B}\x{9F5C}\x{9F5D}\x{9F5E}\x{9F5F}\x{9F60}\x{9F61}\x{9F63}\x{9F64}' .
          '\x{9F65}\x{9F66}\x{9F67}\x{9F68}\x{9F69}\x{9F6A}\x{9F6B}\x{9F6C}\x{9F6E}' .
          '\x{9F6F}\x{9F70}\x{9F71}\x{9F72}\x{9F73}\x{9F74}\x{9F75}\x{9F76}\x{9F77}' .
          '\x{9F78}\x{9F79}\x{9F7A}\x{9F7B}\x{9F7C}\x{9F7D}\x{9F7E}\x{9F7F}\x{9F80}' .
          '\x{9F81}\x{9F82}\x{9F83}\x{9F84}\x{9F85}\x{9F86}\x{9F87}\x{9F88}\x{9F89}' .
          '\x{9F8A}\x{9F8B}\x{9F8C}\x{9F8D}\x{9F8E}\x{9F8F}\x{9F90}\x{9F91}\x{9F92}' .
          '\x{9F93}\x{9F94}\x{9F95}\x{9F96}\x{9F97}\x{9F98}\x{9F99}\x{9F9A}\x{9F9B}' .
          '\x{9F9C}\x{9F9D}\x{9F9E}\x{9F9F}\x{9FA0}\x{9FA2}\x{9FA4}\x{9FA5}]{1,20}$/iu',
];
laminas-validator/src/Hostname/Jp.php000064400000171056147361032560013623 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-validator for the canonical source repository
 * @copyright https://github.com/laminas/laminas-validator/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-validator/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Validator\Hostname;

/**
 * Resource file for japanese idn validation
 */
return [
    1  => '/^[\x{002d}0-9a-z\x{3005}-\x{3007}\x{3041}-\x{3093}\x{309D}\x{309E}' .
          '\x{30A1}-\x{30F6}\x{30FC}' .
          '\x{30FD}\x{30FE}\x{4E00}\x{4E01}\x{4E03}\x{4E07}\x{4E08}\x{4E09}\x{4E0A}' .
          '\x{4E0B}\x{4E0D}\x{4E0E}\x{4E10}\x{4E11}\x{4E14}\x{4E15}\x{4E16}\x{4E17}' .
          '\x{4E18}\x{4E19}\x{4E1E}\x{4E21}\x{4E26}\x{4E2A}\x{4E2D}\x{4E31}\x{4E32}' .
          '\x{4E36}\x{4E38}\x{4E39}\x{4E3B}\x{4E3C}\x{4E3F}\x{4E42}\x{4E43}\x{4E45}' .
          '\x{4E4B}\x{4E4D}\x{4E4E}\x{4E4F}\x{4E55}\x{4E56}\x{4E57}\x{4E58}\x{4E59}' .
          '\x{4E5D}\x{4E5E}\x{4E5F}\x{4E62}\x{4E71}\x{4E73}\x{4E7E}\x{4E80}\x{4E82}' .
          '\x{4E85}\x{4E86}\x{4E88}\x{4E89}\x{4E8A}\x{4E8B}\x{4E8C}\x{4E8E}\x{4E91}' .
          '\x{4E92}\x{4E94}\x{4E95}\x{4E98}\x{4E99}\x{4E9B}\x{4E9C}\x{4E9E}\x{4E9F}' .
          '\x{4EA0}\x{4EA1}\x{4EA2}\x{4EA4}\x{4EA5}\x{4EA6}\x{4EA8}\x{4EAB}\x{4EAC}' .
          '\x{4EAD}\x{4EAE}\x{4EB0}\x{4EB3}\x{4EB6}\x{4EBA}\x{4EC0}\x{4EC1}\x{4EC2}' .
          '\x{4EC4}\x{4EC6}\x{4EC7}\x{4ECA}\x{4ECB}\x{4ECD}\x{4ECE}\x{4ECF}\x{4ED4}' .
          '\x{4ED5}\x{4ED6}\x{4ED7}\x{4ED8}\x{4ED9}\x{4EDD}\x{4EDE}\x{4EDF}\x{4EE3}' .
          '\x{4EE4}\x{4EE5}\x{4EED}\x{4EEE}\x{4EF0}\x{4EF2}\x{4EF6}\x{4EF7}\x{4EFB}' .
          '\x{4F01}\x{4F09}\x{4F0A}\x{4F0D}\x{4F0E}\x{4F0F}\x{4F10}\x{4F11}\x{4F1A}' .
          '\x{4F1C}\x{4F1D}\x{4F2F}\x{4F30}\x{4F34}\x{4F36}\x{4F38}\x{4F3A}\x{4F3C}' .
          '\x{4F3D}\x{4F43}\x{4F46}\x{4F47}\x{4F4D}\x{4F4E}\x{4F4F}\x{4F50}\x{4F51}' .
          '\x{4F53}\x{4F55}\x{4F57}\x{4F59}\x{4F5A}\x{4F5B}\x{4F5C}\x{4F5D}\x{4F5E}' .
          '\x{4F69}\x{4F6F}\x{4F70}\x{4F73}\x{4F75}\x{4F76}\x{4F7B}\x{4F7C}\x{4F7F}' .
          '\x{4F83}\x{4F86}\x{4F88}\x{4F8B}\x{4F8D}\x{4F8F}\x{4F91}\x{4F96}\x{4F98}' .
          '\x{4F9B}\x{4F9D}\x{4FA0}\x{4FA1}\x{4FAB}\x{4FAD}\x{4FAE}\x{4FAF}\x{4FB5}' .
          '\x{4FB6}\x{4FBF}\x{4FC2}\x{4FC3}\x{4FC4}\x{4FCA}\x{4FCE}\x{4FD0}\x{4FD1}' .
          '\x{4FD4}\x{4FD7}\x{4FD8}\x{4FDA}\x{4FDB}\x{4FDD}\x{4FDF}\x{4FE1}\x{4FE3}' .
          '\x{4FE4}\x{4FE5}\x{4FEE}\x{4FEF}\x{4FF3}\x{4FF5}\x{4FF6}\x{4FF8}\x{4FFA}' .
          '\x{4FFE}\x{5005}\x{5006}\x{5009}\x{500B}\x{500D}\x{500F}\x{5011}\x{5012}' .
          '\x{5014}\x{5016}\x{5019}\x{501A}\x{501F}\x{5021}\x{5023}\x{5024}\x{5025}' .
          '\x{5026}\x{5028}\x{5029}\x{502A}\x{502B}\x{502C}\x{502D}\x{5036}\x{5039}' .
          '\x{5043}\x{5047}\x{5048}\x{5049}\x{504F}\x{5050}\x{5055}\x{5056}\x{505A}' .
          '\x{505C}\x{5065}\x{506C}\x{5072}\x{5074}\x{5075}\x{5076}\x{5078}\x{507D}' .
          '\x{5080}\x{5085}\x{508D}\x{5091}\x{5098}\x{5099}\x{509A}\x{50AC}\x{50AD}' .
          '\x{50B2}\x{50B3}\x{50B4}\x{50B5}\x{50B7}\x{50BE}\x{50C2}\x{50C5}\x{50C9}' .
          '\x{50CA}\x{50CD}\x{50CF}\x{50D1}\x{50D5}\x{50D6}\x{50DA}\x{50DE}\x{50E3}' .
          '\x{50E5}\x{50E7}\x{50ED}\x{50EE}\x{50F5}\x{50F9}\x{50FB}\x{5100}\x{5101}' .
          '\x{5102}\x{5104}\x{5109}\x{5112}\x{5114}\x{5115}\x{5116}\x{5118}\x{511A}' .
          '\x{511F}\x{5121}\x{512A}\x{5132}\x{5137}\x{513A}\x{513B}\x{513C}\x{513F}' .
          '\x{5140}\x{5141}\x{5143}\x{5144}\x{5145}\x{5146}\x{5147}\x{5148}\x{5149}' .
          '\x{514B}\x{514C}\x{514D}\x{514E}\x{5150}\x{5152}\x{5154}\x{515A}\x{515C}' .
          '\x{5162}\x{5165}\x{5168}\x{5169}\x{516A}\x{516B}\x{516C}\x{516D}\x{516E}' .
          '\x{5171}\x{5175}\x{5176}\x{5177}\x{5178}\x{517C}\x{5180}\x{5182}\x{5185}' .
          '\x{5186}\x{5189}\x{518A}\x{518C}\x{518D}\x{518F}\x{5190}\x{5191}\x{5192}' .
          '\x{5193}\x{5195}\x{5196}\x{5197}\x{5199}\x{51A0}\x{51A2}\x{51A4}\x{51A5}' .
          '\x{51A6}\x{51A8}\x{51A9}\x{51AA}\x{51AB}\x{51AC}\x{51B0}\x{51B1}\x{51B2}' .
          '\x{51B3}\x{51B4}\x{51B5}\x{51B6}\x{51B7}\x{51BD}\x{51C4}\x{51C5}\x{51C6}' .
          '\x{51C9}\x{51CB}\x{51CC}\x{51CD}\x{51D6}\x{51DB}\x{51DC}\x{51DD}\x{51E0}' .
          '\x{51E1}\x{51E6}\x{51E7}\x{51E9}\x{51EA}\x{51ED}\x{51F0}\x{51F1}\x{51F5}' .
          '\x{51F6}\x{51F8}\x{51F9}\x{51FA}\x{51FD}\x{51FE}\x{5200}\x{5203}\x{5204}' .
          '\x{5206}\x{5207}\x{5208}\x{520A}\x{520B}\x{520E}\x{5211}\x{5214}\x{5217}' .
          '\x{521D}\x{5224}\x{5225}\x{5227}\x{5229}\x{522A}\x{522E}\x{5230}\x{5233}' .
          '\x{5236}\x{5237}\x{5238}\x{5239}\x{523A}\x{523B}\x{5243}\x{5244}\x{5247}' .
          '\x{524A}\x{524B}\x{524C}\x{524D}\x{524F}\x{5254}\x{5256}\x{525B}\x{525E}' .
          '\x{5263}\x{5264}\x{5265}\x{5269}\x{526A}\x{526F}\x{5270}\x{5271}\x{5272}' .
          '\x{5273}\x{5274}\x{5275}\x{527D}\x{527F}\x{5283}\x{5287}\x{5288}\x{5289}' .
          '\x{528D}\x{5291}\x{5292}\x{5294}\x{529B}\x{529F}\x{52A0}\x{52A3}\x{52A9}' .
          '\x{52AA}\x{52AB}\x{52AC}\x{52AD}\x{52B1}\x{52B4}\x{52B5}\x{52B9}\x{52BC}' .
          '\x{52BE}\x{52C1}\x{52C3}\x{52C5}\x{52C7}\x{52C9}\x{52CD}\x{52D2}\x{52D5}' .
          '\x{52D7}\x{52D8}\x{52D9}\x{52DD}\x{52DE}\x{52DF}\x{52E0}\x{52E2}\x{52E3}' .
          '\x{52E4}\x{52E6}\x{52E7}\x{52F2}\x{52F3}\x{52F5}\x{52F8}\x{52F9}\x{52FA}' .
          '\x{52FE}\x{52FF}\x{5301}\x{5302}\x{5305}\x{5306}\x{5308}\x{530D}\x{530F}' .
          '\x{5310}\x{5315}\x{5316}\x{5317}\x{5319}\x{531A}\x{531D}\x{5320}\x{5321}' .
          '\x{5323}\x{532A}\x{532F}\x{5331}\x{5333}\x{5338}\x{5339}\x{533A}\x{533B}' .
          '\x{533F}\x{5340}\x{5341}\x{5343}\x{5345}\x{5346}\x{5347}\x{5348}\x{5349}' .
          '\x{534A}\x{534D}\x{5351}\x{5352}\x{5353}\x{5354}\x{5357}\x{5358}\x{535A}' .
          '\x{535C}\x{535E}\x{5360}\x{5366}\x{5369}\x{536E}\x{536F}\x{5370}\x{5371}' .
          '\x{5373}\x{5374}\x{5375}\x{5377}\x{5378}\x{537B}\x{537F}\x{5382}\x{5384}' .
          '\x{5396}\x{5398}\x{539A}\x{539F}\x{53A0}\x{53A5}\x{53A6}\x{53A8}\x{53A9}' .
          '\x{53AD}\x{53AE}\x{53B0}\x{53B3}\x{53B6}\x{53BB}\x{53C2}\x{53C3}\x{53C8}' .
          '\x{53C9}\x{53CA}\x{53CB}\x{53CC}\x{53CD}\x{53CE}\x{53D4}\x{53D6}\x{53D7}' .
          '\x{53D9}\x{53DB}\x{53DF}\x{53E1}\x{53E2}\x{53E3}\x{53E4}\x{53E5}\x{53E8}' .
          '\x{53E9}\x{53EA}\x{53EB}\x{53EC}\x{53ED}\x{53EE}\x{53EF}\x{53F0}\x{53F1}' .
          '\x{53F2}\x{53F3}\x{53F6}\x{53F7}\x{53F8}\x{53FA}\x{5401}\x{5403}\x{5404}' .
          '\x{5408}\x{5409}\x{540A}\x{540B}\x{540C}\x{540D}\x{540E}\x{540F}\x{5410}' .
          '\x{5411}\x{541B}\x{541D}\x{541F}\x{5420}\x{5426}\x{5429}\x{542B}\x{542C}' .
          '\x{542D}\x{542E}\x{5436}\x{5438}\x{5439}\x{543B}\x{543C}\x{543D}\x{543E}' .
          '\x{5440}\x{5442}\x{5446}\x{5448}\x{5449}\x{544A}\x{544E}\x{5451}\x{545F}' .
          '\x{5468}\x{546A}\x{5470}\x{5471}\x{5473}\x{5475}\x{5476}\x{5477}\x{547B}' .
          '\x{547C}\x{547D}\x{5480}\x{5484}\x{5486}\x{548B}\x{548C}\x{548E}\x{548F}' .
          '\x{5490}\x{5492}\x{54A2}\x{54A4}\x{54A5}\x{54A8}\x{54AB}\x{54AC}\x{54AF}' .
          '\x{54B2}\x{54B3}\x{54B8}\x{54BC}\x{54BD}\x{54BE}\x{54C0}\x{54C1}\x{54C2}' .
          '\x{54C4}\x{54C7}\x{54C8}\x{54C9}\x{54D8}\x{54E1}\x{54E2}\x{54E5}\x{54E6}' .
          '\x{54E8}\x{54E9}\x{54ED}\x{54EE}\x{54F2}\x{54FA}\x{54FD}\x{5504}\x{5506}' .
          '\x{5507}\x{550F}\x{5510}\x{5514}\x{5516}\x{552E}\x{552F}\x{5531}\x{5533}' .
          '\x{5538}\x{5539}\x{553E}\x{5540}\x{5544}\x{5545}\x{5546}\x{554C}\x{554F}' .
          '\x{5553}\x{5556}\x{5557}\x{555C}\x{555D}\x{5563}\x{557B}\x{557C}\x{557E}' .
          '\x{5580}\x{5583}\x{5584}\x{5587}\x{5589}\x{558A}\x{558B}\x{5598}\x{5599}' .
          '\x{559A}\x{559C}\x{559D}\x{559E}\x{559F}\x{55A7}\x{55A8}\x{55A9}\x{55AA}' .
          '\x{55AB}\x{55AC}\x{55AE}\x{55B0}\x{55B6}\x{55C4}\x{55C5}\x{55C7}\x{55D4}' .
          '\x{55DA}\x{55DC}\x{55DF}\x{55E3}\x{55E4}\x{55F7}\x{55F9}\x{55FD}\x{55FE}' .
          '\x{5606}\x{5609}\x{5614}\x{5616}\x{5617}\x{5618}\x{561B}\x{5629}\x{562F}' .
          '\x{5631}\x{5632}\x{5634}\x{5636}\x{5638}\x{5642}\x{564C}\x{564E}\x{5650}' .
          '\x{565B}\x{5664}\x{5668}\x{566A}\x{566B}\x{566C}\x{5674}\x{5678}\x{567A}' .
          '\x{5680}\x{5686}\x{5687}\x{568A}\x{568F}\x{5694}\x{56A0}\x{56A2}\x{56A5}' .
          '\x{56AE}\x{56B4}\x{56B6}\x{56BC}\x{56C0}\x{56C1}\x{56C2}\x{56C3}\x{56C8}' .
          '\x{56CE}\x{56D1}\x{56D3}\x{56D7}\x{56D8}\x{56DA}\x{56DB}\x{56DE}\x{56E0}' .
          '\x{56E3}\x{56EE}\x{56F0}\x{56F2}\x{56F3}\x{56F9}\x{56FA}\x{56FD}\x{56FF}' .
          '\x{5700}\x{5703}\x{5704}\x{5708}\x{5709}\x{570B}\x{570D}\x{570F}\x{5712}' .
          '\x{5713}\x{5716}\x{5718}\x{571C}\x{571F}\x{5726}\x{5727}\x{5728}\x{572D}' .
          '\x{5730}\x{5737}\x{5738}\x{573B}\x{5740}\x{5742}\x{5747}\x{574A}\x{574E}' .
          '\x{574F}\x{5750}\x{5751}\x{5761}\x{5764}\x{5766}\x{5769}\x{576A}\x{577F}' .
          '\x{5782}\x{5788}\x{5789}\x{578B}\x{5793}\x{57A0}\x{57A2}\x{57A3}\x{57A4}' .
          '\x{57AA}\x{57B0}\x{57B3}\x{57C0}\x{57C3}\x{57C6}\x{57CB}\x{57CE}\x{57D2}' .
          '\x{57D3}\x{57D4}\x{57D6}\x{57DC}\x{57DF}\x{57E0}\x{57E3}\x{57F4}\x{57F7}' .
          '\x{57F9}\x{57FA}\x{57FC}\x{5800}\x{5802}\x{5805}\x{5806}\x{580A}\x{580B}' .
          '\x{5815}\x{5819}\x{581D}\x{5821}\x{5824}\x{582A}\x{582F}\x{5830}\x{5831}' .
          '\x{5834}\x{5835}\x{583A}\x{583D}\x{5840}\x{5841}\x{584A}\x{584B}\x{5851}' .
          '\x{5852}\x{5854}\x{5857}\x{5858}\x{5859}\x{585A}\x{585E}\x{5862}\x{5869}' .
          '\x{586B}\x{5870}\x{5872}\x{5875}\x{5879}\x{587E}\x{5883}\x{5885}\x{5893}' .
          '\x{5897}\x{589C}\x{589F}\x{58A8}\x{58AB}\x{58AE}\x{58B3}\x{58B8}\x{58B9}' .
          '\x{58BA}\x{58BB}\x{58BE}\x{58C1}\x{58C5}\x{58C7}\x{58CA}\x{58CC}\x{58D1}' .
          '\x{58D3}\x{58D5}\x{58D7}\x{58D8}\x{58D9}\x{58DC}\x{58DE}\x{58DF}\x{58E4}' .
          '\x{58E5}\x{58EB}\x{58EC}\x{58EE}\x{58EF}\x{58F0}\x{58F1}\x{58F2}\x{58F7}' .
          '\x{58F9}\x{58FA}\x{58FB}\x{58FC}\x{58FD}\x{5902}\x{5909}\x{590A}\x{590F}' .
          '\x{5910}\x{5915}\x{5916}\x{5918}\x{5919}\x{591A}\x{591B}\x{591C}\x{5922}' .
          '\x{5925}\x{5927}\x{5929}\x{592A}\x{592B}\x{592C}\x{592D}\x{592E}\x{5931}' .
          '\x{5932}\x{5937}\x{5938}\x{593E}\x{5944}\x{5947}\x{5948}\x{5949}\x{594E}' .
          '\x{594F}\x{5950}\x{5951}\x{5954}\x{5955}\x{5957}\x{5958}\x{595A}\x{5960}' .
          '\x{5962}\x{5965}\x{5967}\x{5968}\x{5969}\x{596A}\x{596C}\x{596E}\x{5973}' .
          '\x{5974}\x{5978}\x{597D}\x{5981}\x{5982}\x{5983}\x{5984}\x{598A}\x{598D}' .
          '\x{5993}\x{5996}\x{5999}\x{599B}\x{599D}\x{59A3}\x{59A5}\x{59A8}\x{59AC}' .
          '\x{59B2}\x{59B9}\x{59BB}\x{59BE}\x{59C6}\x{59C9}\x{59CB}\x{59D0}\x{59D1}' .
          '\x{59D3}\x{59D4}\x{59D9}\x{59DA}\x{59DC}\x{59E5}\x{59E6}\x{59E8}\x{59EA}' .
          '\x{59EB}\x{59F6}\x{59FB}\x{59FF}\x{5A01}\x{5A03}\x{5A09}\x{5A11}\x{5A18}' .
          '\x{5A1A}\x{5A1C}\x{5A1F}\x{5A20}\x{5A25}\x{5A29}\x{5A2F}\x{5A35}\x{5A36}' .
          '\x{5A3C}\x{5A40}\x{5A41}\x{5A46}\x{5A49}\x{5A5A}\x{5A62}\x{5A66}\x{5A6A}' .
          '\x{5A6C}\x{5A7F}\x{5A92}\x{5A9A}\x{5A9B}\x{5ABC}\x{5ABD}\x{5ABE}\x{5AC1}' .
          '\x{5AC2}\x{5AC9}\x{5ACB}\x{5ACC}\x{5AD0}\x{5AD6}\x{5AD7}\x{5AE1}\x{5AE3}' .
          '\x{5AE6}\x{5AE9}\x{5AFA}\x{5AFB}\x{5B09}\x{5B0B}\x{5B0C}\x{5B16}\x{5B22}' .
          '\x{5B2A}\x{5B2C}\x{5B30}\x{5B32}\x{5B36}\x{5B3E}\x{5B40}\x{5B43}\x{5B45}' .
          '\x{5B50}\x{5B51}\x{5B54}\x{5B55}\x{5B57}\x{5B58}\x{5B5A}\x{5B5B}\x{5B5C}' .
          '\x{5B5D}\x{5B5F}\x{5B63}\x{5B64}\x{5B65}\x{5B66}\x{5B69}\x{5B6B}\x{5B70}' .
          '\x{5B71}\x{5B73}\x{5B75}\x{5B78}\x{5B7A}\x{5B80}\x{5B83}\x{5B85}\x{5B87}' .
          '\x{5B88}\x{5B89}\x{5B8B}\x{5B8C}\x{5B8D}\x{5B8F}\x{5B95}\x{5B97}\x{5B98}' .
          '\x{5B99}\x{5B9A}\x{5B9B}\x{5B9C}\x{5B9D}\x{5B9F}\x{5BA2}\x{5BA3}\x{5BA4}' .
          '\x{5BA5}\x{5BA6}\x{5BAE}\x{5BB0}\x{5BB3}\x{5BB4}\x{5BB5}\x{5BB6}\x{5BB8}' .
          '\x{5BB9}\x{5BBF}\x{5BC2}\x{5BC3}\x{5BC4}\x{5BC5}\x{5BC6}\x{5BC7}\x{5BC9}' .
          '\x{5BCC}\x{5BD0}\x{5BD2}\x{5BD3}\x{5BD4}\x{5BDB}\x{5BDD}\x{5BDE}\x{5BDF}' .
          '\x{5BE1}\x{5BE2}\x{5BE4}\x{5BE5}\x{5BE6}\x{5BE7}\x{5BE8}\x{5BE9}\x{5BEB}' .
          '\x{5BEE}\x{5BF0}\x{5BF3}\x{5BF5}\x{5BF6}\x{5BF8}\x{5BFA}\x{5BFE}\x{5BFF}' .
          '\x{5C01}\x{5C02}\x{5C04}\x{5C05}\x{5C06}\x{5C07}\x{5C08}\x{5C09}\x{5C0A}' .
          '\x{5C0B}\x{5C0D}\x{5C0E}\x{5C0F}\x{5C11}\x{5C13}\x{5C16}\x{5C1A}\x{5C20}' .
          '\x{5C22}\x{5C24}\x{5C28}\x{5C2D}\x{5C31}\x{5C38}\x{5C39}\x{5C3A}\x{5C3B}' .
          '\x{5C3C}\x{5C3D}\x{5C3E}\x{5C3F}\x{5C40}\x{5C41}\x{5C45}\x{5C46}\x{5C48}' .
          '\x{5C4A}\x{5C4B}\x{5C4D}\x{5C4E}\x{5C4F}\x{5C50}\x{5C51}\x{5C53}\x{5C55}' .
          '\x{5C5E}\x{5C60}\x{5C61}\x{5C64}\x{5C65}\x{5C6C}\x{5C6E}\x{5C6F}\x{5C71}' .
          '\x{5C76}\x{5C79}\x{5C8C}\x{5C90}\x{5C91}\x{5C94}\x{5CA1}\x{5CA8}\x{5CA9}' .
          '\x{5CAB}\x{5CAC}\x{5CB1}\x{5CB3}\x{5CB6}\x{5CB7}\x{5CB8}\x{5CBB}\x{5CBC}' .
          '\x{5CBE}\x{5CC5}\x{5CC7}\x{5CD9}\x{5CE0}\x{5CE1}\x{5CE8}\x{5CE9}\x{5CEA}' .
          '\x{5CED}\x{5CEF}\x{5CF0}\x{5CF6}\x{5CFA}\x{5CFB}\x{5CFD}\x{5D07}\x{5D0B}' .
          '\x{5D0E}\x{5D11}\x{5D14}\x{5D15}\x{5D16}\x{5D17}\x{5D18}\x{5D19}\x{5D1A}' .
          '\x{5D1B}\x{5D1F}\x{5D22}\x{5D29}\x{5D4B}\x{5D4C}\x{5D4E}\x{5D50}\x{5D52}' .
          '\x{5D5C}\x{5D69}\x{5D6C}\x{5D6F}\x{5D73}\x{5D76}\x{5D82}\x{5D84}\x{5D87}' .
          '\x{5D8B}\x{5D8C}\x{5D90}\x{5D9D}\x{5DA2}\x{5DAC}\x{5DAE}\x{5DB7}\x{5DBA}' .
          '\x{5DBC}\x{5DBD}\x{5DC9}\x{5DCC}\x{5DCD}\x{5DD2}\x{5DD3}\x{5DD6}\x{5DDB}' .
          '\x{5DDD}\x{5DDE}\x{5DE1}\x{5DE3}\x{5DE5}\x{5DE6}\x{5DE7}\x{5DE8}\x{5DEB}' .
          '\x{5DEE}\x{5DF1}\x{5DF2}\x{5DF3}\x{5DF4}\x{5DF5}\x{5DF7}\x{5DFB}\x{5DFD}' .
          '\x{5DFE}\x{5E02}\x{5E03}\x{5E06}\x{5E0B}\x{5E0C}\x{5E11}\x{5E16}\x{5E19}' .
          '\x{5E1A}\x{5E1B}\x{5E1D}\x{5E25}\x{5E2B}\x{5E2D}\x{5E2F}\x{5E30}\x{5E33}' .
          '\x{5E36}\x{5E37}\x{5E38}\x{5E3D}\x{5E40}\x{5E43}\x{5E44}\x{5E45}\x{5E47}' .
          '\x{5E4C}\x{5E4E}\x{5E54}\x{5E55}\x{5E57}\x{5E5F}\x{5E61}\x{5E62}\x{5E63}' .
          '\x{5E64}\x{5E72}\x{5E73}\x{5E74}\x{5E75}\x{5E76}\x{5E78}\x{5E79}\x{5E7A}' .
          '\x{5E7B}\x{5E7C}\x{5E7D}\x{5E7E}\x{5E7F}\x{5E81}\x{5E83}\x{5E84}\x{5E87}' .
          '\x{5E8A}\x{5E8F}\x{5E95}\x{5E96}\x{5E97}\x{5E9A}\x{5E9C}\x{5EA0}\x{5EA6}' .
          '\x{5EA7}\x{5EAB}\x{5EAD}\x{5EB5}\x{5EB6}\x{5EB7}\x{5EB8}\x{5EC1}\x{5EC2}' .
          '\x{5EC3}\x{5EC8}\x{5EC9}\x{5ECA}\x{5ECF}\x{5ED0}\x{5ED3}\x{5ED6}\x{5EDA}' .
          '\x{5EDB}\x{5EDD}\x{5EDF}\x{5EE0}\x{5EE1}\x{5EE2}\x{5EE3}\x{5EE8}\x{5EE9}' .
          '\x{5EEC}\x{5EF0}\x{5EF1}\x{5EF3}\x{5EF4}\x{5EF6}\x{5EF7}\x{5EF8}\x{5EFA}' .
          '\x{5EFB}\x{5EFC}\x{5EFE}\x{5EFF}\x{5F01}\x{5F03}\x{5F04}\x{5F09}\x{5F0A}' .
          '\x{5F0B}\x{5F0C}\x{5F0D}\x{5F0F}\x{5F10}\x{5F11}\x{5F13}\x{5F14}\x{5F15}' .
          '\x{5F16}\x{5F17}\x{5F18}\x{5F1B}\x{5F1F}\x{5F25}\x{5F26}\x{5F27}\x{5F29}' .
          '\x{5F2D}\x{5F2F}\x{5F31}\x{5F35}\x{5F37}\x{5F38}\x{5F3C}\x{5F3E}\x{5F41}' .
          '\x{5F48}\x{5F4A}\x{5F4C}\x{5F4E}\x{5F51}\x{5F53}\x{5F56}\x{5F57}\x{5F59}' .
          '\x{5F5C}\x{5F5D}\x{5F61}\x{5F62}\x{5F66}\x{5F69}\x{5F6A}\x{5F6B}\x{5F6C}' .
          '\x{5F6D}\x{5F70}\x{5F71}\x{5F73}\x{5F77}\x{5F79}\x{5F7C}\x{5F7F}\x{5F80}' .
          '\x{5F81}\x{5F82}\x{5F83}\x{5F84}\x{5F85}\x{5F87}\x{5F88}\x{5F8A}\x{5F8B}' .
          '\x{5F8C}\x{5F90}\x{5F91}\x{5F92}\x{5F93}\x{5F97}\x{5F98}\x{5F99}\x{5F9E}' .
          '\x{5FA0}\x{5FA1}\x{5FA8}\x{5FA9}\x{5FAA}\x{5FAD}\x{5FAE}\x{5FB3}\x{5FB4}' .
          '\x{5FB9}\x{5FBC}\x{5FBD}\x{5FC3}\x{5FC5}\x{5FCC}\x{5FCD}\x{5FD6}\x{5FD7}' .
          '\x{5FD8}\x{5FD9}\x{5FDC}\x{5FDD}\x{5FE0}\x{5FE4}\x{5FEB}\x{5FF0}\x{5FF1}' .
          '\x{5FF5}\x{5FF8}\x{5FFB}\x{5FFD}\x{5FFF}\x{600E}\x{600F}\x{6010}\x{6012}' .
          '\x{6015}\x{6016}\x{6019}\x{601B}\x{601C}\x{601D}\x{6020}\x{6021}\x{6025}' .
          '\x{6026}\x{6027}\x{6028}\x{6029}\x{602A}\x{602B}\x{602F}\x{6031}\x{603A}' .
          '\x{6041}\x{6042}\x{6043}\x{6046}\x{604A}\x{604B}\x{604D}\x{6050}\x{6052}' .
          '\x{6055}\x{6059}\x{605A}\x{605F}\x{6060}\x{6062}\x{6063}\x{6064}\x{6065}' .
          '\x{6068}\x{6069}\x{606A}\x{606B}\x{606C}\x{606D}\x{606F}\x{6070}\x{6075}' .
          '\x{6077}\x{6081}\x{6083}\x{6084}\x{6089}\x{608B}\x{608C}\x{608D}\x{6092}' .
          '\x{6094}\x{6096}\x{6097}\x{609A}\x{609B}\x{609F}\x{60A0}\x{60A3}\x{60A6}' .
          '\x{60A7}\x{60A9}\x{60AA}\x{60B2}\x{60B3}\x{60B4}\x{60B5}\x{60B6}\x{60B8}' .
          '\x{60BC}\x{60BD}\x{60C5}\x{60C6}\x{60C7}\x{60D1}\x{60D3}\x{60D8}\x{60DA}' .
          '\x{60DC}\x{60DF}\x{60E0}\x{60E1}\x{60E3}\x{60E7}\x{60E8}\x{60F0}\x{60F1}' .
          '\x{60F3}\x{60F4}\x{60F6}\x{60F7}\x{60F9}\x{60FA}\x{60FB}\x{6100}\x{6101}' .
          '\x{6103}\x{6106}\x{6108}\x{6109}\x{610D}\x{610E}\x{610F}\x{6115}\x{611A}' .
          '\x{611B}\x{611F}\x{6121}\x{6127}\x{6128}\x{612C}\x{6134}\x{613C}\x{613D}' .
          '\x{613E}\x{613F}\x{6142}\x{6144}\x{6147}\x{6148}\x{614A}\x{614B}\x{614C}' .
          '\x{614D}\x{614E}\x{6153}\x{6155}\x{6158}\x{6159}\x{615A}\x{615D}\x{615F}' .
          '\x{6162}\x{6163}\x{6165}\x{6167}\x{6168}\x{616B}\x{616E}\x{616F}\x{6170}' .
          '\x{6171}\x{6173}\x{6174}\x{6175}\x{6176}\x{6177}\x{617E}\x{6182}\x{6187}' .
          '\x{618A}\x{618E}\x{6190}\x{6191}\x{6194}\x{6196}\x{6199}\x{619A}\x{61A4}' .
          '\x{61A7}\x{61A9}\x{61AB}\x{61AC}\x{61AE}\x{61B2}\x{61B6}\x{61BA}\x{61BE}' .
          '\x{61C3}\x{61C6}\x{61C7}\x{61C8}\x{61C9}\x{61CA}\x{61CB}\x{61CC}\x{61CD}' .
          '\x{61D0}\x{61E3}\x{61E6}\x{61F2}\x{61F4}\x{61F6}\x{61F7}\x{61F8}\x{61FA}' .
          '\x{61FC}\x{61FD}\x{61FE}\x{61FF}\x{6200}\x{6208}\x{6209}\x{620A}\x{620C}' .
          '\x{620D}\x{620E}\x{6210}\x{6211}\x{6212}\x{6214}\x{6216}\x{621A}\x{621B}' .
          '\x{621D}\x{621E}\x{621F}\x{6221}\x{6226}\x{622A}\x{622E}\x{622F}\x{6230}' .
          '\x{6232}\x{6233}\x{6234}\x{6238}\x{623B}\x{623F}\x{6240}\x{6241}\x{6247}' .
          '\x{6248}\x{6249}\x{624B}\x{624D}\x{624E}\x{6253}\x{6255}\x{6258}\x{625B}' .
          '\x{625E}\x{6260}\x{6263}\x{6268}\x{626E}\x{6271}\x{6276}\x{6279}\x{627C}' .
          '\x{627E}\x{627F}\x{6280}\x{6282}\x{6283}\x{6284}\x{6289}\x{628A}\x{6291}' .
          '\x{6292}\x{6293}\x{6294}\x{6295}\x{6296}\x{6297}\x{6298}\x{629B}\x{629C}' .
          '\x{629E}\x{62AB}\x{62AC}\x{62B1}\x{62B5}\x{62B9}\x{62BB}\x{62BC}\x{62BD}' .
          '\x{62C2}\x{62C5}\x{62C6}\x{62C7}\x{62C8}\x{62C9}\x{62CA}\x{62CC}\x{62CD}' .
          '\x{62CF}\x{62D0}\x{62D1}\x{62D2}\x{62D3}\x{62D4}\x{62D7}\x{62D8}\x{62D9}' .
          '\x{62DB}\x{62DC}\x{62DD}\x{62E0}\x{62E1}\x{62EC}\x{62ED}\x{62EE}\x{62EF}' .
          '\x{62F1}\x{62F3}\x{62F5}\x{62F6}\x{62F7}\x{62FE}\x{62FF}\x{6301}\x{6302}' .
          '\x{6307}\x{6308}\x{6309}\x{630C}\x{6311}\x{6319}\x{631F}\x{6327}\x{6328}' .
          '\x{632B}\x{632F}\x{633A}\x{633D}\x{633E}\x{633F}\x{6349}\x{634C}\x{634D}' .
          '\x{634F}\x{6350}\x{6355}\x{6357}\x{635C}\x{6367}\x{6368}\x{6369}\x{636B}' .
          '\x{636E}\x{6372}\x{6376}\x{6377}\x{637A}\x{637B}\x{6380}\x{6383}\x{6388}' .
          '\x{6389}\x{638C}\x{638E}\x{638F}\x{6392}\x{6396}\x{6398}\x{639B}\x{639F}' .
          '\x{63A0}\x{63A1}\x{63A2}\x{63A3}\x{63A5}\x{63A7}\x{63A8}\x{63A9}\x{63AA}' .
          '\x{63AB}\x{63AC}\x{63B2}\x{63B4}\x{63B5}\x{63BB}\x{63BE}\x{63C0}\x{63C3}' .
          '\x{63C4}\x{63C6}\x{63C9}\x{63CF}\x{63D0}\x{63D2}\x{63D6}\x{63DA}\x{63DB}' .
          '\x{63E1}\x{63E3}\x{63E9}\x{63EE}\x{63F4}\x{63F6}\x{63FA}\x{6406}\x{640D}' .
          '\x{640F}\x{6413}\x{6416}\x{6417}\x{641C}\x{6426}\x{6428}\x{642C}\x{642D}' .
          '\x{6434}\x{6436}\x{643A}\x{643E}\x{6442}\x{644E}\x{6458}\x{6467}\x{6469}' .
          '\x{646F}\x{6476}\x{6478}\x{647A}\x{6483}\x{6488}\x{6492}\x{6493}\x{6495}' .
          '\x{649A}\x{649E}\x{64A4}\x{64A5}\x{64A9}\x{64AB}\x{64AD}\x{64AE}\x{64B0}' .
          '\x{64B2}\x{64B9}\x{64BB}\x{64BC}\x{64C1}\x{64C2}\x{64C5}\x{64C7}\x{64CD}' .
          '\x{64D2}\x{64D4}\x{64D8}\x{64DA}\x{64E0}\x{64E1}\x{64E2}\x{64E3}\x{64E6}' .
          '\x{64E7}\x{64EC}\x{64EF}\x{64F1}\x{64F2}\x{64F4}\x{64F6}\x{64FA}\x{64FD}' .
          '\x{64FE}\x{6500}\x{6505}\x{6518}\x{651C}\x{651D}\x{6523}\x{6524}\x{652A}' .
          '\x{652B}\x{652C}\x{652F}\x{6534}\x{6535}\x{6536}\x{6537}\x{6538}\x{6539}' .
          '\x{653B}\x{653E}\x{653F}\x{6545}\x{6548}\x{654D}\x{654F}\x{6551}\x{6555}' .
          '\x{6556}\x{6557}\x{6558}\x{6559}\x{655D}\x{655E}\x{6562}\x{6563}\x{6566}' .
          '\x{656C}\x{6570}\x{6572}\x{6574}\x{6575}\x{6577}\x{6578}\x{6582}\x{6583}' .
          '\x{6587}\x{6588}\x{6589}\x{658C}\x{658E}\x{6590}\x{6591}\x{6597}\x{6599}' .
          '\x{659B}\x{659C}\x{659F}\x{65A1}\x{65A4}\x{65A5}\x{65A7}\x{65AB}\x{65AC}' .
          '\x{65AD}\x{65AF}\x{65B0}\x{65B7}\x{65B9}\x{65BC}\x{65BD}\x{65C1}\x{65C3}' .
          '\x{65C4}\x{65C5}\x{65C6}\x{65CB}\x{65CC}\x{65CF}\x{65D2}\x{65D7}\x{65D9}' .
          '\x{65DB}\x{65E0}\x{65E1}\x{65E2}\x{65E5}\x{65E6}\x{65E7}\x{65E8}\x{65E9}' .
          '\x{65EC}\x{65ED}\x{65F1}\x{65FA}\x{65FB}\x{6602}\x{6603}\x{6606}\x{6607}' .
          '\x{660A}\x{660C}\x{660E}\x{660F}\x{6613}\x{6614}\x{661C}\x{661F}\x{6620}' .
          '\x{6625}\x{6627}\x{6628}\x{662D}\x{662F}\x{6634}\x{6635}\x{6636}\x{663C}' .
          '\x{663F}\x{6641}\x{6642}\x{6643}\x{6644}\x{6649}\x{664B}\x{664F}\x{6652}' .
          '\x{665D}\x{665E}\x{665F}\x{6662}\x{6664}\x{6666}\x{6667}\x{6668}\x{6669}' .
          '\x{666E}\x{666F}\x{6670}\x{6674}\x{6676}\x{667A}\x{6681}\x{6683}\x{6684}' .
          '\x{6687}\x{6688}\x{6689}\x{668E}\x{6691}\x{6696}\x{6697}\x{6698}\x{669D}' .
          '\x{66A2}\x{66A6}\x{66AB}\x{66AE}\x{66B4}\x{66B8}\x{66B9}\x{66BC}\x{66BE}' .
          '\x{66C1}\x{66C4}\x{66C7}\x{66C9}\x{66D6}\x{66D9}\x{66DA}\x{66DC}\x{66DD}' .
          '\x{66E0}\x{66E6}\x{66E9}\x{66F0}\x{66F2}\x{66F3}\x{66F4}\x{66F5}\x{66F7}' .
          '\x{66F8}\x{66F9}\x{66FC}\x{66FD}\x{66FE}\x{66FF}\x{6700}\x{6703}\x{6708}' .
          '\x{6709}\x{670B}\x{670D}\x{670F}\x{6714}\x{6715}\x{6716}\x{6717}\x{671B}' .
          '\x{671D}\x{671E}\x{671F}\x{6726}\x{6727}\x{6728}\x{672A}\x{672B}\x{672C}' .
          '\x{672D}\x{672E}\x{6731}\x{6734}\x{6736}\x{6737}\x{6738}\x{673A}\x{673D}' .
          '\x{673F}\x{6741}\x{6746}\x{6749}\x{674E}\x{674F}\x{6750}\x{6751}\x{6753}' .
          '\x{6756}\x{6759}\x{675C}\x{675E}\x{675F}\x{6760}\x{6761}\x{6762}\x{6763}' .
          '\x{6764}\x{6765}\x{676A}\x{676D}\x{676F}\x{6770}\x{6771}\x{6772}\x{6773}' .
          '\x{6775}\x{6777}\x{677C}\x{677E}\x{677F}\x{6785}\x{6787}\x{6789}\x{678B}' .
          '\x{678C}\x{6790}\x{6795}\x{6797}\x{679A}\x{679C}\x{679D}\x{67A0}\x{67A1}' .
          '\x{67A2}\x{67A6}\x{67A9}\x{67AF}\x{67B3}\x{67B4}\x{67B6}\x{67B7}\x{67B8}' .
          '\x{67B9}\x{67C1}\x{67C4}\x{67C6}\x{67CA}\x{67CE}\x{67CF}\x{67D0}\x{67D1}' .
          '\x{67D3}\x{67D4}\x{67D8}\x{67DA}\x{67DD}\x{67DE}\x{67E2}\x{67E4}\x{67E7}' .
          '\x{67E9}\x{67EC}\x{67EE}\x{67EF}\x{67F1}\x{67F3}\x{67F4}\x{67F5}\x{67FB}' .
          '\x{67FE}\x{67FF}\x{6802}\x{6803}\x{6804}\x{6813}\x{6816}\x{6817}\x{681E}' .
          '\x{6821}\x{6822}\x{6829}\x{682A}\x{682B}\x{6832}\x{6834}\x{6838}\x{6839}' .
          '\x{683C}\x{683D}\x{6840}\x{6841}\x{6842}\x{6843}\x{6846}\x{6848}\x{684D}' .
          '\x{684E}\x{6850}\x{6851}\x{6853}\x{6854}\x{6859}\x{685C}\x{685D}\x{685F}' .
          '\x{6863}\x{6867}\x{6874}\x{6876}\x{6877}\x{687E}\x{687F}\x{6881}\x{6883}' .
          '\x{6885}\x{688D}\x{688F}\x{6893}\x{6894}\x{6897}\x{689B}\x{689D}\x{689F}' .
          '\x{68A0}\x{68A2}\x{68A6}\x{68A7}\x{68A8}\x{68AD}\x{68AF}\x{68B0}\x{68B1}' .
          '\x{68B3}\x{68B5}\x{68B6}\x{68B9}\x{68BA}\x{68BC}\x{68C4}\x{68C6}\x{68C9}' .
          '\x{68CA}\x{68CB}\x{68CD}\x{68D2}\x{68D4}\x{68D5}\x{68D7}\x{68D8}\x{68DA}' .
          '\x{68DF}\x{68E0}\x{68E1}\x{68E3}\x{68E7}\x{68EE}\x{68EF}\x{68F2}\x{68F9}' .
          '\x{68FA}\x{6900}\x{6901}\x{6904}\x{6905}\x{6908}\x{690B}\x{690C}\x{690D}' .
          '\x{690E}\x{690F}\x{6912}\x{6919}\x{691A}\x{691B}\x{691C}\x{6921}\x{6922}' .
          '\x{6923}\x{6925}\x{6926}\x{6928}\x{692A}\x{6930}\x{6934}\x{6936}\x{6939}' .
          '\x{693D}\x{693F}\x{694A}\x{6953}\x{6954}\x{6955}\x{6959}\x{695A}\x{695C}' .
          '\x{695D}\x{695E}\x{6960}\x{6961}\x{6962}\x{696A}\x{696B}\x{696D}\x{696E}' .
          '\x{696F}\x{6973}\x{6974}\x{6975}\x{6977}\x{6978}\x{6979}\x{697C}\x{697D}' .
          '\x{697E}\x{6981}\x{6982}\x{698A}\x{698E}\x{6991}\x{6994}\x{6995}\x{699B}' .
          '\x{699C}\x{69A0}\x{69A7}\x{69AE}\x{69B1}\x{69B2}\x{69B4}\x{69BB}\x{69BE}' .
          '\x{69BF}\x{69C1}\x{69C3}\x{69C7}\x{69CA}\x{69CB}\x{69CC}\x{69CD}\x{69CE}' .
          '\x{69D0}\x{69D3}\x{69D8}\x{69D9}\x{69DD}\x{69DE}\x{69E7}\x{69E8}\x{69EB}' .
          '\x{69ED}\x{69F2}\x{69F9}\x{69FB}\x{69FD}\x{69FF}\x{6A02}\x{6A05}\x{6A0A}' .
          '\x{6A0B}\x{6A0C}\x{6A12}\x{6A13}\x{6A14}\x{6A17}\x{6A19}\x{6A1B}\x{6A1E}' .
          '\x{6A1F}\x{6A21}\x{6A22}\x{6A23}\x{6A29}\x{6A2A}\x{6A2B}\x{6A2E}\x{6A35}' .
          '\x{6A36}\x{6A38}\x{6A39}\x{6A3A}\x{6A3D}\x{6A44}\x{6A47}\x{6A48}\x{6A4B}' .
          '\x{6A58}\x{6A59}\x{6A5F}\x{6A61}\x{6A62}\x{6A66}\x{6A72}\x{6A78}\x{6A7F}' .
          '\x{6A80}\x{6A84}\x{6A8D}\x{6A8E}\x{6A90}\x{6A97}\x{6A9C}\x{6AA0}\x{6AA2}' .
          '\x{6AA3}\x{6AAA}\x{6AAC}\x{6AAE}\x{6AB3}\x{6AB8}\x{6ABB}\x{6AC1}\x{6AC2}' .
          '\x{6AC3}\x{6AD1}\x{6AD3}\x{6ADA}\x{6ADB}\x{6ADE}\x{6ADF}\x{6AE8}\x{6AEA}' .
          '\x{6AFA}\x{6AFB}\x{6B04}\x{6B05}\x{6B0A}\x{6B12}\x{6B16}\x{6B1D}\x{6B1F}' .
          '\x{6B20}\x{6B21}\x{6B23}\x{6B27}\x{6B32}\x{6B37}\x{6B38}\x{6B39}\x{6B3A}' .
          '\x{6B3D}\x{6B3E}\x{6B43}\x{6B47}\x{6B49}\x{6B4C}\x{6B4E}\x{6B50}\x{6B53}' .
          '\x{6B54}\x{6B59}\x{6B5B}\x{6B5F}\x{6B61}\x{6B62}\x{6B63}\x{6B64}\x{6B66}' .
          '\x{6B69}\x{6B6A}\x{6B6F}\x{6B73}\x{6B74}\x{6B78}\x{6B79}\x{6B7B}\x{6B7F}' .
          '\x{6B80}\x{6B83}\x{6B84}\x{6B86}\x{6B89}\x{6B8A}\x{6B8B}\x{6B8D}\x{6B95}' .
          '\x{6B96}\x{6B98}\x{6B9E}\x{6BA4}\x{6BAA}\x{6BAB}\x{6BAF}\x{6BB1}\x{6BB2}' .
          '\x{6BB3}\x{6BB4}\x{6BB5}\x{6BB7}\x{6BBA}\x{6BBB}\x{6BBC}\x{6BBF}\x{6BC0}' .
          '\x{6BC5}\x{6BC6}\x{6BCB}\x{6BCD}\x{6BCE}\x{6BD2}\x{6BD3}\x{6BD4}\x{6BD8}' .
          '\x{6BDB}\x{6BDF}\x{6BEB}\x{6BEC}\x{6BEF}\x{6BF3}\x{6C08}\x{6C0F}\x{6C11}' .
          '\x{6C13}\x{6C14}\x{6C17}\x{6C1B}\x{6C23}\x{6C24}\x{6C34}\x{6C37}\x{6C38}' .
          '\x{6C3E}\x{6C40}\x{6C41}\x{6C42}\x{6C4E}\x{6C50}\x{6C55}\x{6C57}\x{6C5A}' .
          '\x{6C5D}\x{6C5E}\x{6C5F}\x{6C60}\x{6C62}\x{6C68}\x{6C6A}\x{6C70}\x{6C72}' .
          '\x{6C73}\x{6C7A}\x{6C7D}\x{6C7E}\x{6C81}\x{6C82}\x{6C83}\x{6C88}\x{6C8C}' .
          '\x{6C8D}\x{6C90}\x{6C92}\x{6C93}\x{6C96}\x{6C99}\x{6C9A}\x{6C9B}\x{6CA1}' .
          '\x{6CA2}\x{6CAB}\x{6CAE}\x{6CB1}\x{6CB3}\x{6CB8}\x{6CB9}\x{6CBA}\x{6CBB}' .
          '\x{6CBC}\x{6CBD}\x{6CBE}\x{6CBF}\x{6CC1}\x{6CC4}\x{6CC5}\x{6CC9}\x{6CCA}' .
          '\x{6CCC}\x{6CD3}\x{6CD5}\x{6CD7}\x{6CD9}\x{6CDB}\x{6CDD}\x{6CE1}\x{6CE2}' .
          '\x{6CE3}\x{6CE5}\x{6CE8}\x{6CEA}\x{6CEF}\x{6CF0}\x{6CF1}\x{6CF3}\x{6D0B}' .
          '\x{6D0C}\x{6D12}\x{6D17}\x{6D19}\x{6D1B}\x{6D1E}\x{6D1F}\x{6D25}\x{6D29}' .
          '\x{6D2A}\x{6D2B}\x{6D32}\x{6D33}\x{6D35}\x{6D36}\x{6D38}\x{6D3B}\x{6D3D}' .
          '\x{6D3E}\x{6D41}\x{6D44}\x{6D45}\x{6D59}\x{6D5A}\x{6D5C}\x{6D63}\x{6D64}' .
          '\x{6D66}\x{6D69}\x{6D6A}\x{6D6C}\x{6D6E}\x{6D74}\x{6D77}\x{6D78}\x{6D79}' .
          '\x{6D85}\x{6D88}\x{6D8C}\x{6D8E}\x{6D93}\x{6D95}\x{6D99}\x{6D9B}\x{6D9C}' .
          '\x{6DAF}\x{6DB2}\x{6DB5}\x{6DB8}\x{6DBC}\x{6DC0}\x{6DC5}\x{6DC6}\x{6DC7}' .
          '\x{6DCB}\x{6DCC}\x{6DD1}\x{6DD2}\x{6DD5}\x{6DD8}\x{6DD9}\x{6DDE}\x{6DE1}' .
          '\x{6DE4}\x{6DE6}\x{6DE8}\x{6DEA}\x{6DEB}\x{6DEC}\x{6DEE}\x{6DF1}\x{6DF3}' .
          '\x{6DF5}\x{6DF7}\x{6DF9}\x{6DFA}\x{6DFB}\x{6E05}\x{6E07}\x{6E08}\x{6E09}' .
          '\x{6E0A}\x{6E0B}\x{6E13}\x{6E15}\x{6E19}\x{6E1A}\x{6E1B}\x{6E1D}\x{6E1F}' .
          '\x{6E20}\x{6E21}\x{6E23}\x{6E24}\x{6E25}\x{6E26}\x{6E29}\x{6E2B}\x{6E2C}' .
          '\x{6E2D}\x{6E2E}\x{6E2F}\x{6E38}\x{6E3A}\x{6E3E}\x{6E43}\x{6E4A}\x{6E4D}' .
          '\x{6E4E}\x{6E56}\x{6E58}\x{6E5B}\x{6E5F}\x{6E67}\x{6E6B}\x{6E6E}\x{6E6F}' .
          '\x{6E72}\x{6E76}\x{6E7E}\x{6E7F}\x{6E80}\x{6E82}\x{6E8C}\x{6E8F}\x{6E90}' .
          '\x{6E96}\x{6E98}\x{6E9C}\x{6E9D}\x{6E9F}\x{6EA2}\x{6EA5}\x{6EAA}\x{6EAF}' .
          '\x{6EB2}\x{6EB6}\x{6EB7}\x{6EBA}\x{6EBD}\x{6EC2}\x{6EC4}\x{6EC5}\x{6EC9}' .
          '\x{6ECB}\x{6ECC}\x{6ED1}\x{6ED3}\x{6ED4}\x{6ED5}\x{6EDD}\x{6EDE}\x{6EEC}' .
          '\x{6EEF}\x{6EF2}\x{6EF4}\x{6EF7}\x{6EF8}\x{6EFE}\x{6EFF}\x{6F01}\x{6F02}' .
          '\x{6F06}\x{6F09}\x{6F0F}\x{6F11}\x{6F13}\x{6F14}\x{6F15}\x{6F20}\x{6F22}' .
          '\x{6F23}\x{6F2B}\x{6F2C}\x{6F31}\x{6F32}\x{6F38}\x{6F3E}\x{6F3F}\x{6F41}' .
          '\x{6F45}\x{6F54}\x{6F58}\x{6F5B}\x{6F5C}\x{6F5F}\x{6F64}\x{6F66}\x{6F6D}' .
          '\x{6F6E}\x{6F6F}\x{6F70}\x{6F74}\x{6F78}\x{6F7A}\x{6F7C}\x{6F80}\x{6F81}' .
          '\x{6F82}\x{6F84}\x{6F86}\x{6F8E}\x{6F91}\x{6F97}\x{6FA1}\x{6FA3}\x{6FA4}' .
          '\x{6FAA}\x{6FB1}\x{6FB3}\x{6FB9}\x{6FC0}\x{6FC1}\x{6FC2}\x{6FC3}\x{6FC6}' .
          '\x{6FD4}\x{6FD5}\x{6FD8}\x{6FDB}\x{6FDF}\x{6FE0}\x{6FE1}\x{6FE4}\x{6FEB}' .
          '\x{6FEC}\x{6FEE}\x{6FEF}\x{6FF1}\x{6FF3}\x{6FF6}\x{6FFA}\x{6FFE}\x{7001}' .
          '\x{7009}\x{700B}\x{700F}\x{7011}\x{7015}\x{7018}\x{701A}\x{701B}\x{701D}' .
          '\x{701E}\x{701F}\x{7026}\x{7027}\x{702C}\x{7030}\x{7032}\x{703E}\x{704C}' .
          '\x{7051}\x{7058}\x{7063}\x{706B}\x{706F}\x{7070}\x{7078}\x{707C}\x{707D}' .
          '\x{7089}\x{708A}\x{708E}\x{7092}\x{7099}\x{70AC}\x{70AD}\x{70AE}\x{70AF}' .
          '\x{70B3}\x{70B8}\x{70B9}\x{70BA}\x{70C8}\x{70CB}\x{70CF}\x{70D9}\x{70DD}' .
          '\x{70DF}\x{70F1}\x{70F9}\x{70FD}\x{7109}\x{7114}\x{7119}\x{711A}\x{711C}' .
          '\x{7121}\x{7126}\x{7136}\x{713C}\x{7149}\x{714C}\x{714E}\x{7155}\x{7156}' .
          '\x{7159}\x{7162}\x{7164}\x{7165}\x{7166}\x{7167}\x{7169}\x{716C}\x{716E}' .
          '\x{717D}\x{7184}\x{7188}\x{718A}\x{718F}\x{7194}\x{7195}\x{7199}\x{719F}' .
          '\x{71A8}\x{71AC}\x{71B1}\x{71B9}\x{71BE}\x{71C3}\x{71C8}\x{71C9}\x{71CE}' .
          '\x{71D0}\x{71D2}\x{71D4}\x{71D5}\x{71D7}\x{71DF}\x{71E0}\x{71E5}\x{71E6}' .
          '\x{71E7}\x{71EC}\x{71ED}\x{71EE}\x{71F5}\x{71F9}\x{71FB}\x{71FC}\x{71FF}' .
          '\x{7206}\x{720D}\x{7210}\x{721B}\x{7228}\x{722A}\x{722C}\x{722D}\x{7230}' .
          '\x{7232}\x{7235}\x{7236}\x{723A}\x{723B}\x{723C}\x{723D}\x{723E}\x{723F}' .
          '\x{7240}\x{7246}\x{7247}\x{7248}\x{724B}\x{724C}\x{7252}\x{7258}\x{7259}' .
          '\x{725B}\x{725D}\x{725F}\x{7261}\x{7262}\x{7267}\x{7269}\x{7272}\x{7274}' .
          '\x{7279}\x{727D}\x{727E}\x{7280}\x{7281}\x{7282}\x{7287}\x{7292}\x{7296}' .
          '\x{72A0}\x{72A2}\x{72A7}\x{72AC}\x{72AF}\x{72B2}\x{72B6}\x{72B9}\x{72C2}' .
          '\x{72C3}\x{72C4}\x{72C6}\x{72CE}\x{72D0}\x{72D2}\x{72D7}\x{72D9}\x{72DB}' .
          '\x{72E0}\x{72E1}\x{72E2}\x{72E9}\x{72EC}\x{72ED}\x{72F7}\x{72F8}\x{72F9}' .
          '\x{72FC}\x{72FD}\x{730A}\x{7316}\x{7317}\x{731B}\x{731C}\x{731D}\x{731F}' .
          '\x{7325}\x{7329}\x{732A}\x{732B}\x{732E}\x{732F}\x{7334}\x{7336}\x{7337}' .
          '\x{733E}\x{733F}\x{7344}\x{7345}\x{734E}\x{734F}\x{7357}\x{7363}\x{7368}' .
          '\x{736A}\x{7370}\x{7372}\x{7375}\x{7378}\x{737A}\x{737B}\x{7384}\x{7387}' .
          '\x{7389}\x{738B}\x{7396}\x{73A9}\x{73B2}\x{73B3}\x{73BB}\x{73C0}\x{73C2}' .
          '\x{73C8}\x{73CA}\x{73CD}\x{73CE}\x{73DE}\x{73E0}\x{73E5}\x{73EA}\x{73ED}' .
          '\x{73EE}\x{73F1}\x{73F8}\x{73FE}\x{7403}\x{7405}\x{7406}\x{7409}\x{7422}' .
          '\x{7425}\x{7432}\x{7433}\x{7434}\x{7435}\x{7436}\x{743A}\x{743F}\x{7441}' .
          '\x{7455}\x{7459}\x{745A}\x{745B}\x{745C}\x{745E}\x{745F}\x{7460}\x{7463}' .
          '\x{7464}\x{7469}\x{746A}\x{746F}\x{7470}\x{7473}\x{7476}\x{747E}\x{7483}' .
          '\x{748B}\x{749E}\x{74A2}\x{74A7}\x{74B0}\x{74BD}\x{74CA}\x{74CF}\x{74D4}' .
          '\x{74DC}\x{74E0}\x{74E2}\x{74E3}\x{74E6}\x{74E7}\x{74E9}\x{74EE}\x{74F0}' .
          '\x{74F1}\x{74F2}\x{74F6}\x{74F7}\x{74F8}\x{7503}\x{7504}\x{7505}\x{750C}' .
          '\x{750D}\x{750E}\x{7511}\x{7513}\x{7515}\x{7518}\x{751A}\x{751C}\x{751E}' .
          '\x{751F}\x{7523}\x{7525}\x{7526}\x{7528}\x{752B}\x{752C}\x{7530}\x{7531}' .
          '\x{7532}\x{7533}\x{7537}\x{7538}\x{753A}\x{753B}\x{753C}\x{7544}\x{7546}' .
          '\x{7549}\x{754A}\x{754B}\x{754C}\x{754D}\x{754F}\x{7551}\x{7554}\x{7559}' .
          '\x{755A}\x{755B}\x{755C}\x{755D}\x{7560}\x{7562}\x{7564}\x{7565}\x{7566}' .
          '\x{7567}\x{7569}\x{756A}\x{756B}\x{756D}\x{7570}\x{7573}\x{7574}\x{7576}' .
          '\x{7577}\x{7578}\x{757F}\x{7582}\x{7586}\x{7587}\x{7589}\x{758A}\x{758B}' .
          '\x{758E}\x{758F}\x{7591}\x{7594}\x{759A}\x{759D}\x{75A3}\x{75A5}\x{75AB}' .
          '\x{75B1}\x{75B2}\x{75B3}\x{75B5}\x{75B8}\x{75B9}\x{75BC}\x{75BD}\x{75BE}' .
          '\x{75C2}\x{75C3}\x{75C5}\x{75C7}\x{75CA}\x{75CD}\x{75D2}\x{75D4}\x{75D5}' .
          '\x{75D8}\x{75D9}\x{75DB}\x{75DE}\x{75E2}\x{75E3}\x{75E9}\x{75F0}\x{75F2}' .
          '\x{75F3}\x{75F4}\x{75FA}\x{75FC}\x{75FE}\x{75FF}\x{7601}\x{7609}\x{760B}' .
          '\x{760D}\x{761F}\x{7620}\x{7621}\x{7622}\x{7624}\x{7627}\x{7630}\x{7634}' .
          '\x{763B}\x{7642}\x{7646}\x{7647}\x{7648}\x{764C}\x{7652}\x{7656}\x{7658}' .
          '\x{765C}\x{7661}\x{7662}\x{7667}\x{7668}\x{7669}\x{766A}\x{766C}\x{7670}' .
          '\x{7672}\x{7676}\x{7678}\x{767A}\x{767B}\x{767C}\x{767D}\x{767E}\x{7680}' .
          '\x{7683}\x{7684}\x{7686}\x{7687}\x{7688}\x{768B}\x{768E}\x{7690}\x{7693}' .
          '\x{7696}\x{7699}\x{769A}\x{76AE}\x{76B0}\x{76B4}\x{76B7}\x{76B8}\x{76B9}' .
          '\x{76BA}\x{76BF}\x{76C2}\x{76C3}\x{76C6}\x{76C8}\x{76CA}\x{76CD}\x{76D2}' .
          '\x{76D6}\x{76D7}\x{76DB}\x{76DC}\x{76DE}\x{76DF}\x{76E1}\x{76E3}\x{76E4}' .
          '\x{76E5}\x{76E7}\x{76EA}\x{76EE}\x{76F2}\x{76F4}\x{76F8}\x{76FB}\x{76FE}' .
          '\x{7701}\x{7704}\x{7707}\x{7708}\x{7709}\x{770B}\x{770C}\x{771B}\x{771E}' .
          '\x{771F}\x{7720}\x{7724}\x{7725}\x{7726}\x{7729}\x{7737}\x{7738}\x{773A}' .
          '\x{773C}\x{7740}\x{7747}\x{775A}\x{775B}\x{7761}\x{7763}\x{7765}\x{7766}' .
          '\x{7768}\x{776B}\x{7779}\x{777E}\x{777F}\x{778B}\x{778E}\x{7791}\x{779E}' .
          '\x{77A0}\x{77A5}\x{77AC}\x{77AD}\x{77B0}\x{77B3}\x{77B6}\x{77B9}\x{77BB}' .
          '\x{77BC}\x{77BD}\x{77BF}\x{77C7}\x{77CD}\x{77D7}\x{77DA}\x{77DB}\x{77DC}' .
          '\x{77E2}\x{77E3}\x{77E5}\x{77E7}\x{77E9}\x{77ED}\x{77EE}\x{77EF}\x{77F3}' .
          '\x{77FC}\x{7802}\x{780C}\x{7812}\x{7814}\x{7815}\x{7820}\x{7825}\x{7826}' .
          '\x{7827}\x{7832}\x{7834}\x{783A}\x{783F}\x{7845}\x{785D}\x{786B}\x{786C}' .
          '\x{786F}\x{7872}\x{7874}\x{787C}\x{7881}\x{7886}\x{7887}\x{788C}\x{788D}' .
          '\x{788E}\x{7891}\x{7893}\x{7895}\x{7897}\x{789A}\x{78A3}\x{78A7}\x{78A9}' .
          '\x{78AA}\x{78AF}\x{78B5}\x{78BA}\x{78BC}\x{78BE}\x{78C1}\x{78C5}\x{78C6}' .
          '\x{78CA}\x{78CB}\x{78D0}\x{78D1}\x{78D4}\x{78DA}\x{78E7}\x{78E8}\x{78EC}' .
          '\x{78EF}\x{78F4}\x{78FD}\x{7901}\x{7907}\x{790E}\x{7911}\x{7912}\x{7919}' .
          '\x{7926}\x{792A}\x{792B}\x{792C}\x{793A}\x{793C}\x{793E}\x{7940}\x{7941}' .
          '\x{7947}\x{7948}\x{7949}\x{7950}\x{7953}\x{7955}\x{7956}\x{7957}\x{795A}' .
          '\x{795D}\x{795E}\x{795F}\x{7960}\x{7962}\x{7965}\x{7968}\x{796D}\x{7977}' .
          '\x{797A}\x{797F}\x{7980}\x{7981}\x{7984}\x{7985}\x{798A}\x{798D}\x{798E}' .
          '\x{798F}\x{799D}\x{79A6}\x{79A7}\x{79AA}\x{79AE}\x{79B0}\x{79B3}\x{79B9}' .
          '\x{79BA}\x{79BD}\x{79BE}\x{79BF}\x{79C0}\x{79C1}\x{79C9}\x{79CB}\x{79D1}' .
          '\x{79D2}\x{79D5}\x{79D8}\x{79DF}\x{79E1}\x{79E3}\x{79E4}\x{79E6}\x{79E7}' .
          '\x{79E9}\x{79EC}\x{79F0}\x{79FB}\x{7A00}\x{7A08}\x{7A0B}\x{7A0D}\x{7A0E}' .
          '\x{7A14}\x{7A17}\x{7A18}\x{7A19}\x{7A1A}\x{7A1C}\x{7A1F}\x{7A20}\x{7A2E}' .
          '\x{7A31}\x{7A32}\x{7A37}\x{7A3B}\x{7A3C}\x{7A3D}\x{7A3E}\x{7A3F}\x{7A40}' .
          '\x{7A42}\x{7A43}\x{7A46}\x{7A49}\x{7A4D}\x{7A4E}\x{7A4F}\x{7A50}\x{7A57}' .
          '\x{7A61}\x{7A62}\x{7A63}\x{7A69}\x{7A6B}\x{7A70}\x{7A74}\x{7A76}\x{7A79}' .
          '\x{7A7A}\x{7A7D}\x{7A7F}\x{7A81}\x{7A83}\x{7A84}\x{7A88}\x{7A92}\x{7A93}' .
          '\x{7A95}\x{7A96}\x{7A97}\x{7A98}\x{7A9F}\x{7AA9}\x{7AAA}\x{7AAE}\x{7AAF}' .
          '\x{7AB0}\x{7AB6}\x{7ABA}\x{7ABF}\x{7AC3}\x{7AC4}\x{7AC5}\x{7AC7}\x{7AC8}' .
          '\x{7ACA}\x{7ACB}\x{7ACD}\x{7ACF}\x{7AD2}\x{7AD3}\x{7AD5}\x{7AD9}\x{7ADA}' .
          '\x{7ADC}\x{7ADD}\x{7ADF}\x{7AE0}\x{7AE1}\x{7AE2}\x{7AE3}\x{7AE5}\x{7AE6}' .
          '\x{7AEA}\x{7AED}\x{7AEF}\x{7AF0}\x{7AF6}\x{7AF8}\x{7AF9}\x{7AFA}\x{7AFF}' .
          '\x{7B02}\x{7B04}\x{7B06}\x{7B08}\x{7B0A}\x{7B0B}\x{7B0F}\x{7B11}\x{7B18}' .
          '\x{7B19}\x{7B1B}\x{7B1E}\x{7B20}\x{7B25}\x{7B26}\x{7B28}\x{7B2C}\x{7B33}' .
          '\x{7B35}\x{7B36}\x{7B39}\x{7B45}\x{7B46}\x{7B48}\x{7B49}\x{7B4B}\x{7B4C}' .
          '\x{7B4D}\x{7B4F}\x{7B50}\x{7B51}\x{7B52}\x{7B54}\x{7B56}\x{7B5D}\x{7B65}' .
          '\x{7B67}\x{7B6C}\x{7B6E}\x{7B70}\x{7B71}\x{7B74}\x{7B75}\x{7B7A}\x{7B86}' .
          '\x{7B87}\x{7B8B}\x{7B8D}\x{7B8F}\x{7B92}\x{7B94}\x{7B95}\x{7B97}\x{7B98}' .
          '\x{7B99}\x{7B9A}\x{7B9C}\x{7B9D}\x{7B9F}\x{7BA1}\x{7BAA}\x{7BAD}\x{7BB1}' .
          '\x{7BB4}\x{7BB8}\x{7BC0}\x{7BC1}\x{7BC4}\x{7BC6}\x{7BC7}\x{7BC9}\x{7BCB}' .
          '\x{7BCC}\x{7BCF}\x{7BDD}\x{7BE0}\x{7BE4}\x{7BE5}\x{7BE6}\x{7BE9}\x{7BED}' .
          '\x{7BF3}\x{7BF6}\x{7BF7}\x{7C00}\x{7C07}\x{7C0D}\x{7C11}\x{7C12}\x{7C13}' .
          '\x{7C14}\x{7C17}\x{7C1F}\x{7C21}\x{7C23}\x{7C27}\x{7C2A}\x{7C2B}\x{7C37}' .
          '\x{7C38}\x{7C3D}\x{7C3E}\x{7C3F}\x{7C40}\x{7C43}\x{7C4C}\x{7C4D}\x{7C4F}' .
          '\x{7C50}\x{7C54}\x{7C56}\x{7C58}\x{7C5F}\x{7C60}\x{7C64}\x{7C65}\x{7C6C}' .
          '\x{7C73}\x{7C75}\x{7C7E}\x{7C81}\x{7C82}\x{7C83}\x{7C89}\x{7C8B}\x{7C8D}' .
          '\x{7C90}\x{7C92}\x{7C95}\x{7C97}\x{7C98}\x{7C9B}\x{7C9F}\x{7CA1}\x{7CA2}' .
          '\x{7CA4}\x{7CA5}\x{7CA7}\x{7CA8}\x{7CAB}\x{7CAD}\x{7CAE}\x{7CB1}\x{7CB2}' .
          '\x{7CB3}\x{7CB9}\x{7CBD}\x{7CBE}\x{7CC0}\x{7CC2}\x{7CC5}\x{7CCA}\x{7CCE}' .
          '\x{7CD2}\x{7CD6}\x{7CD8}\x{7CDC}\x{7CDE}\x{7CDF}\x{7CE0}\x{7CE2}\x{7CE7}' .
          '\x{7CEF}\x{7CF2}\x{7CF4}\x{7CF6}\x{7CF8}\x{7CFA}\x{7CFB}\x{7CFE}\x{7D00}' .
          '\x{7D02}\x{7D04}\x{7D05}\x{7D06}\x{7D0A}\x{7D0B}\x{7D0D}\x{7D10}\x{7D14}' .
          '\x{7D15}\x{7D17}\x{7D18}\x{7D19}\x{7D1A}\x{7D1B}\x{7D1C}\x{7D20}\x{7D21}' .
          '\x{7D22}\x{7D2B}\x{7D2C}\x{7D2E}\x{7D2F}\x{7D30}\x{7D32}\x{7D33}\x{7D35}' .
          '\x{7D39}\x{7D3A}\x{7D3F}\x{7D42}\x{7D43}\x{7D44}\x{7D45}\x{7D46}\x{7D4B}' .
          '\x{7D4C}\x{7D4E}\x{7D4F}\x{7D50}\x{7D56}\x{7D5B}\x{7D5E}\x{7D61}\x{7D62}' .
          '\x{7D63}\x{7D66}\x{7D68}\x{7D6E}\x{7D71}\x{7D72}\x{7D73}\x{7D75}\x{7D76}' .
          '\x{7D79}\x{7D7D}\x{7D89}\x{7D8F}\x{7D93}\x{7D99}\x{7D9A}\x{7D9B}\x{7D9C}' .
          '\x{7D9F}\x{7DA2}\x{7DA3}\x{7DAB}\x{7DAC}\x{7DAD}\x{7DAE}\x{7DAF}\x{7DB0}' .
          '\x{7DB1}\x{7DB2}\x{7DB4}\x{7DB5}\x{7DB8}\x{7DBA}\x{7DBB}\x{7DBD}\x{7DBE}' .
          '\x{7DBF}\x{7DC7}\x{7DCA}\x{7DCB}\x{7DCF}\x{7DD1}\x{7DD2}\x{7DD5}\x{7DD8}' .
          '\x{7DDA}\x{7DDC}\x{7DDD}\x{7DDE}\x{7DE0}\x{7DE1}\x{7DE4}\x{7DE8}\x{7DE9}' .
          '\x{7DEC}\x{7DEF}\x{7DF2}\x{7DF4}\x{7DFB}\x{7E01}\x{7E04}\x{7E05}\x{7E09}' .
          '\x{7E0A}\x{7E0B}\x{7E12}\x{7E1B}\x{7E1E}\x{7E1F}\x{7E21}\x{7E22}\x{7E23}' .
          '\x{7E26}\x{7E2B}\x{7E2E}\x{7E31}\x{7E32}\x{7E35}\x{7E37}\x{7E39}\x{7E3A}' .
          '\x{7E3B}\x{7E3D}\x{7E3E}\x{7E41}\x{7E43}\x{7E46}\x{7E4A}\x{7E4B}\x{7E4D}' .
          '\x{7E54}\x{7E55}\x{7E56}\x{7E59}\x{7E5A}\x{7E5D}\x{7E5E}\x{7E66}\x{7E67}' .
          '\x{7E69}\x{7E6A}\x{7E6D}\x{7E70}\x{7E79}\x{7E7B}\x{7E7C}\x{7E7D}\x{7E7F}' .
          '\x{7E82}\x{7E83}\x{7E88}\x{7E89}\x{7E8C}\x{7E8E}\x{7E8F}\x{7E90}\x{7E92}' .
          '\x{7E93}\x{7E94}\x{7E96}\x{7E9B}\x{7E9C}\x{7F36}\x{7F38}\x{7F3A}\x{7F45}' .
          '\x{7F4C}\x{7F4D}\x{7F4E}\x{7F50}\x{7F51}\x{7F54}\x{7F55}\x{7F58}\x{7F5F}' .
          '\x{7F60}\x{7F67}\x{7F68}\x{7F69}\x{7F6A}\x{7F6B}\x{7F6E}\x{7F70}\x{7F72}' .
          '\x{7F75}\x{7F77}\x{7F78}\x{7F79}\x{7F82}\x{7F83}\x{7F85}\x{7F86}\x{7F87}' .
          '\x{7F88}\x{7F8A}\x{7F8C}\x{7F8E}\x{7F94}\x{7F9A}\x{7F9D}\x{7F9E}\x{7FA3}' .
          '\x{7FA4}\x{7FA8}\x{7FA9}\x{7FAE}\x{7FAF}\x{7FB2}\x{7FB6}\x{7FB8}\x{7FB9}' .
          '\x{7FBD}\x{7FC1}\x{7FC5}\x{7FC6}\x{7FCA}\x{7FCC}\x{7FD2}\x{7FD4}\x{7FD5}' .
          '\x{7FE0}\x{7FE1}\x{7FE6}\x{7FE9}\x{7FEB}\x{7FF0}\x{7FF3}\x{7FF9}\x{7FFB}' .
          '\x{7FFC}\x{8000}\x{8001}\x{8003}\x{8004}\x{8005}\x{8006}\x{800B}\x{800C}' .
          '\x{8010}\x{8012}\x{8015}\x{8017}\x{8018}\x{8019}\x{801C}\x{8021}\x{8028}' .
          '\x{8033}\x{8036}\x{803B}\x{803D}\x{803F}\x{8046}\x{804A}\x{8052}\x{8056}' .
          '\x{8058}\x{805A}\x{805E}\x{805F}\x{8061}\x{8062}\x{8068}\x{806F}\x{8070}' .
          '\x{8072}\x{8073}\x{8074}\x{8076}\x{8077}\x{8079}\x{807D}\x{807E}\x{807F}' .
          '\x{8084}\x{8085}\x{8086}\x{8087}\x{8089}\x{808B}\x{808C}\x{8093}\x{8096}' .
          '\x{8098}\x{809A}\x{809B}\x{809D}\x{80A1}\x{80A2}\x{80A5}\x{80A9}\x{80AA}' .
          '\x{80AC}\x{80AD}\x{80AF}\x{80B1}\x{80B2}\x{80B4}\x{80BA}\x{80C3}\x{80C4}' .
          '\x{80C6}\x{80CC}\x{80CE}\x{80D6}\x{80D9}\x{80DA}\x{80DB}\x{80DD}\x{80DE}' .
          '\x{80E1}\x{80E4}\x{80E5}\x{80EF}\x{80F1}\x{80F4}\x{80F8}\x{80FC}\x{80FD}' .
          '\x{8102}\x{8105}\x{8106}\x{8107}\x{8108}\x{8109}\x{810A}\x{811A}\x{811B}' .
          '\x{8123}\x{8129}\x{812F}\x{8131}\x{8133}\x{8139}\x{813E}\x{8146}\x{814B}' .
          '\x{814E}\x{8150}\x{8151}\x{8153}\x{8154}\x{8155}\x{815F}\x{8165}\x{8166}' .
          '\x{816B}\x{816E}\x{8170}\x{8171}\x{8174}\x{8178}\x{8179}\x{817A}\x{817F}' .
          '\x{8180}\x{8182}\x{8183}\x{8188}\x{818A}\x{818F}\x{8193}\x{8195}\x{819A}' .
          '\x{819C}\x{819D}\x{81A0}\x{81A3}\x{81A4}\x{81A8}\x{81A9}\x{81B0}\x{81B3}' .
          '\x{81B5}\x{81B8}\x{81BA}\x{81BD}\x{81BE}\x{81BF}\x{81C0}\x{81C2}\x{81C6}' .
          '\x{81C8}\x{81C9}\x{81CD}\x{81D1}\x{81D3}\x{81D8}\x{81D9}\x{81DA}\x{81DF}' .
          '\x{81E0}\x{81E3}\x{81E5}\x{81E7}\x{81E8}\x{81EA}\x{81ED}\x{81F3}\x{81F4}' .
          '\x{81FA}\x{81FB}\x{81FC}\x{81FE}\x{8201}\x{8202}\x{8205}\x{8207}\x{8208}' .
          '\x{8209}\x{820A}\x{820C}\x{820D}\x{820E}\x{8210}\x{8212}\x{8216}\x{8217}' .
          '\x{8218}\x{821B}\x{821C}\x{821E}\x{821F}\x{8229}\x{822A}\x{822B}\x{822C}' .
          '\x{822E}\x{8233}\x{8235}\x{8236}\x{8237}\x{8238}\x{8239}\x{8240}\x{8247}' .
          '\x{8258}\x{8259}\x{825A}\x{825D}\x{825F}\x{8262}\x{8264}\x{8266}\x{8268}' .
          '\x{826A}\x{826B}\x{826E}\x{826F}\x{8271}\x{8272}\x{8276}\x{8277}\x{8278}' .
          '\x{827E}\x{828B}\x{828D}\x{8292}\x{8299}\x{829D}\x{829F}\x{82A5}\x{82A6}' .
          '\x{82AB}\x{82AC}\x{82AD}\x{82AF}\x{82B1}\x{82B3}\x{82B8}\x{82B9}\x{82BB}' .
          '\x{82BD}\x{82C5}\x{82D1}\x{82D2}\x{82D3}\x{82D4}\x{82D7}\x{82D9}\x{82DB}' .
          '\x{82DC}\x{82DE}\x{82DF}\x{82E1}\x{82E3}\x{82E5}\x{82E6}\x{82E7}\x{82EB}' .
          '\x{82F1}\x{82F3}\x{82F4}\x{82F9}\x{82FA}\x{82FB}\x{8302}\x{8303}\x{8304}' .
          '\x{8305}\x{8306}\x{8309}\x{830E}\x{8316}\x{8317}\x{8318}\x{831C}\x{8323}' .
          '\x{8328}\x{832B}\x{832F}\x{8331}\x{8332}\x{8334}\x{8335}\x{8336}\x{8338}' .
          '\x{8339}\x{8340}\x{8345}\x{8349}\x{834A}\x{834F}\x{8350}\x{8352}\x{8358}' .
          '\x{8373}\x{8375}\x{8377}\x{837B}\x{837C}\x{8385}\x{8387}\x{8389}\x{838A}' .
          '\x{838E}\x{8393}\x{8396}\x{839A}\x{839E}\x{839F}\x{83A0}\x{83A2}\x{83A8}' .
          '\x{83AA}\x{83AB}\x{83B1}\x{83B5}\x{83BD}\x{83C1}\x{83C5}\x{83CA}\x{83CC}' .
          '\x{83CE}\x{83D3}\x{83D6}\x{83D8}\x{83DC}\x{83DF}\x{83E0}\x{83E9}\x{83EB}' .
          '\x{83EF}\x{83F0}\x{83F1}\x{83F2}\x{83F4}\x{83F7}\x{83FB}\x{83FD}\x{8403}' .
          '\x{8404}\x{8407}\x{840B}\x{840C}\x{840D}\x{840E}\x{8413}\x{8420}\x{8422}' .
          '\x{8429}\x{842A}\x{842C}\x{8431}\x{8435}\x{8438}\x{843C}\x{843D}\x{8446}' .
          '\x{8449}\x{844E}\x{8457}\x{845B}\x{8461}\x{8462}\x{8463}\x{8466}\x{8469}' .
          '\x{846B}\x{846C}\x{846D}\x{846E}\x{846F}\x{8471}\x{8475}\x{8477}\x{8479}' .
          '\x{847A}\x{8482}\x{8484}\x{848B}\x{8490}\x{8494}\x{8499}\x{849C}\x{849F}' .
          '\x{84A1}\x{84AD}\x{84B2}\x{84B8}\x{84B9}\x{84BB}\x{84BC}\x{84BF}\x{84C1}' .
          '\x{84C4}\x{84C6}\x{84C9}\x{84CA}\x{84CB}\x{84CD}\x{84D0}\x{84D1}\x{84D6}' .
          '\x{84D9}\x{84DA}\x{84EC}\x{84EE}\x{84F4}\x{84FC}\x{84FF}\x{8500}\x{8506}' .
          '\x{8511}\x{8513}\x{8514}\x{8515}\x{8517}\x{8518}\x{851A}\x{851F}\x{8521}' .
          '\x{8526}\x{852C}\x{852D}\x{8535}\x{853D}\x{8540}\x{8541}\x{8543}\x{8548}' .
          '\x{8549}\x{854A}\x{854B}\x{854E}\x{8555}\x{8557}\x{8558}\x{855A}\x{8563}' .
          '\x{8568}\x{8569}\x{856A}\x{856D}\x{8577}\x{857E}\x{8580}\x{8584}\x{8587}' .
          '\x{8588}\x{858A}\x{8590}\x{8591}\x{8594}\x{8597}\x{8599}\x{859B}\x{859C}' .
          '\x{85A4}\x{85A6}\x{85A8}\x{85A9}\x{85AA}\x{85AB}\x{85AC}\x{85AE}\x{85AF}' .
          '\x{85B9}\x{85BA}\x{85C1}\x{85C9}\x{85CD}\x{85CF}\x{85D0}\x{85D5}\x{85DC}' .
          '\x{85DD}\x{85E4}\x{85E5}\x{85E9}\x{85EA}\x{85F7}\x{85F9}\x{85FA}\x{85FB}' .
          '\x{85FE}\x{8602}\x{8606}\x{8607}\x{860A}\x{860B}\x{8613}\x{8616}\x{8617}' .
          '\x{861A}\x{8622}\x{862D}\x{862F}\x{8630}\x{863F}\x{864D}\x{864E}\x{8650}' .
          '\x{8654}\x{8655}\x{865A}\x{865C}\x{865E}\x{865F}\x{8667}\x{866B}\x{8671}' .
          '\x{8679}\x{867B}\x{868A}\x{868B}\x{868C}\x{8693}\x{8695}\x{86A3}\x{86A4}' .
          '\x{86A9}\x{86AA}\x{86AB}\x{86AF}\x{86B0}\x{86B6}\x{86C4}\x{86C6}\x{86C7}' .
          '\x{86C9}\x{86CB}\x{86CD}\x{86CE}\x{86D4}\x{86D9}\x{86DB}\x{86DE}\x{86DF}' .
          '\x{86E4}\x{86E9}\x{86EC}\x{86ED}\x{86EE}\x{86EF}\x{86F8}\x{86F9}\x{86FB}' .
          '\x{86FE}\x{8700}\x{8702}\x{8703}\x{8706}\x{8708}\x{8709}\x{870A}\x{870D}' .
          '\x{8711}\x{8712}\x{8718}\x{871A}\x{871C}\x{8725}\x{8729}\x{8734}\x{8737}' .
          '\x{873B}\x{873F}\x{8749}\x{874B}\x{874C}\x{874E}\x{8753}\x{8755}\x{8757}' .
          '\x{8759}\x{875F}\x{8760}\x{8763}\x{8766}\x{8768}\x{876A}\x{876E}\x{8774}' .
          '\x{8776}\x{8778}\x{877F}\x{8782}\x{878D}\x{879F}\x{87A2}\x{87AB}\x{87AF}' .
          '\x{87B3}\x{87BA}\x{87BB}\x{87BD}\x{87C0}\x{87C4}\x{87C6}\x{87C7}\x{87CB}' .
          '\x{87D0}\x{87D2}\x{87E0}\x{87EF}\x{87F2}\x{87F6}\x{87F7}\x{87F9}\x{87FB}' .
          '\x{87FE}\x{8805}\x{880D}\x{880E}\x{880F}\x{8811}\x{8815}\x{8816}\x{8821}' .
          '\x{8822}\x{8823}\x{8827}\x{8831}\x{8836}\x{8839}\x{883B}\x{8840}\x{8842}' .
          '\x{8844}\x{8846}\x{884C}\x{884D}\x{8852}\x{8853}\x{8857}\x{8859}\x{885B}' .
          '\x{885D}\x{885E}\x{8861}\x{8862}\x{8863}\x{8868}\x{886B}\x{8870}\x{8872}' .
          '\x{8875}\x{8877}\x{887D}\x{887E}\x{887F}\x{8881}\x{8882}\x{8888}\x{888B}' .
          '\x{888D}\x{8892}\x{8896}\x{8897}\x{8899}\x{889E}\x{88A2}\x{88A4}\x{88AB}' .
          '\x{88AE}\x{88B0}\x{88B1}\x{88B4}\x{88B5}\x{88B7}\x{88BF}\x{88C1}\x{88C2}' .
          '\x{88C3}\x{88C4}\x{88C5}\x{88CF}\x{88D4}\x{88D5}\x{88D8}\x{88D9}\x{88DC}' .
          '\x{88DD}\x{88DF}\x{88E1}\x{88E8}\x{88F2}\x{88F3}\x{88F4}\x{88F8}\x{88F9}' .
          '\x{88FC}\x{88FD}\x{88FE}\x{8902}\x{8904}\x{8907}\x{890A}\x{890C}\x{8910}' .
          '\x{8912}\x{8913}\x{891D}\x{891E}\x{8925}\x{892A}\x{892B}\x{8936}\x{8938}' .
          '\x{893B}\x{8941}\x{8943}\x{8944}\x{894C}\x{894D}\x{8956}\x{895E}\x{895F}' .
          '\x{8960}\x{8964}\x{8966}\x{896A}\x{896D}\x{896F}\x{8972}\x{8974}\x{8977}' .
          '\x{897E}\x{897F}\x{8981}\x{8983}\x{8986}\x{8987}\x{8988}\x{898A}\x{898B}' .
          '\x{898F}\x{8993}\x{8996}\x{8997}\x{8998}\x{899A}\x{89A1}\x{89A6}\x{89A7}' .
          '\x{89A9}\x{89AA}\x{89AC}\x{89AF}\x{89B2}\x{89B3}\x{89BA}\x{89BD}\x{89BF}' .
          '\x{89C0}\x{89D2}\x{89DA}\x{89DC}\x{89DD}\x{89E3}\x{89E6}\x{89E7}\x{89F4}' .
          '\x{89F8}\x{8A00}\x{8A02}\x{8A03}\x{8A08}\x{8A0A}\x{8A0C}\x{8A0E}\x{8A10}' .
          '\x{8A13}\x{8A16}\x{8A17}\x{8A18}\x{8A1B}\x{8A1D}\x{8A1F}\x{8A23}\x{8A25}' .
          '\x{8A2A}\x{8A2D}\x{8A31}\x{8A33}\x{8A34}\x{8A36}\x{8A3A}\x{8A3B}\x{8A3C}' .
          '\x{8A41}\x{8A46}\x{8A48}\x{8A50}\x{8A51}\x{8A52}\x{8A54}\x{8A55}\x{8A5B}' .
          '\x{8A5E}\x{8A60}\x{8A62}\x{8A63}\x{8A66}\x{8A69}\x{8A6B}\x{8A6C}\x{8A6D}' .
          '\x{8A6E}\x{8A70}\x{8A71}\x{8A72}\x{8A73}\x{8A7C}\x{8A82}\x{8A84}\x{8A85}' .
          '\x{8A87}\x{8A89}\x{8A8C}\x{8A8D}\x{8A91}\x{8A93}\x{8A95}\x{8A98}\x{8A9A}' .
          '\x{8A9E}\x{8AA0}\x{8AA1}\x{8AA3}\x{8AA4}\x{8AA5}\x{8AA6}\x{8AA8}\x{8AAC}' .
          '\x{8AAD}\x{8AB0}\x{8AB2}\x{8AB9}\x{8ABC}\x{8ABF}\x{8AC2}\x{8AC4}\x{8AC7}' .
          '\x{8ACB}\x{8ACC}\x{8ACD}\x{8ACF}\x{8AD2}\x{8AD6}\x{8ADA}\x{8ADB}\x{8ADC}' .
          '\x{8ADE}\x{8AE0}\x{8AE1}\x{8AE2}\x{8AE4}\x{8AE6}\x{8AE7}\x{8AEB}\x{8AED}' .
          '\x{8AEE}\x{8AF1}\x{8AF3}\x{8AF7}\x{8AF8}\x{8AFA}\x{8AFE}\x{8B00}\x{8B01}' .
          '\x{8B02}\x{8B04}\x{8B07}\x{8B0C}\x{8B0E}\x{8B10}\x{8B14}\x{8B16}\x{8B17}' .
          '\x{8B19}\x{8B1A}\x{8B1B}\x{8B1D}\x{8B20}\x{8B21}\x{8B26}\x{8B28}\x{8B2B}' .
          '\x{8B2C}\x{8B33}\x{8B39}\x{8B3E}\x{8B41}\x{8B49}\x{8B4C}\x{8B4E}\x{8B4F}' .
          '\x{8B56}\x{8B58}\x{8B5A}\x{8B5B}\x{8B5C}\x{8B5F}\x{8B66}\x{8B6B}\x{8B6C}' .
          '\x{8B6F}\x{8B70}\x{8B71}\x{8B72}\x{8B74}\x{8B77}\x{8B7D}\x{8B80}\x{8B83}' .
          '\x{8B8A}\x{8B8C}\x{8B8E}\x{8B90}\x{8B92}\x{8B93}\x{8B96}\x{8B99}\x{8B9A}' .
          '\x{8C37}\x{8C3A}\x{8C3F}\x{8C41}\x{8C46}\x{8C48}\x{8C4A}\x{8C4C}\x{8C4E}' .
          '\x{8C50}\x{8C55}\x{8C5A}\x{8C61}\x{8C62}\x{8C6A}\x{8C6B}\x{8C6C}\x{8C78}' .
          '\x{8C79}\x{8C7A}\x{8C7C}\x{8C82}\x{8C85}\x{8C89}\x{8C8A}\x{8C8C}\x{8C8D}' .
          '\x{8C8E}\x{8C94}\x{8C98}\x{8C9D}\x{8C9E}\x{8CA0}\x{8CA1}\x{8CA2}\x{8CA7}' .
          '\x{8CA8}\x{8CA9}\x{8CAA}\x{8CAB}\x{8CAC}\x{8CAD}\x{8CAE}\x{8CAF}\x{8CB0}' .
          '\x{8CB2}\x{8CB3}\x{8CB4}\x{8CB6}\x{8CB7}\x{8CB8}\x{8CBB}\x{8CBC}\x{8CBD}' .
          '\x{8CBF}\x{8CC0}\x{8CC1}\x{8CC2}\x{8CC3}\x{8CC4}\x{8CC7}\x{8CC8}\x{8CCA}' .
          '\x{8CCD}\x{8CCE}\x{8CD1}\x{8CD3}\x{8CDA}\x{8CDB}\x{8CDC}\x{8CDE}\x{8CE0}' .
          '\x{8CE2}\x{8CE3}\x{8CE4}\x{8CE6}\x{8CEA}\x{8CED}\x{8CFA}\x{8CFB}\x{8CFC}' .
          '\x{8CFD}\x{8D04}\x{8D05}\x{8D07}\x{8D08}\x{8D0A}\x{8D0B}\x{8D0D}\x{8D0F}' .
          '\x{8D10}\x{8D13}\x{8D14}\x{8D16}\x{8D64}\x{8D66}\x{8D67}\x{8D6B}\x{8D6D}' .
          '\x{8D70}\x{8D71}\x{8D73}\x{8D74}\x{8D77}\x{8D81}\x{8D85}\x{8D8A}\x{8D99}' .
          '\x{8DA3}\x{8DA8}\x{8DB3}\x{8DBA}\x{8DBE}\x{8DC2}\x{8DCB}\x{8DCC}\x{8DCF}' .
          '\x{8DD6}\x{8DDA}\x{8DDB}\x{8DDD}\x{8DDF}\x{8DE1}\x{8DE3}\x{8DE8}\x{8DEA}' .
          '\x{8DEB}\x{8DEF}\x{8DF3}\x{8DF5}\x{8DFC}\x{8DFF}\x{8E08}\x{8E09}\x{8E0A}' .
          '\x{8E0F}\x{8E10}\x{8E1D}\x{8E1E}\x{8E1F}\x{8E2A}\x{8E30}\x{8E34}\x{8E35}' .
          '\x{8E42}\x{8E44}\x{8E47}\x{8E48}\x{8E49}\x{8E4A}\x{8E4C}\x{8E50}\x{8E55}' .
          '\x{8E59}\x{8E5F}\x{8E60}\x{8E63}\x{8E64}\x{8E72}\x{8E74}\x{8E76}\x{8E7C}' .
          '\x{8E81}\x{8E84}\x{8E85}\x{8E87}\x{8E8A}\x{8E8B}\x{8E8D}\x{8E91}\x{8E93}' .
          '\x{8E94}\x{8E99}\x{8EA1}\x{8EAA}\x{8EAB}\x{8EAC}\x{8EAF}\x{8EB0}\x{8EB1}' .
          '\x{8EBE}\x{8EC5}\x{8EC6}\x{8EC8}\x{8ECA}\x{8ECB}\x{8ECC}\x{8ECD}\x{8ED2}' .
          '\x{8EDB}\x{8EDF}\x{8EE2}\x{8EE3}\x{8EEB}\x{8EF8}\x{8EFB}\x{8EFC}\x{8EFD}' .
          '\x{8EFE}\x{8F03}\x{8F05}\x{8F09}\x{8F0A}\x{8F0C}\x{8F12}\x{8F13}\x{8F14}' .
          '\x{8F15}\x{8F19}\x{8F1B}\x{8F1C}\x{8F1D}\x{8F1F}\x{8F26}\x{8F29}\x{8F2A}' .
          '\x{8F2F}\x{8F33}\x{8F38}\x{8F39}\x{8F3B}\x{8F3E}\x{8F3F}\x{8F42}\x{8F44}' .
          '\x{8F45}\x{8F46}\x{8F49}\x{8F4C}\x{8F4D}\x{8F4E}\x{8F57}\x{8F5C}\x{8F5F}' .
          '\x{8F61}\x{8F62}\x{8F63}\x{8F64}\x{8F9B}\x{8F9C}\x{8F9E}\x{8F9F}\x{8FA3}' .
          '\x{8FA7}\x{8FA8}\x{8FAD}\x{8FAE}\x{8FAF}\x{8FB0}\x{8FB1}\x{8FB2}\x{8FB7}' .
          '\x{8FBA}\x{8FBB}\x{8FBC}\x{8FBF}\x{8FC2}\x{8FC4}\x{8FC5}\x{8FCE}\x{8FD1}' .
          '\x{8FD4}\x{8FDA}\x{8FE2}\x{8FE5}\x{8FE6}\x{8FE9}\x{8FEA}\x{8FEB}\x{8FED}' .
          '\x{8FEF}\x{8FF0}\x{8FF4}\x{8FF7}\x{8FF8}\x{8FF9}\x{8FFA}\x{8FFD}\x{9000}' .
          '\x{9001}\x{9003}\x{9005}\x{9006}\x{900B}\x{900D}\x{900E}\x{900F}\x{9010}' .
          '\x{9011}\x{9013}\x{9014}\x{9015}\x{9016}\x{9017}\x{9019}\x{901A}\x{901D}' .
          '\x{901E}\x{901F}\x{9020}\x{9021}\x{9022}\x{9023}\x{9027}\x{902E}\x{9031}' .
          '\x{9032}\x{9035}\x{9036}\x{9038}\x{9039}\x{903C}\x{903E}\x{9041}\x{9042}' .
          '\x{9045}\x{9047}\x{9049}\x{904A}\x{904B}\x{904D}\x{904E}\x{904F}\x{9050}' .
          '\x{9051}\x{9052}\x{9053}\x{9054}\x{9055}\x{9056}\x{9058}\x{9059}\x{905C}' .
          '\x{905E}\x{9060}\x{9061}\x{9063}\x{9065}\x{9068}\x{9069}\x{906D}\x{906E}' .
          '\x{906F}\x{9072}\x{9075}\x{9076}\x{9077}\x{9078}\x{907A}\x{907C}\x{907D}' .
          '\x{907F}\x{9080}\x{9081}\x{9082}\x{9083}\x{9084}\x{9087}\x{9089}\x{908A}' .
          '\x{908F}\x{9091}\x{90A3}\x{90A6}\x{90A8}\x{90AA}\x{90AF}\x{90B1}\x{90B5}' .
          '\x{90B8}\x{90C1}\x{90CA}\x{90CE}\x{90DB}\x{90E1}\x{90E2}\x{90E4}\x{90E8}' .
          '\x{90ED}\x{90F5}\x{90F7}\x{90FD}\x{9102}\x{9112}\x{9119}\x{912D}\x{9130}' .
          '\x{9132}\x{9149}\x{914A}\x{914B}\x{914C}\x{914D}\x{914E}\x{9152}\x{9154}' .
          '\x{9156}\x{9158}\x{9162}\x{9163}\x{9165}\x{9169}\x{916A}\x{916C}\x{9172}' .
          '\x{9173}\x{9175}\x{9177}\x{9178}\x{9182}\x{9187}\x{9189}\x{918B}\x{918D}' .
          '\x{9190}\x{9192}\x{9197}\x{919C}\x{91A2}\x{91A4}\x{91AA}\x{91AB}\x{91AF}' .
          '\x{91B4}\x{91B5}\x{91B8}\x{91BA}\x{91C0}\x{91C1}\x{91C6}\x{91C7}\x{91C8}' .
          '\x{91C9}\x{91CB}\x{91CC}\x{91CD}\x{91CE}\x{91CF}\x{91D0}\x{91D1}\x{91D6}' .
          '\x{91D8}\x{91DB}\x{91DC}\x{91DD}\x{91DF}\x{91E1}\x{91E3}\x{91E6}\x{91E7}' .
          '\x{91F5}\x{91F6}\x{91FC}\x{91FF}\x{920D}\x{920E}\x{9211}\x{9214}\x{9215}' .
          '\x{921E}\x{9229}\x{922C}\x{9234}\x{9237}\x{923F}\x{9244}\x{9245}\x{9248}' .
          '\x{9249}\x{924B}\x{9250}\x{9257}\x{925A}\x{925B}\x{925E}\x{9262}\x{9264}' .
          '\x{9266}\x{9271}\x{927E}\x{9280}\x{9283}\x{9285}\x{9291}\x{9293}\x{9295}' .
          '\x{9296}\x{9298}\x{929A}\x{929B}\x{929C}\x{92AD}\x{92B7}\x{92B9}\x{92CF}' .
          '\x{92D2}\x{92E4}\x{92E9}\x{92EA}\x{92ED}\x{92F2}\x{92F3}\x{92F8}\x{92FA}' .
          '\x{92FC}\x{9306}\x{930F}\x{9310}\x{9318}\x{9319}\x{931A}\x{9320}\x{9322}' .
          '\x{9323}\x{9326}\x{9328}\x{932B}\x{932C}\x{932E}\x{932F}\x{9332}\x{9335}' .
          '\x{933A}\x{933B}\x{9344}\x{934B}\x{934D}\x{9354}\x{9356}\x{935B}\x{935C}' .
          '\x{9360}\x{936C}\x{936E}\x{9375}\x{937C}\x{937E}\x{938C}\x{9394}\x{9396}' .
          '\x{9397}\x{939A}\x{93A7}\x{93AC}\x{93AD}\x{93AE}\x{93B0}\x{93B9}\x{93C3}' .
          '\x{93C8}\x{93D0}\x{93D1}\x{93D6}\x{93D7}\x{93D8}\x{93DD}\x{93E1}\x{93E4}' .
          '\x{93E5}\x{93E8}\x{9403}\x{9407}\x{9410}\x{9413}\x{9414}\x{9418}\x{9419}' .
          '\x{941A}\x{9421}\x{942B}\x{9435}\x{9436}\x{9438}\x{943A}\x{9441}\x{9444}' .
          '\x{9451}\x{9452}\x{9453}\x{945A}\x{945B}\x{945E}\x{9460}\x{9462}\x{946A}' .
          '\x{9470}\x{9475}\x{9477}\x{947C}\x{947D}\x{947E}\x{947F}\x{9481}\x{9577}' .
          '\x{9580}\x{9582}\x{9583}\x{9587}\x{9589}\x{958A}\x{958B}\x{958F}\x{9591}' .
          '\x{9593}\x{9594}\x{9596}\x{9598}\x{9599}\x{95A0}\x{95A2}\x{95A3}\x{95A4}' .
          '\x{95A5}\x{95A7}\x{95A8}\x{95AD}\x{95B2}\x{95B9}\x{95BB}\x{95BC}\x{95BE}' .
          '\x{95C3}\x{95C7}\x{95CA}\x{95CC}\x{95CD}\x{95D4}\x{95D5}\x{95D6}\x{95D8}' .
          '\x{95DC}\x{95E1}\x{95E2}\x{95E5}\x{961C}\x{9621}\x{9628}\x{962A}\x{962E}' .
          '\x{962F}\x{9632}\x{963B}\x{963F}\x{9640}\x{9642}\x{9644}\x{964B}\x{964C}' .
          '\x{964D}\x{964F}\x{9650}\x{965B}\x{965C}\x{965D}\x{965E}\x{965F}\x{9662}' .
          '\x{9663}\x{9664}\x{9665}\x{9666}\x{966A}\x{966C}\x{9670}\x{9672}\x{9673}' .
          '\x{9675}\x{9676}\x{9677}\x{9678}\x{967A}\x{967D}\x{9685}\x{9686}\x{9688}' .
          '\x{968A}\x{968B}\x{968D}\x{968E}\x{968F}\x{9694}\x{9695}\x{9697}\x{9698}' .
          '\x{9699}\x{969B}\x{969C}\x{96A0}\x{96A3}\x{96A7}\x{96A8}\x{96AA}\x{96B0}' .
          '\x{96B1}\x{96B2}\x{96B4}\x{96B6}\x{96B7}\x{96B8}\x{96B9}\x{96BB}\x{96BC}' .
          '\x{96C0}\x{96C1}\x{96C4}\x{96C5}\x{96C6}\x{96C7}\x{96C9}\x{96CB}\x{96CC}' .
          '\x{96CD}\x{96CE}\x{96D1}\x{96D5}\x{96D6}\x{96D9}\x{96DB}\x{96DC}\x{96E2}' .
          '\x{96E3}\x{96E8}\x{96EA}\x{96EB}\x{96F0}\x{96F2}\x{96F6}\x{96F7}\x{96F9}' .
          '\x{96FB}\x{9700}\x{9704}\x{9706}\x{9707}\x{9708}\x{970A}\x{970D}\x{970E}' .
          '\x{970F}\x{9711}\x{9713}\x{9716}\x{9719}\x{971C}\x{971E}\x{9724}\x{9727}' .
          '\x{972A}\x{9730}\x{9732}\x{9738}\x{9739}\x{973D}\x{973E}\x{9742}\x{9744}' .
          '\x{9746}\x{9748}\x{9749}\x{9752}\x{9756}\x{9759}\x{975C}\x{975E}\x{9760}' .
          '\x{9761}\x{9762}\x{9764}\x{9766}\x{9768}\x{9769}\x{976B}\x{976D}\x{9771}' .
          '\x{9774}\x{9779}\x{977A}\x{977C}\x{9781}\x{9784}\x{9785}\x{9786}\x{978B}' .
          '\x{978D}\x{978F}\x{9790}\x{9798}\x{979C}\x{97A0}\x{97A3}\x{97A6}\x{97A8}' .
          '\x{97AB}\x{97AD}\x{97B3}\x{97B4}\x{97C3}\x{97C6}\x{97C8}\x{97CB}\x{97D3}' .
          '\x{97DC}\x{97ED}\x{97EE}\x{97F2}\x{97F3}\x{97F5}\x{97F6}\x{97FB}\x{97FF}' .
          '\x{9801}\x{9802}\x{9803}\x{9805}\x{9806}\x{9808}\x{980C}\x{980F}\x{9810}' .
          '\x{9811}\x{9812}\x{9813}\x{9817}\x{9818}\x{981A}\x{9821}\x{9824}\x{982C}' .
          '\x{982D}\x{9834}\x{9837}\x{9838}\x{983B}\x{983C}\x{983D}\x{9846}\x{984B}' .
          '\x{984C}\x{984D}\x{984E}\x{984F}\x{9854}\x{9855}\x{9858}\x{985B}\x{985E}' .
          '\x{9867}\x{986B}\x{986F}\x{9870}\x{9871}\x{9873}\x{9874}\x{98A8}\x{98AA}' .
          '\x{98AF}\x{98B1}\x{98B6}\x{98C3}\x{98C4}\x{98C6}\x{98DB}\x{98DC}\x{98DF}' .
          '\x{98E2}\x{98E9}\x{98EB}\x{98ED}\x{98EE}\x{98EF}\x{98F2}\x{98F4}\x{98FC}' .
          '\x{98FD}\x{98FE}\x{9903}\x{9905}\x{9909}\x{990A}\x{990C}\x{9910}\x{9912}' .
          '\x{9913}\x{9914}\x{9918}\x{991D}\x{991E}\x{9920}\x{9921}\x{9924}\x{9928}' .
          '\x{992C}\x{992E}\x{993D}\x{993E}\x{9942}\x{9945}\x{9949}\x{994B}\x{994C}' .
          '\x{9950}\x{9951}\x{9952}\x{9955}\x{9957}\x{9996}\x{9997}\x{9998}\x{9999}' .
          '\x{99A5}\x{99A8}\x{99AC}\x{99AD}\x{99AE}\x{99B3}\x{99B4}\x{99BC}\x{99C1}' .
          '\x{99C4}\x{99C5}\x{99C6}\x{99C8}\x{99D0}\x{99D1}\x{99D2}\x{99D5}\x{99D8}' .
          '\x{99DB}\x{99DD}\x{99DF}\x{99E2}\x{99ED}\x{99EE}\x{99F1}\x{99F2}\x{99F8}' .
          '\x{99FB}\x{99FF}\x{9A01}\x{9A05}\x{9A0E}\x{9A0F}\x{9A12}\x{9A13}\x{9A19}' .
          '\x{9A28}\x{9A2B}\x{9A30}\x{9A37}\x{9A3E}\x{9A40}\x{9A42}\x{9A43}\x{9A45}' .
          '\x{9A4D}\x{9A55}\x{9A57}\x{9A5A}\x{9A5B}\x{9A5F}\x{9A62}\x{9A64}\x{9A65}' .
          '\x{9A69}\x{9A6A}\x{9A6B}\x{9AA8}\x{9AAD}\x{9AB0}\x{9AB8}\x{9ABC}\x{9AC0}' .
          '\x{9AC4}\x{9ACF}\x{9AD1}\x{9AD3}\x{9AD4}\x{9AD8}\x{9ADE}\x{9ADF}\x{9AE2}' .
          '\x{9AE3}\x{9AE6}\x{9AEA}\x{9AEB}\x{9AED}\x{9AEE}\x{9AEF}\x{9AF1}\x{9AF4}' .
          '\x{9AF7}\x{9AFB}\x{9B06}\x{9B18}\x{9B1A}\x{9B1F}\x{9B22}\x{9B23}\x{9B25}' .
          '\x{9B27}\x{9B28}\x{9B29}\x{9B2A}\x{9B2E}\x{9B2F}\x{9B31}\x{9B32}\x{9B3B}' .
          '\x{9B3C}\x{9B41}\x{9B42}\x{9B43}\x{9B44}\x{9B45}\x{9B4D}\x{9B4E}\x{9B4F}' .
          '\x{9B51}\x{9B54}\x{9B58}\x{9B5A}\x{9B6F}\x{9B74}\x{9B83}\x{9B8E}\x{9B91}' .
          '\x{9B92}\x{9B93}\x{9B96}\x{9B97}\x{9B9F}\x{9BA0}\x{9BA8}\x{9BAA}\x{9BAB}' .
          '\x{9BAD}\x{9BAE}\x{9BB4}\x{9BB9}\x{9BC0}\x{9BC6}\x{9BC9}\x{9BCA}\x{9BCF}' .
          '\x{9BD1}\x{9BD2}\x{9BD4}\x{9BD6}\x{9BDB}\x{9BE1}\x{9BE2}\x{9BE3}\x{9BE4}' .
          '\x{9BE8}\x{9BF0}\x{9BF1}\x{9BF2}\x{9BF5}\x{9C04}\x{9C06}\x{9C08}\x{9C09}' .
          '\x{9C0A}\x{9C0C}\x{9C0D}\x{9C10}\x{9C12}\x{9C13}\x{9C14}\x{9C15}\x{9C1B}' .
          '\x{9C21}\x{9C24}\x{9C25}\x{9C2D}\x{9C2E}\x{9C2F}\x{9C30}\x{9C32}\x{9C39}' .
          '\x{9C3A}\x{9C3B}\x{9C3E}\x{9C46}\x{9C47}\x{9C48}\x{9C52}\x{9C57}\x{9C5A}' .
          '\x{9C60}\x{9C67}\x{9C76}\x{9C78}\x{9CE5}\x{9CE7}\x{9CE9}\x{9CEB}\x{9CEC}' .
          '\x{9CF0}\x{9CF3}\x{9CF4}\x{9CF6}\x{9D03}\x{9D06}\x{9D07}\x{9D08}\x{9D09}' .
          '\x{9D0E}\x{9D12}\x{9D15}\x{9D1B}\x{9D1F}\x{9D23}\x{9D26}\x{9D28}\x{9D2A}' .
          '\x{9D2B}\x{9D2C}\x{9D3B}\x{9D3E}\x{9D3F}\x{9D41}\x{9D44}\x{9D46}\x{9D48}' .
          '\x{9D50}\x{9D51}\x{9D59}\x{9D5C}\x{9D5D}\x{9D5E}\x{9D60}\x{9D61}\x{9D64}' .
          '\x{9D6C}\x{9D6F}\x{9D72}\x{9D7A}\x{9D87}\x{9D89}\x{9D8F}\x{9D9A}\x{9DA4}' .
          '\x{9DA9}\x{9DAB}\x{9DAF}\x{9DB2}\x{9DB4}\x{9DB8}\x{9DBA}\x{9DBB}\x{9DC1}' .
          '\x{9DC2}\x{9DC4}\x{9DC6}\x{9DCF}\x{9DD3}\x{9DD9}\x{9DE6}\x{9DED}\x{9DEF}' .
          '\x{9DF2}\x{9DF8}\x{9DF9}\x{9DFA}\x{9DFD}\x{9E1A}\x{9E1B}\x{9E1E}\x{9E75}' .
          '\x{9E78}\x{9E79}\x{9E7D}\x{9E7F}\x{9E81}\x{9E88}\x{9E8B}\x{9E8C}\x{9E91}' .
          '\x{9E92}\x{9E93}\x{9E95}\x{9E97}\x{9E9D}\x{9E9F}\x{9EA5}\x{9EA6}\x{9EA9}' .
          '\x{9EAA}\x{9EAD}\x{9EB8}\x{9EB9}\x{9EBA}\x{9EBB}\x{9EBC}\x{9EBE}\x{9EBF}' .
          '\x{9EC4}\x{9ECC}\x{9ECD}\x{9ECE}\x{9ECF}\x{9ED0}\x{9ED2}\x{9ED4}\x{9ED8}' .
          '\x{9ED9}\x{9EDB}\x{9EDC}\x{9EDD}\x{9EDE}\x{9EE0}\x{9EE5}\x{9EE8}\x{9EEF}' .
          '\x{9EF4}\x{9EF6}\x{9EF7}\x{9EF9}\x{9EFB}\x{9EFC}\x{9EFD}\x{9F07}\x{9F08}' .
          '\x{9F0E}\x{9F13}\x{9F15}\x{9F20}\x{9F21}\x{9F2C}\x{9F3B}\x{9F3E}\x{9F4A}' .
          '\x{9F4B}\x{9F4E}\x{9F4F}\x{9F52}\x{9F54}\x{9F5F}\x{9F60}\x{9F61}\x{9F62}' .
          '\x{9F63}\x{9F66}\x{9F67}\x{9F6A}\x{9F6C}\x{9F72}\x{9F76}\x{9F77}\x{9F8D}' .
          '\x{9F95}\x{9F9C}\x{9F9D}\x{9FA0}]{1,15}$/iu',
];
laminas-validator/src/Isbn/Isbn13.php000064400000002320147361032560013411 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-validator for the canonical source repository
 * @copyright https://github.com/laminas/laminas-validator/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-validator/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Validator\Isbn;

class Isbn13
{
    /**
     * @param int|string $value
     * @return int|string
     */
    public function getChecksum($value)
    {
        $sum = $this->sum($value);
        return $this->checksum($sum);
    }

    /**
     * Calculate the value sum.
     *
     * @param int|string $value
     * @return int
     */
    private function sum($value)
    {
        $sum = 0;

        for ($i = 0; $i < 12; $i++) {
            if ($i % 2 == 0) {
                $sum += $value[$i];
                continue;
            }

            $sum += 3 * $value[$i];
        }

        return $sum;
    }

    /**
     * Calculate the checksum for the value's sum.
     *
     * @param int $sum
     * @return int|string
     */
    private function checksum($sum)
    {
        $checksum = 10 - ($sum % 10);

        if ($checksum == 10) {
            return '0';
        }

        return $checksum;
    }
}
laminas-validator/src/Isbn/Isbn10.php000064400000002255147361032560013415 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-validator for the canonical source repository
 * @copyright https://github.com/laminas/laminas-validator/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-validator/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Validator\Isbn;

class Isbn10
{
    /**
     * @param int|string $value
     * @return int|string
     */
    public function getChecksum($value)
    {
        $sum = $this->sum($value);
        return $this->checksum($sum);
    }

    /**
     * Calculate the value sum.
     *
     * @param int|string $value
     * @return int
     */
    private function sum($value)
    {
        $sum = 0;

        for ($i = 0; $i < 9; $i++) {
            $sum += (10 - $i) * $value[$i];
        }

        return $sum;
    }

    /**
     * Calculate the checksum for the value's sum.
     *
     * @param int $sum
     * @return int|string
     */
    private function checksum($sum)
    {
        $checksum = 11 - ($sum % 11);

        if ($checksum == 11) {
            return '0';
        }

        if ($checksum == 10) {
            return 'X';
        }

        return $checksum;
    }
}
laminas-validator/src/Identical.php000064400000011670147361032560013363 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-validator for the canonical source repository
 * @copyright https://github.com/laminas/laminas-validator/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-validator/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Validator;

use ArrayAccess;
use Laminas\Stdlib\ArrayUtils;
use Traversable;

class Identical extends AbstractValidator
{
    /**
     * Error codes
     * @const string
     */
    const NOT_SAME      = 'notSame';
    const MISSING_TOKEN = 'missingToken';

    /**
     * Error messages
     * @var array
     */
    protected $messageTemplates = [
        self::NOT_SAME      => 'The two given tokens do not match',
        self::MISSING_TOKEN => 'No token was provided to match against',
    ];

    /**
     * @var array
     */
    protected $messageVariables = [
        'token' => 'tokenString',
    ];

    /**
     * Original token against which to validate
     * @var string
     */
    protected $tokenString;
    protected $token;
    protected $strict  = true;
    protected $literal = false;

    /**
     * Sets validator options
     *
     * @param  mixed $token
     */
    public function __construct($token = null)
    {
        if ($token instanceof Traversable) {
            $token = ArrayUtils::iteratorToArray($token);
        }

        if (is_array($token) && array_key_exists('token', $token)) {
            if (array_key_exists('strict', $token)) {
                $this->setStrict($token['strict']);
            }

            if (array_key_exists('literal', $token)) {
                $this->setLiteral($token['literal']);
            }

            $this->setToken($token['token']);
        } elseif (null !== $token) {
            $this->setToken($token);
        }

        parent::__construct(is_array($token) ? $token : null);
    }

    /**
     * Retrieve token
     *
     * @return mixed
     */
    public function getToken()
    {
        return $this->token;
    }

    /**
     * Set token against which to compare
     *
     * @param  mixed $token
     * @return $this
     */
    public function setToken($token)
    {
        $this->tokenString = is_array($token) ? var_export($token, true) : (string) $token;
        $this->token       = $token;
        return $this;
    }

    /**
     * Returns the strict parameter
     *
     * @return bool
     */
    public function getStrict()
    {
        return $this->strict;
    }

    /**
     * Sets the strict parameter
     *
     * @param  bool $strict
     * @return $this
     */
    public function setStrict($strict)
    {
        $this->strict = (bool) $strict;
        return $this;
    }

    /**
     * Returns the literal parameter
     *
     * @return bool
     */
    public function getLiteral()
    {
        return $this->literal;
    }

    /**
     * Sets the literal parameter
     *
     * @param  bool $literal
     * @return $this
     */
    public function setLiteral($literal)
    {
        $this->literal = (bool) $literal;
        return $this;
    }

    /**
     * Returns true if and only if a token has been set and the provided value
     * matches that token.
     *
     * @param  mixed $value
     * @param  array|ArrayAccess $context
     * @throws Exception\InvalidArgumentException If context is not array or ArrayObject
     * @return bool
     */
    public function isValid($value, $context = null)
    {
        $this->setValue($value);

        $token = $this->getToken();

        if (! $this->getLiteral() && $context !== null) {
            if (! is_array($context) && ! $context instanceof ArrayAccess) {
                throw new Exception\InvalidArgumentException(sprintf(
                    'Context passed to %s must be array, ArrayObject or null; received "%s"',
                    __METHOD__,
                    is_object($context) ? get_class($context) : gettype($context)
                ));
            }

            if (is_array($token)) {
                while (is_array($token)) {
                    $key = key($token);
                    if (! isset($context[$key])) {
                        break;
                    }
                    $context = $context[$key];
                    $token   = $token[$key];
                }
            }

            // if $token is an array it means the above loop didn't went all the way down to the leaf,
            // so the $token structure doesn't match the $context structure
            if (is_array($token) || ! isset($context[$token])) {
                $token = $this->getToken();
            } else {
                $token = $context[$token];
            }
        }

        if ($token === null) {
            $this->error(self::MISSING_TOKEN);
            return false;
        }

        $strict = $this->getStrict();
        if (($strict && ($value !== $token)) || (! $strict && ($value != $token))) {
            $this->error(self::NOT_SAME);
            return false;
        }

        return true;
    }
}
laminas-validator/src/ValidatorProviderInterface.php000064400000001765147361032560016754 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-validator for the canonical source repository
 * @copyright https://github.com/laminas/laminas-validator/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-validator/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Validator;

/**
 * Hint to the laminas-modulemanager ServiceListener that a module provides validators.
 *
 * Module classes implementing this interface hint to
 * Laminas\ModuleManager\ServiceListener that they provide validators for the
 * ValidatorPluginManager.
 *
 * For users of laminas-mvc/laminas-modulemanager v2, this poses no backwards-compatibility
 * break as the method getValidatorConfig is still duck-typed within Laminas\Validator\Module
 * when providing configuration to the ServiceListener.
 */
interface ValidatorProviderInterface
{
    /**
     * Provide plugin manager configuration for validators.
     *
     * @return array
     */
    public function getValidatorConfig();
}
laminas-validator/src/Date.php000064400000013044147361032560012341 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-validator for the canonical source repository
 * @copyright https://github.com/laminas/laminas-validator/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-validator/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Validator;

use DateTime;
use DateTimeImmutable;
use Traversable;

/**
 * Validates that a given value is a DateTime instance or can be converted into one.
 */
class Date extends AbstractValidator
{
    /**#@+
     * Validity constants
     * @var string
     */
    const INVALID        = 'dateInvalid';
    const INVALID_DATE   = 'dateInvalidDate';
    const FALSEFORMAT    = 'dateFalseFormat';
    /**#@-*/

    /**
     * Default format constant
     * @var string
     */
    const FORMAT_DEFAULT = 'Y-m-d';

    /**
     * Validation failure message template definitions
     *
     * @var array
     */
    protected $messageTemplates = [
        self::INVALID      => 'Invalid type given. String, integer, array or DateTime expected',
        self::INVALID_DATE => 'The input does not appear to be a valid date',
        self::FALSEFORMAT  => "The input does not fit the date format '%format%'",
    ];

    /**
     * @var array
     */
    protected $messageVariables = [
        'format' => 'format',
    ];

    /**
     * @var string
     */
    protected $format = self::FORMAT_DEFAULT;

    /**
     * @var bool
     */
    protected $strict = false;

    /**
     * Sets validator options
     *
     * @param  string|array|Traversable $options OPTIONAL
     */
    public function __construct($options = [])
    {
        if ($options instanceof Traversable) {
            $options = iterator_to_array($options);
        } elseif (! is_array($options)) {
            $options = func_get_args();
            $temp['format'] = array_shift($options);
            $options = $temp;
        }

        parent::__construct($options);
    }

    /**
     * Returns the format option
     *
     * @return string|null
     */
    public function getFormat()
    {
        return $this->format;
    }

    /**
     * Sets the format option
     *
     * Format cannot be null.  It will always default to 'Y-m-d', even
     * if null is provided.
     *
     * @param  string $format
     * @return $this provides a fluent interface
     * @todo   validate the format
     */
    public function setFormat($format = self::FORMAT_DEFAULT)
    {
        $this->format = empty($format) ? self::FORMAT_DEFAULT : $format;
        return $this;
    }

    public function setStrict(bool $strict) : self
    {
        $this->strict = $strict;
        return $this;
    }

    public function isStrict() : bool
    {
        return $this->strict;
    }

    /**
     * Returns true if $value is a DateTime instance or can be converted into one.
     *
     * @param  string|array|int|DateTime $value
     * @return bool
     */
    public function isValid($value)
    {
        $this->setValue($value);

        $date = $this->convertToDateTime($value);
        if (! $date) {
            $this->error(self::INVALID_DATE);
            return false;
        }

        if ($this->isStrict() && $date->format($this->getFormat()) !== $value) {
            $this->error(self::FALSEFORMAT);
            return false;
        }

        return true;
    }

    /**
     * Attempts to convert an int, string, or array to a DateTime object
     *
     * @param  string|int|array $param
     * @param  bool             $addErrors
     * @return bool|DateTime
     */
    protected function convertToDateTime($param, $addErrors = true)
    {
        if ($param instanceof DateTime || $param instanceof DateTimeImmutable) {
            return $param;
        }

        $type = gettype($param);
        if (! in_array($type, ['string', 'integer', 'double', 'array'])) {
            if ($addErrors) {
                $this->error(self::INVALID);
            }
            return false;
        }

        $convertMethod = 'convert' . ucfirst($type);
        return $this->{$convertMethod}($param, $addErrors);
    }

    /**
     * Attempts to convert an integer into a DateTime object
     *
     * @param  integer $value
     * @return bool|DateTime
     */
    protected function convertInteger($value)
    {
        return date_create("@$value");
    }

    /**
     * Attempts to convert an double into a DateTime object
     *
     * @param  double $value
     * @return bool|DateTime
     */
    protected function convertDouble($value)
    {
        return DateTime::createFromFormat('U', $value);
    }

    /**
     * Attempts to convert a string into a DateTime object
     *
     * @param  string $value
     * @param  bool   $addErrors
     * @return bool|DateTime
     */
    protected function convertString($value, $addErrors = true)
    {
        $date = DateTime::createFromFormat($this->format, $value);

        // Invalid dates can show up as warnings (ie. "2007-02-99")
        // and still return a DateTime object.
        $errors = DateTime::getLastErrors();
        if ($errors['warning_count'] > 0) {
            if ($addErrors) {
                $this->error(self::FALSEFORMAT);
            }
            return false;
        }

        return $date;
    }

    /**
     * Implodes the array into a string and proxies to {@link convertString()}.
     *
     * @param  array $value
     * @param  bool  $addErrors
     * @return bool|DateTime
     * @todo   enhance the implosion
     */
    protected function convertArray(array $value, $addErrors = true)
    {
        return $this->convertString(implode('-', $value), $addErrors);
    }
}
laminas-validator/src/Barcode/Upca.php000064400000001112147361032560013704 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-validator for the canonical source repository
 * @copyright https://github.com/laminas/laminas-validator/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-validator/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Validator\Barcode;

class Upca extends AbstractAdapter
{
    /**
     * Constructor for this barcode adapter
     */
    public function __construct()
    {
        $this->setLength(12);
        $this->setCharacters('0123456789');
        $this->setChecksum('gtin');
    }
}
laminas-validator/src/Barcode/Code25.php000064400000001161147361032560014041 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-validator for the canonical source repository
 * @copyright https://github.com/laminas/laminas-validator/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-validator/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Validator\Barcode;

class Code25 extends AbstractAdapter
{
    /**
     * Constructor for this barcode adapter
     */
    public function __construct()
    {
        $this->setLength(-1);
        $this->setCharacters('0123456789');
        $this->setChecksum('code25');
        $this->useChecksum(false);
    }
}
laminas-validator/src/Barcode/Gtin14.php000064400000001114147361032560014064 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-validator for the canonical source repository
 * @copyright https://github.com/laminas/laminas-validator/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-validator/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Validator\Barcode;

class Gtin14 extends AbstractAdapter
{
    /**
     * Constructor for this barcode adapter
     */
    public function __construct()
    {
        $this->setLength(14);
        $this->setCharacters('0123456789');
        $this->setChecksum('gtin');
    }
}
laminas-validator/src/Barcode/Ean14.php000064400000001113147361032560013665 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-validator for the canonical source repository
 * @copyright https://github.com/laminas/laminas-validator/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-validator/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Validator\Barcode;

class Ean14 extends AbstractAdapter
{
    /**
     * Constructor for this barcode adapter
     */
    public function __construct()
    {
        $this->setLength(14);
        $this->setCharacters('0123456789');
        $this->setChecksum('gtin');
    }
}
laminas-validator/src/Barcode/Planet.php000064400000001125147361032560014243 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-validator for the canonical source repository
 * @copyright https://github.com/laminas/laminas-validator/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-validator/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Validator\Barcode;

class Planet extends AbstractAdapter
{
    /**
     * Constructor for this barcode adapter
     */
    public function __construct()
    {
        $this->setLength([12, 14]);
        $this->setCharacters('0123456789');
        $this->setChecksum('postnet');
    }
}
laminas-validator/src/Barcode/Leitcode.php000064400000001123147361032560014546 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-validator for the canonical source repository
 * @copyright https://github.com/laminas/laminas-validator/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-validator/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Validator\Barcode;

class Leitcode extends AbstractAdapter
{
    /**
     * Constructor for this barcode adapter
     */
    public function __construct()
    {
        $this->setLength(14);
        $this->setCharacters('0123456789');
        $this->setChecksum('identcode');
    }
}
laminas-validator/src/Barcode/Identcode.php000064400000001604147361032560014720 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-validator for the canonical source repository
 * @copyright https://github.com/laminas/laminas-validator/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-validator/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Validator\Barcode;

class Identcode extends AbstractAdapter
{
    /**
     * Allowed barcode lengths
     * @var int
     */
    protected $length = 12;

    /**
     * Allowed barcode characters
     * @var string
     */
    protected $characters = '0123456789';

    /**
     * Checksum function
     * @var string
     */
    protected $checksum = 'identcode';

    /**
     * Constructor for this barcode adapter
     */
    public function __construct()
    {
        $this->setLength(12);
        $this->setCharacters('0123456789');
        $this->setChecksum('identcode');
    }
}
laminas-validator/src/Barcode/Code93.php000064400000004532147361032560014053 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-validator for the canonical source repository
 * @copyright https://github.com/laminas/laminas-validator/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-validator/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Validator\Barcode;

class Code93 extends AbstractAdapter
{
    /**
     * Note that the characters !"§& are only synonyms
     * @var array
     */
    protected $check = [
        '0' => 0, '1' => 1, '2' => 2, '3' => 3, '4' => 4, '5' => 5, '6' => 6,
        '7' => 7, '8' => 8, '9' => 9, 'A' => 10, 'B' => 11, 'C' => 12, 'D' => 13,
        'E' => 14, 'F' => 15, 'G' => 16, 'H' => 17, 'I' => 18, 'J' => 19, 'K' => 20,
        'L' => 21, 'M' => 22, 'N' => 23, 'O' => 24, 'P' => 25, 'Q' => 26, 'R' => 27,
        'S' => 28, 'T' => 29, 'U' => 30, 'V' => 31, 'W' => 32, 'X' => 33, 'Y' => 34,
        'Z' => 35, '-' => 36, '.' => 37, ' ' => 38, '$' => 39, '/' => 40, '+' => 41,
        '%' => 42, '!' => 43, '"' => 44, '§' => 45, '&' => 46,
    ];

    /**
     * Constructor for this barcode adapter
     */
    public function __construct()
    {
        $this->setLength(-1);
        $this->setCharacters('0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ -.$/+%');
        $this->setChecksum('code93');
        $this->useChecksum(false);
    }

    /**
     * Validates the checksum (Modulo CK)
     *
     * @param  string $value The barcode to validate
     * @return bool
     */
    protected function code93($value)
    {
        $checksum = substr($value, -2, 2);
        $value    = str_split(substr($value, 0, -2));
        $count    = 0;
        $length   = count($value) % 20;
        foreach ($value as $char) {
            if ($length == 0) {
                $length = 20;
            }

            $count += $this->check[$char] * $length;
            --$length;
        }

        $check   = array_search($count % 47, $this->check);
        $value[] = $check;
        $count   = 0;
        $length  = count($value) % 15;
        foreach ($value as $char) {
            if ($length == 0) {
                $length = 15;
            }

            $count += $this->check[$char] * $length;
            --$length;
        }
        $check .= array_search($count % 47, $this->check);

        if ($check == $checksum) {
            return true;
        }

        return false;
    }
}
laminas-validator/src/Barcode/AdapterInterface.php000064400000003034147361032560016222 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-validator for the canonical source repository
 * @copyright https://github.com/laminas/laminas-validator/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-validator/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Validator\Barcode;

interface AdapterInterface
{
    /**
     * Checks the length of a barcode
     *
     * @param  string $value  The barcode to check for proper length
     * @return bool
     */
    public function hasValidLength($value);

    /**
     * Checks for allowed characters within the barcode
     *
     * @param  string $value The barcode to check for allowed characters
     * @return bool
     */
    public function hasValidCharacters($value);

    /**
     * Validates the checksum
     *
     * @param string $value The barcode to check the checksum for
     * @return bool
     */
    public function hasValidChecksum($value);

    /**
     * Returns the allowed barcode length
     *
     * @return int|array
     */
    public function getLength();

    /**
     * Returns the allowed characters
     *
     * @return int|string|array
     */
    public function getCharacters();

    /**
     * Returns if barcode uses a checksum
     *
     * @return bool
     */
    public function getChecksum();

    /**
     * Sets the checksum validation, if no value is given, the actual setting is returned
     *
     * @param  bool $check
     * @return AbstractAdapter|bool
     */
    public function useChecksum($check = null);
}
laminas-validator/src/Barcode/Code39ext.php000064400000001105147361032560014565 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-validator for the canonical source repository
 * @copyright https://github.com/laminas/laminas-validator/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-validator/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Validator\Barcode;

class Code39ext extends AbstractAdapter
{
    /**
     * Constructor for this barcode adapter
     */
    public function __construct()
    {
        $this->setLength(-1);
        $this->setCharacters(128);
        $this->useChecksum(false);
    }
}
laminas-validator/src/Barcode/Royalmail.php000064400000005475147361032560014765 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-validator for the canonical source repository
 * @copyright https://github.com/laminas/laminas-validator/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-validator/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Validator\Barcode;

class Royalmail extends AbstractAdapter
{
    protected $rows = [
        '0' => 1, '1' => 1, '2' => 1, '3' => 1, '4' => 1, '5' => 1,
        '6' => 2, '7' => 2, '8' => 2, '9' => 2, 'A' => 2, 'B' => 2,
        'C' => 3, 'D' => 3, 'E' => 3, 'F' => 3, 'G' => 3, 'H' => 3,
        'I' => 4, 'J' => 4, 'K' => 4, 'L' => 4, 'M' => 4, 'N' => 4,
        'O' => 5, 'P' => 5, 'Q' => 5, 'R' => 5, 'S' => 5, 'T' => 5,
        'U' => 0, 'V' => 0, 'W' => 0, 'X' => 0, 'Y' => 0, 'Z' => 0,
     ];

    protected $columns = [
        '0' => 1, '1' => 2, '2' => 3, '3' => 4, '4' => 5, '5' => 0,
        '6' => 1, '7' => 2, '8' => 3, '9' => 4, 'A' => 5, 'B' => 0,
        'C' => 1, 'D' => 2, 'E' => 3, 'F' => 4, 'G' => 5, 'H' => 0,
        'I' => 1, 'J' => 2, 'K' => 3, 'L' => 4, 'M' => 5, 'N' => 0,
        'O' => 1, 'P' => 2, 'Q' => 3, 'R' => 4, 'S' => 5, 'T' => 0,
        'U' => 1, 'V' => 2, 'W' => 3, 'X' => 4, 'Y' => 5, 'Z' => 0,
    ];

    /**
     * Constructor for this barcode adapter
     */
    public function __construct()
    {
        $this->setLength(-1);
        $this->setCharacters('0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ');
        $this->setChecksum('royalmail');
    }

    /**
     * Validates the checksum ()
     *
     * @param  string $value The barcode to validate
     * @return bool
     */
    protected function royalmail($value)
    {
        $checksum = substr($value, -1, 1);
        $values   = str_split(substr($value, 0, -1));
        $rowvalue = 0;
        $colvalue = 0;
        foreach ($values as $row) {
            $rowvalue += $this->rows[$row];
            $colvalue += $this->columns[$row];
        }

        $rowvalue %= 6;
        $colvalue %= 6;

        $rowchkvalue = array_keys($this->rows, $rowvalue);
        $colchkvalue = array_keys($this->columns, $colvalue);
        $intersect = array_intersect($rowchkvalue, $colchkvalue);
        $chkvalue    = current($intersect);
        if ($chkvalue == $checksum) {
            return true;
        }

        return false;
    }

    /**
     * Allows start and stop tag within checked chars
     *
     * @param  string $value The barcode to check for allowed characters
     * @return bool
     */
    public function hasValidCharacters($value)
    {
        if ($value[0] == '(') {
            $value = substr($value, 1);

            if ($value[strlen($value) - 1] == ')') {
                $value = substr($value, 0, -1);
            } else {
                return false;
            }
        }

        return parent::hasValidCharacters($value);
    }
}
laminas-validator/src/Barcode/Itf14.php000064400000001113147361032560013704 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-validator for the canonical source repository
 * @copyright https://github.com/laminas/laminas-validator/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-validator/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Validator\Barcode;

class Itf14 extends AbstractAdapter
{
    /**
     * Constructor for this barcode adapter
     */
    public function __construct()
    {
        $this->setLength(14);
        $this->setCharacters('0123456789');
        $this->setChecksum('gtin');
    }
}
laminas-validator/src/Barcode/Ean2.php000064400000001110147361032560013577 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-validator for the canonical source repository
 * @copyright https://github.com/laminas/laminas-validator/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-validator/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Validator\Barcode;

class Ean2 extends AbstractAdapter
{
    /**
     * Constructor for this barcode adapter
     */
    public function __construct()
    {
        $this->setLength(2);
        $this->setCharacters('0123456789');
        $this->useChecksum(false);
    }
}
laminas-validator/src/Barcode/Ean12.php000064400000001113147361032560013663 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-validator for the canonical source repository
 * @copyright https://github.com/laminas/laminas-validator/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-validator/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Validator\Barcode;

class Ean12 extends AbstractAdapter
{
    /**
     * Constructor for this barcode adapter
     */
    public function __construct()
    {
        $this->setLength(12);
        $this->setCharacters('0123456789');
        $this->setChecksum('gtin');
    }
}
laminas-validator/src/Barcode/Postnet.php000064400000001134147361032560014454 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-validator for the canonical source repository
 * @copyright https://github.com/laminas/laminas-validator/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-validator/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Validator\Barcode;

class Postnet extends AbstractAdapter
{
    /**
     * Constructor for this barcode adapter
     */
    public function __construct()
    {
        $this->setLength([6, 7, 10, 12]);
        $this->setCharacters('0123456789');
        $this->setChecksum('postnet');
    }
}
laminas-validator/src/Barcode/Sscc.php000064400000001112147361032560013707 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-validator for the canonical source repository
 * @copyright https://github.com/laminas/laminas-validator/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-validator/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Validator\Barcode;

class Sscc extends AbstractAdapter
{
    /**
     * Constructor for this barcode adapter
     */
    public function __construct()
    {
        $this->setLength(18);
        $this->setCharacters('0123456789');
        $this->setChecksum('gtin');
    }
}
laminas-validator/src/Barcode/Intelligentmail.php000064400000001161147361032560016141 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-validator for the canonical source repository
 * @copyright https://github.com/laminas/laminas-validator/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-validator/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Validator\Barcode;

class Intelligentmail extends AbstractAdapter
{
    /**
     * Constructor
     *
     * Sets check flag to false.
     */
    public function __construct()
    {
        $this->setLength([20, 25, 29, 31]);
        $this->setCharacters('0123456789');
        $this->useChecksum(false);
    }
}
laminas-validator/src/Barcode/Code93ext.php000064400000001105147361032560014565 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-validator for the canonical source repository
 * @copyright https://github.com/laminas/laminas-validator/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-validator/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Validator\Barcode;

class Code93ext extends AbstractAdapter
{
    /**
     * Constructor for this barcode adapter
     */
    public function __construct()
    {
        $this->setLength(-1);
        $this->setCharacters(128);
        $this->useChecksum(false);
    }
}
laminas-validator/src/Barcode/Code25interleaved.php000064400000001217147361032560016266 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-validator for the canonical source repository
 * @copyright https://github.com/laminas/laminas-validator/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-validator/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Validator\Barcode;

class Code25interleaved extends AbstractAdapter
{
    /**
     * Constructor
     *
     * Sets check flag to false.
     */
    public function __construct()
    {
        $this->setLength('even');
        $this->setCharacters('0123456789');
        $this->setChecksum('code25');
        $this->useChecksum(false);
    }
}
laminas-validator/src/Barcode/Gtin13.php000064400000001114147361032560014063 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-validator for the canonical source repository
 * @copyright https://github.com/laminas/laminas-validator/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-validator/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Validator\Barcode;

class Gtin13 extends AbstractAdapter
{
    /**
     * Constructor for this barcode adapter
     */
    public function __construct()
    {
        $this->setLength(13);
        $this->setCharacters('0123456789');
        $this->setChecksum('gtin');
    }
}
laminas-validator/src/Barcode/Ean8.php000064400000001662147361032560013621 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-validator for the canonical source repository
 * @copyright https://github.com/laminas/laminas-validator/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-validator/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Validator\Barcode;

class Ean8 extends AbstractAdapter
{
    /**
     * Constructor for this barcode adapter
     */
    public function __construct()
    {
        $this->setLength([7, 8]);
        $this->setCharacters('0123456789');
        $this->setChecksum('gtin');
    }

    /**
     * Overrides parent checkLength
     *
     * @param string $value Value
     * @return bool
     */
    public function hasValidLength($value)
    {
        if (strlen($value) == 7) {
            $this->useChecksum(false);
        } else {
            $this->useChecksum(true);
        }

        return parent::hasValidLength($value);
    }
}
laminas-validator/src/Barcode/Issn.php000064400000004211147361032560013733 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-validator for the canonical source repository
 * @copyright https://github.com/laminas/laminas-validator/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-validator/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Validator\Barcode;

class Issn extends AbstractAdapter
{
    /**
     * Constructor for this barcode adapter
     */
    public function __construct()
    {
        $this->setLength([8, 13]);
        $this->setCharacters('0123456789X');
        $this->setChecksum('gtin');
    }

    /**
     * Allows X on length of 8 chars
     *
     * @param  string $value The barcode to check for allowed characters
     * @return bool
     */
    public function hasValidCharacters($value)
    {
        if (strlen($value) != 8) {
            if (strpos($value, 'X') !== false) {
                return false;
            }
        }

        return parent::hasValidCharacters($value);
    }

    /**
     * Validates the checksum
     *
     * @param  string $value The barcode to check the checksum for
     * @return bool
     */
    public function hasValidChecksum($value)
    {
        if (strlen($value) == 8) {
            $this->setChecksum('issn');
        } else {
            $this->setChecksum('gtin');
        }

        return parent::hasValidChecksum($value);
    }

    /**
     * Validates the checksum ()
     * ISSN implementation (reversed mod11)
     *
     * @param  string $value The barcode to validate
     * @return bool
     */
    protected function issn($value)
    {
        $checksum = substr($value, -1, 1);
        $values   = str_split(substr($value, 0, -1));
        $check    = 0;
        $multi    = 8;
        foreach ($values as $token) {
            if ($token == 'X') {
                $token = 10;
            }

            $check += $token * $multi;
            --$multi;
        }

        $check %= 11;
        $check  = $check === 0 ? 0 : 11 - $check;
        if ($check == $checksum) {
            return true;
        } elseif (($check == 10) && ($checksum == 'X')) {
            return true;
        }

        return false;
    }
}
laminas-validator/src/Barcode/Codabar.php000064400000003450147361032560014356 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-validator for the canonical source repository
 * @copyright https://github.com/laminas/laminas-validator/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-validator/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Validator\Barcode;

class Codabar extends AbstractAdapter
{
    /**
     * Constructor for this barcode adapter
     */
    public function __construct()
    {
        $this->setLength(-1);
        $this->setCharacters('0123456789-$:/.+ABCDTN*E');
        $this->useChecksum(false);
    }

    /**
     * Checks for allowed characters
     * @see Laminas\Validator\Barcode.AbstractAdapter::checkChars()
     */
    public function hasValidCharacters($value)
    {
        if (strpbrk($value, 'ABCD')) {
            $first = $value[0];
            if (! strpbrk($first, 'ABCD')) {
                // Missing start char
                return false;
            }

            $last = substr($value, -1, 1);
            if (! strpbrk($last, 'ABCD')) {
                // Missing stop char
                return false;
            }

            $value = substr($value, 1, -1);
        } elseif (strpbrk($value, 'TN*E')) {
            $first = $value[0];
            if (! strpbrk($first, 'TN*E')) {
                // Missing start char
                return false;
            }

            $last = substr($value, -1, 1);
            if (! strpbrk($last, 'TN*E')) {
                // Missing stop char
                return false;
            }

            $value = substr($value, 1, -1);
        }

        $chars  = $this->getCharacters();
        $this->setCharacters('0123456789-$:/.+');
        $result = parent::hasValidCharacters($value);
        $this->setCharacters($chars);
        return $result;
    }
}
laminas-validator/src/Barcode/Ean18.php000064400000001113147361032560013671 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-validator for the canonical source repository
 * @copyright https://github.com/laminas/laminas-validator/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-validator/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Validator\Barcode;

class Ean18 extends AbstractAdapter
{
    /**
     * Constructor for this barcode adapter
     */
    public function __construct()
    {
        $this->setLength(18);
        $this->setCharacters('0123456789');
        $this->setChecksum('gtin');
    }
}
laminas-validator/src/Barcode/Ean5.php000064400000001127147361032560013612 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-validator for the canonical source repository
 * @copyright https://github.com/laminas/laminas-validator/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-validator/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Validator\Barcode;

class Ean5 extends AbstractAdapter
{
    /**
     * Constructor
     *
     * Sets check flag to false.
     */
    public function __construct()
    {
        $this->setLength(5);
        $this->setCharacters('0123456789');
        $this->useChecksum(false);
    }
}
laminas-validator/src/Barcode/Upce.php000064400000001665147361032560013725 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-validator for the canonical source repository
 * @copyright https://github.com/laminas/laminas-validator/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-validator/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Validator\Barcode;

class Upce extends AbstractAdapter
{
    /**
     * Constructor for this barcode adapter
     */
    public function __construct()
    {
        $this->setLength([6, 7, 8]);
        $this->setCharacters('0123456789');
        $this->setChecksum('gtin');
    }

    /**
     * Overrides parent checkLength
     *
     * @param string $value Value
     * @return bool
     */
    public function hasValidLength($value)
    {
        if (strlen($value) != 8) {
            $this->useChecksum(false);
        } else {
            $this->useChecksum(true);
        }

        return parent::hasValidLength($value);
    }
}
laminas-validator/src/Barcode/Code39.php000064400000003360147361032560014051 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-validator for the canonical source repository
 * @copyright https://github.com/laminas/laminas-validator/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-validator/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Validator\Barcode;

class Code39 extends AbstractAdapter
{
    /**
     * @var array
     */
    protected $check = [
        '0' => 0, '1' => 1, '2' => 2, '3' => 3, '4' => 4, '5' => 5, '6' => 6,
        '7' => 7, '8' => 8, '9' => 9, 'A' => 10, 'B' => 11, 'C' => 12, 'D' => 13,
        'E' => 14, 'F' => 15, 'G' => 16, 'H' => 17, 'I' => 18, 'J' => 19, 'K' => 20,
        'L' => 21, 'M' => 22, 'N' => 23, 'O' => 24, 'P' => 25, 'Q' => 26, 'R' => 27,
        'S' => 28, 'T' => 29, 'U' => 30, 'V' => 31, 'W' => 32, 'X' => 33, 'Y' => 34,
        'Z' => 35, '-' => 36, '.' => 37, ' ' => 38, '$' => 39, '/' => 40, '+' => 41,
        '%' => 42,
    ];

    /**
     * Constructor for this barcode adapter
     */
    public function __construct()
    {
        $this->setLength(-1);
        $this->setCharacters('0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ -.$/+%');
        $this->setChecksum('code39');
        $this->useChecksum(false);
    }

    /**
     * Validates the checksum (Modulo 43)
     *
     * @param  string $value The barcode to validate
     * @return bool
     */
    protected function code39($value)
    {
        $checksum = substr($value, -1, 1);
        $value    = str_split(substr($value, 0, -1));
        $count    = 0;
        foreach ($value as $char) {
            $count += $this->check[$char];
        }

        $mod = $count % 43;
        if ($mod == $this->check[$checksum]) {
            return true;
        }

        return false;
    }
}
laminas-validator/src/Barcode/Code128.php000064400000036370147361032560014137 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-validator for the canonical source repository
 * @copyright https://github.com/laminas/laminas-validator/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-validator/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Validator\Barcode;

use Laminas\Stdlib\StringUtils;
use Laminas\Stdlib\StringWrapper\StringWrapperInterface;
use Laminas\Validator\Exception;

class Code128 extends AbstractAdapter
{
    /**
     * The used string wrapper used for basic UTF-8 string functions
     *
     * @var StringWrapperInterface
     */
    protected $utf8StringWrapper;

    /**
     * Constructor for this barcode adapter
     */
    public function __construct()
    {
        $this->setLength(-1);
        $this->setCharacters([
            'A' => [
                 0 => ' ',  1 => '!',  2 => '"',  3 => '#',  4 => '$',  5 => '%',  6 => '&',  7 => "'",
                 8 => '(',  9 => ')', 10 => '*', 11 => '+', 12 => ',', 13 => '-', 14 => '.', 15 => '/',
                16 => '0', 17 => '1', 18 => '2', 19 => '3', 20 => '4', 21 => '5', 22 => '6', 23 => '7',
                24 => '8', 25 => '9', 26 => ':', 27 => ';', 28 => '<', 29 => '=', 30 => '>', 31 => '?',
                32 => '@', 33 => 'A', 34 => 'B', 35 => 'C', 36 => 'D', 37 => 'E', 38 => 'F', 39 => 'G',
                40 => 'H', 41 => 'I', 42 => 'J', 43 => 'K', 44 => 'L', 45 => 'M', 46 => 'N', 47 => 'O',
                48 => 'P', 49 => 'Q', 50 => 'R', 51 => 'S', 52 => 'T', 53 => 'U', 54 => 'V', 55 => 'W',
                56 => 'X', 57 => 'Y', 58 => 'Z', 59 => '[', 60 => '\\', 61 => ']', 62 => '^', 63 => '_',
                64 => 0x00, 65 => 0x01, 66 => 0x02, 67 => 0x03, 68 => 0x04, 69 => 0x05, 70 => 0x06, 71 => 0x07,
                72 => 0x08, 73 => 0x09, 74 => 0x0A, 75 => 0x0B, 76 => 0x0C, 77 => 0x0D, 78 => 0x0E, 79 => 0x0F,
                80 => 0x10, 81 => 0x11, 82 => 0x12, 83 => 0x13, 84 => 0x14, 85 => 0x15, 86 => 0x16, 87 => 0x17,
                88 => 0x18, 89 => 0x19, 90 => 0x1A, 91 => 0x1B, 92 => 0x1C, 93 => 0x1D, 94 => 0x1E, 95 => 0x1F,
                96 => 'Ç', 97 => 'ü', 98 => 'é', 99 => 'â', 100 => 'ä', 101 => 'à', 102 => 'å', 103 => '‡',
               104 => 'ˆ', 105 => '‰', 106 => 'Š'],
            'B' => [
                 0 => ' ',  1 => '!',  2 => '"',  3 => '#',  4 => '$',  5 => '%',  6 => '&',  7 => "'",
                 8 => '(',  9 => ')', 10 => '*', 11 => '+', 12 => ',', 13 => '-', 14 => '.', 15 => '/',
                16 => '0', 17 => '1', 18 => '2', 19 => '3', 20 => '4', 21 => '5', 22 => '6', 23 => '7',
                24 => '8', 25 => '9', 26 => ':', 27 => ';', 28 => '<', 29 => '=', 30 => '>', 31 => '?',
                32 => '@', 33 => 'A', 34 => 'B', 35 => 'C', 36 => 'D', 37 => 'E', 38 => 'F', 39 => 'G',
                40 => 'H', 41 => 'I', 42 => 'J', 43 => 'K', 44 => 'L', 45 => 'M', 46 => 'N', 47 => 'O',
                48 => 'P', 49 => 'Q', 50 => 'R', 51 => 'S', 52 => 'T', 53 => 'U', 54 => 'V', 55 => 'W',
                56 => 'X', 57 => 'Y', 58 => 'Z', 59 => '[', 60 => '\\', 61 => ']', 62 => '^', 63 => '_',
                64 => '`', 65 => 'a', 66 => 'b', 67 => 'c', 68 => 'd', 69 => 'e', 70 => 'f', 71 => 'g',
                72 => 'h', 73 => 'i', 74 => 'j', 75 => 'k', 76 => 'l', 77 => 'm', 78 => 'n', 79 => 'o',
                80 => 'p', 81 => 'q', 82 => 'r', 83 => 's', 84 => 't', 85 => 'u', 86 => 'v', 87 => 'w',
                88 => 'x', 89 => 'y', 90 => 'z', 91 => '{', 92 => '|', 93 => '}', 94 => '~', 95 => 0x7F,
                96 => 'Ç', 97 => 'ü', 98 => 'é', 99 => 'â', 100 => 'ä', 101 => 'à', 102 => 'å', 103 => '‡',
               104 => 'ˆ', 105 => '‰', 106 => 'Š'],
            'C' => [
                 0 => '00',  1 => '01',  2 => '02',  3 => '03',  4 => '04',  5 => '05',  6 => '06',  7 => '07',
                 8 => '08',  9 => '09', 10 => '10', 11 => '11', 12 => '12', 13 => '13', 14 => '14', 15 => '15',
                16 => '16', 17 => '17', 18 => '18', 19 => '19', 20 => '20', 21 => '21', 22 => '22', 23 => '23',
                24 => '24', 25 => '25', 26 => '26', 27 => '27', 28 => '28', 29 => '29', 30 => '30', 31 => '31',
                32 => '32', 33 => '33', 34 => '34', 35 => '35', 36 => '36', 37 => '37', 38 => '38', 39 => '39',
                40 => '40', 41 => '41', 42 => '42', 43 => '43', 44 => '44', 45 => '45', 46 => '46', 47 => '47',
                48 => '48', 49 => '49', 50 => '50', 51 => '51', 52 => '52', 53 => '53', 54 => '54', 55 => '55',
                56 => '56', 57 => '57', 58 => '58', 59 => '59', 60 => '60', 61 => '61', 62 => '62', 63 => '63',
                64 => '64', 65 => '65', 66 => '66', 67 => '67', 68 => '68', 69 => '69', 70 => '70', 71 => '71',
                72 => '72', 73 => '73', 74 => '74', 75 => '75', 76 => '76', 77 => '77', 78 => '78', 79 => '79',
                80 => '80', 81 => '81', 82 => '82', 83 => '83', 84 => '84', 85 => '85', 86 => '86', 87 => '87',
                88 => '88', 89 => '89', 90 => '90', 91 => '91', 92 => '92', 93 => '93', 94 => '94', 95 => '95',
                96 => '96', 97 => '97', 98 => '98', 99 => '99', 100 => 'ä', 101 => 'à', 102 => 'å', 103 => '‡',
               104 => 'ˆ', 105 => '‰', 106 => 'Š']
        ]);
        $this->setChecksum('code128');
    }

    public function setUtf8StringWrapper(StringWrapperInterface $utf8StringWrapper)
    {
        if (! $utf8StringWrapper->isSupported('UTF-8')) {
            throw new Exception\InvalidArgumentException(
                'The string wrapper needs to support UTF-8 character encoding'
            );
        }
        $this->utf8StringWrapper = $utf8StringWrapper;
    }

    /**
     * Get the string wrapper supporting UTF-8 character encoding
     *
     * @return StringWrapperInterface
     */
    public function getUtf8StringWrapper()
    {
        if (! $this->utf8StringWrapper) {
            $this->utf8StringWrapper = StringUtils::getWrapper('UTF-8');
        }
        return $this->utf8StringWrapper;
    }

    /**
     * Checks for allowed characters within the barcode
     *
     * @param  string $value The barcode to check for allowed characters
     * @return bool
     */
    public function hasValidCharacters($value)
    {
        if (! is_string($value)) {
            return false;
        }

        // get used string wrapper for UTF-8 character encoding
        $strWrapper = $this->getUtf8StringWrapper();

        // detect starting charset
        $set        = $this->getCodingSet($value);
        $read       = $set;
        if ($set != '') {
            $value = $strWrapper->substr($value, 1, null);
        }

        // process barcode
        while ($value != '') {
            $char = $strWrapper->substr($value, 0, 1);

            switch ($char) {
                // Function definition
                case 'Ç':
                case 'ü':
                case 'å':
                    break;

                // Switch 1 char between A and B
                case 'é':
                    if ($set == 'A') {
                        $read = 'B';
                    } elseif ($set == 'B') {
                        $read = 'A';
                    }
                    break;

                // Switch to C
                case 'â':
                    $set = 'C';
                    $read = 'C';
                    break;

                // Switch to B
                case 'ä':
                    $set  = 'B';
                    $read = 'B';
                    break;

                // Switch to A
                case 'à':
                    $set  = 'A';
                    $read = 'A';
                    break;

                // Doubled start character
                case '‡':
                case 'ˆ':
                case '‰':
                    return false;

                // Chars after the stop character
                case 'Š':
                    break 2;

                default:
                    // Does the char exist within the charset to read?
                    if ($this->ord128($char, $read) == -1) {
                        return false;
                    }

                    break;
            }

            $value = $strWrapper->substr($value, 1, null);
            $read  = $set;
        }

        if (($value != '') && ($strWrapper->strlen($value) != 1)) {
            return false;
        }

        return true;
    }

    /**
     * Validates the checksum ()
     *
     * @param  string $value The barcode to validate
     * @return bool
     */
    protected function code128($value)
    {
        $sum        = 0;
        $pos        = 1;
        $set        = $this->getCodingSet($value);
        $read       = $set;
        $usecheck   = $this->useChecksum(null);
        $strWrapper = $this->getUtf8StringWrapper();
        $char       = $strWrapper->substr($value, 0, 1);
        if ($char == '‡') {
            $sum = 103;
        } elseif ($char == 'ˆ') {
            $sum = 104;
        } elseif ($char == '‰') {
            $sum = 105;
        } elseif ($usecheck == true) {
            // no start value, unable to detect a proper checksum
            return false;
        }

        $value = $strWrapper->substr($value, 1, null);
        while ($strWrapper->strpos($value, 'Š') || ($value != '')) {
            $char = $strWrapper->substr($value, 0, 1);
            if ($read == 'C') {
                $char = $strWrapper->substr($value, 0, 2);
            }

            switch ($char) {
                // Function definition
                case 'Ç':
                case 'ü':
                case 'å':
                    $sum += $pos * $this->ord128($char, $set);
                    break;

                case 'é':
                    $sum += $pos * $this->ord128($char, $set);
                    if ($set == 'A') {
                        $read = 'B';
                    } elseif ($set == 'B') {
                        $read = 'A';
                    }
                    break;

                // Switch to C
                case 'â':
                    $sum += $pos * $this->ord128($char, $set);
                    $set = 'C';
                    $read = 'C';
                    break;

                // Switch to B
                case 'ä':
                    $sum += $pos * $this->ord128($char, $set);
                    $set  = 'B';
                    $read = 'B';
                    break;

                // Switch to A
                case 'à':
                    $sum += $pos * $this->ord128($char, $set);
                    $set  = 'A';
                    $read = 'A';
                    break;

                case '‡':
                case 'ˆ':
                case '‰':
                    return false;
                    break;

                default:
                    // Does the char exist within the charset to read?
                    if ($this->ord128($char, $read) == -1) {
                        return false;
                    }

                    $sum += $pos * $this->ord128($char, $set);
                    break;
            }

            $value = $strWrapper->substr($value, 1);
            ++$pos;
            if (($strWrapper->strpos($value, 'Š') == 1) && ($strWrapper->strlen($value) == 2)) {
                // break by stop and checksum char
                break;
            }
            $read  = $set;
        }

        if (($strWrapper->strpos($value, 'Š') != 1) || ($strWrapper->strlen($value) != 2)) {
            // return false if checksum is not readable and true if no startvalue is detected
            return ! $usecheck;
        }

        $mod = $sum % 103;
        if ($strWrapper->substr($value, 0, 1) == $this->chr128($mod, $set)) {
            return true;
        }

        return false;
    }

    /**
     * Returns the coding set for a barcode
     *
     * @param string $value Barcode
     * @return string
     */
    protected function getCodingSet($value)
    {
        $value = $this->getUtf8StringWrapper()->substr($value, 0, 1);
        switch ($value) {
            case '‡':
                return 'A';
                break;
            case 'ˆ':
                return 'B';
                break;
            case '‰':
                return 'C';
                break;
        }

        return '';
    }

    /**
     * Internal method to return the code128 integer from an ascii value
     *
     * Table A
     *    ASCII       CODE128
     *  32 to  95 ==  0 to  63
     *   0 to  31 == 64 to  95
     * 128 to 138 == 96 to 106
     *
     * Table B
     *    ASCII       CODE128
     *  32 to 138 == 0 to 106
     *
     * Table C
     *    ASCII       CODE128
     *  "00" to "99" ==   0 to  99
     *   132 to  138 == 100 to 106
     *
     * @param string $value
     * @param string $set
     * @return int
     */
    protected function ord128($value, $set)
    {
        $ord = ord($value);
        if ($set == 'A') {
            if ($ord < 32) {
                return $ord + 64;
            } elseif ($ord < 96) {
                return $ord - 32;
            } elseif ($ord > 138) {
                return -1;
            } else {
                return $ord - 32;
            }
        } elseif ($set == 'B') {
            if ($ord < 32) {
                return -1;
            } elseif ($ord <= 138) {
                return $ord - 32;
            } else {
                return -1;
            }
        } elseif ($set == 'C') {
            $val = (int) $value;
            if (($val >= 0) && ($val <= 99)) {
                return $val;
            } elseif (($ord >= 132) && ($ord <= 138)) {
                return $ord - 32;
            } else {
                return -1;
            }
        } else {
            if ($ord < 32) {
                return $ord + 64;
            } elseif ($ord <= 138) {
                return $ord - 32;
            } else {
                return -1;
            }
        }
    }

    /**
     * Internal Method to return the ascii value from a code128 integer
     *
     * Table A
     *    ASCII       CODE128
     *  32 to  95 ==  0 to  63
     *   0 to  31 == 64 to  95
     * 128 to 138 == 96 to 106
     *
     * Table B
     *    ASCII       CODE128
     *  32 to 138 == 0 to 106
     *
     * Table C
     *    ASCII       CODE128
     *  "00" to "99" ==   0 to  99
     *   132 to  138 == 100 to 106
     *
     * @param int $value
     * @param string $set
     * @return string
     */
    protected function chr128($value, $set)
    {
        if ($set == 'A') {
            if ($value < 64) {
                return chr($value + 32);
            } elseif ($value < 96) {
                return chr($value - 64);
            } elseif ($value > 106) {
                return -1;
            } else {
                return chr($value + 32);
            }
        } elseif ($set == 'B') {
            if ($value > 106) {
                return -1;
            } else {
                return chr($value + 32);
            }
        } elseif ($set == 'C') {
            if (($value >= 0) && ($value <= 9)) {
                return '0' . (string) $value;
            } elseif ($value <= 99) {
                return (string) $value;
            } elseif ($value <= 106) {
                return chr($value + 32);
            } else {
                return -1;
            }
        } else {
            if ($value <= 106) {
                return $value + 32;
            } else {
                return -1;
            }
        }
    }
}
laminas-validator/src/Barcode/Gtin12.php000064400000001114147361032560014062 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-validator for the canonical source repository
 * @copyright https://github.com/laminas/laminas-validator/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-validator/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Validator\Barcode;

class Gtin12 extends AbstractAdapter
{
    /**
     * Constructor for this barcode adapter
     */
    public function __construct()
    {
        $this->setLength(12);
        $this->setCharacters('0123456789');
        $this->setChecksum('gtin');
    }
}
laminas-validator/src/Barcode/Ean13.php000064400000001113147361032560013664 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-validator for the canonical source repository
 * @copyright https://github.com/laminas/laminas-validator/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-validator/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Validator\Barcode;

class Ean13 extends AbstractAdapter
{
    /**
     * Constructor for this barcode adapter
     */
    public function __construct()
    {
        $this->setLength(13);
        $this->setCharacters('0123456789');
        $this->setChecksum('gtin');
    }
}
laminas-validator/src/Barcode/AbstractAdapter.php000064400000016454147361032560016077 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-validator for the canonical source repository
 * @copyright https://github.com/laminas/laminas-validator/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-validator/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Validator\Barcode;

abstract class AbstractAdapter implements AdapterInterface
{
    /**
     * Allowed options for this adapter
     * @var array
     */
    protected $options = [
        'length'     => null,   // Allowed barcode lengths, integer, array, string
        'characters' => null,   // Allowed barcode characters
        'checksum'   => null,   // Callback to checksum function
        'useChecksum' => true,  // Is a checksum value included?, boolean
    ];

    /**
     * Checks the length of a barcode
     *
     * @param  string $value The barcode to check for proper length
     * @return bool
     */
    public function hasValidLength($value)
    {
        if (! is_string($value)) {
            return false;
        }

        $fixum  = strlen($value);
        $found  = false;
        $length = $this->getLength();
        if (is_array($length)) {
            foreach ($length as $value) {
                if ($fixum == $value) {
                    $found = true;
                }

                if ($value == -1) {
                    $found = true;
                }
            }
        } elseif ($fixum == $length) {
            $found = true;
        } elseif ($length == -1) {
            $found = true;
        } elseif ($length == 'even') {
            $count = $fixum % 2;
            $found = 0 == $count;
        } elseif ($length == 'odd') {
            $count = $fixum % 2;
            $found = 1 == $count;
        }

        return $found;
    }

    /**
     * Checks for allowed characters within the barcode
     *
     * @param  string $value The barcode to check for allowed characters
     * @return bool
     */
    public function hasValidCharacters($value)
    {
        if (! is_string($value)) {
            return false;
        }

        $characters = $this->getCharacters();
        if ($characters == 128) {
            for ($x = 0; $x < 128; ++$x) {
                $value = str_replace(chr($x), '', $value);
            }
        } else {
            $chars = str_split($characters);
            foreach ($chars as $char) {
                $value = str_replace($char, '', $value);
            }
        }

        if (strlen($value) > 0) {
            return false;
        }

        return true;
    }

    /**
     * Validates the checksum
     *
     * @param  string $value The barcode to check the checksum for
     * @return bool
     */
    public function hasValidChecksum($value)
    {
        $checksum = $this->getChecksum();
        if (! empty($checksum)) {
            if (method_exists($this, $checksum)) {
                return $this->$checksum($value);
            }
        }

        return false;
    }

    /**
     * Returns the allowed barcode length
     *
     * @return int|array
     */
    public function getLength()
    {
        return $this->options['length'];
    }

    /**
     * Returns the allowed characters
     *
     * @return int|string|array
     */
    public function getCharacters()
    {
        return $this->options['characters'];
    }

    /**
     * Returns the checksum function name
     *
     */
    public function getChecksum()
    {
        return $this->options['checksum'];
    }

    /**
     * Sets the checksum validation method
     *
     * @param callable $checksum Checksum method to call
     * @return $this
     */
    protected function setChecksum($checksum)
    {
        $this->options['checksum'] = $checksum;
        return $this;
    }

    /**
     * Sets the checksum validation, if no value is given, the actual setting is returned
     *
     * @param  bool $check
     * @return AbstractAdapter|bool
     */
    public function useChecksum($check = null)
    {
        if ($check === null) {
            return $this->options['useChecksum'];
        }

        $this->options['useChecksum'] = (bool) $check;
        return $this;
    }

    /**
     * Sets the length of this barcode
     *
     * @param int|array $length
     * @return $this
     */
    protected function setLength($length)
    {
        $this->options['length'] = $length;
        return $this;
    }

    /**
     * Sets the allowed characters of this barcode
     *
     * @param int $characters
     * @return $this
     */
    protected function setCharacters($characters)
    {
        $this->options['characters'] = $characters;
        return $this;
    }

    /**
     * Validates the checksum (Modulo 10)
     * GTIN implementation factor 3
     *
     * @param  string $value The barcode to validate
     * @return bool
     */
    protected function gtin($value)
    {
        $barcode = substr($value, 0, -1);
        $sum     = 0;
        $length  = strlen($barcode) - 1;

        for ($i = 0; $i <= $length; $i++) {
            if (($i % 2) === 0) {
                $sum += $barcode[$length - $i] * 3;
            } else {
                $sum += $barcode[$length - $i];
            }
        }

        $calc     = $sum % 10;
        $checksum = $calc === 0 ? 0 : 10 - $calc;
        if ($value[$length + 1] != $checksum) {
            return false;
        }

        return true;
    }

    /**
     * Validates the checksum (Modulo 10)
     * IDENTCODE implementation factors 9 and 4
     *
     * @param  string $value The barcode to validate
     * @return bool
     */
    protected function identcode($value)
    {
        $barcode = substr($value, 0, -1);
        $sum     = 0;
        $length  = strlen($value) - 2;

        for ($i = 0; $i <= $length; $i++) {
            if (($i % 2) === 0) {
                $sum += $barcode[$length - $i] * 4;
            } else {
                $sum += $barcode[$length - $i] * 9;
            }
        }

        $calc     = $sum % 10;
        $checksum = $calc === 0 ? 0 : 10 - $calc;
        if ($value[$length + 1] != $checksum) {
            return false;
        }

        return true;
    }

    /**
     * Validates the checksum (Modulo 10)
     * CODE25 implementation factor 3
     *
     * @param  string $value The barcode to validate
     * @return bool
     */
    protected function code25($value)
    {
        $barcode = substr($value, 0, -1);
        $sum     = 0;
        $length  = strlen($barcode) - 1;

        for ($i = 0; $i <= $length; $i++) {
            if (($i % 2) === 0) {
                $sum += $barcode[$i] * 3;
            } else {
                $sum += $barcode[$i];
            }
        }

        $calc     = $sum % 10;
        $checksum = $calc === 0 ? 0 : 10 - $calc;
        if ($value[$length + 1] != $checksum) {
            return false;
        }

        return true;
    }

    /**
     * Validates the checksum ()
     * POSTNET implementation
     *
     * @param  string $value The barcode to validate
     * @return bool
     */
    protected function postnet($value)
    {
        $checksum = substr($value, -1, 1);
        $values   = str_split(substr($value, 0, -1));

        $check = 0;
        foreach ($values as $row) {
            $check += $row;
        }

        $check %= 10;
        $check = 10 - $check;
        if ($check == $checksum) {
            return true;
        }

        return false;
    }
}
laminas-validator/src/UndisclosedPassword.php000064400000010236147361032560015463 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-validator for the canonical source repository
 * @copyright https://github.com/laminas/laminas-validator/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-validator/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Validator;

use Psr\Http\Client\ClientExceptionInterface;
use Psr\Http\Client\ClientInterface;
use Psr\Http\Message\RequestFactoryInterface;

use function array_filter;
use function explode;
use function is_string;
use function sha1;
use function strcmp;
use function strtoupper;
use function substr;

final class UndisclosedPassword extends AbstractValidator
{
    private const HIBP_API_URI = 'https://api.pwnedpasswords.com';
    private const HIBP_API_REQUEST_TIMEOUT = 300;
    private const HIBP_CLIENT_USER_AGENT_STRING = 'laminas-validator';
    private const HIBP_CLIENT_ACCEPT_HEADER = 'application/vnd.haveibeenpwned.v2+json';
    private const HIBP_K_ANONYMITY_HASH_RANGE_LENGTH = 5;
    private const HIBP_K_ANONYMITY_HASH_RANGE_BASE = 0;
    private const SHA1_STRING_LENGTH = 40;

    private const PASSWORD_BREACHED = 'passwordBreached';
    private const NOT_A_STRING = 'wrongInput';

    protected $messageTemplates = [
        self::PASSWORD_BREACHED =>
            'The provided password was found in previous breaches, please create another password',
        self::NOT_A_STRING => 'The provided password is not a string, please provide a correct password',
    ];

    /** @var ClientInterface */
    private $httpClient;

    /** @var RequestFactoryInterface */
    private $makeHttpRequest;

    public function __construct(ClientInterface $httpClient, RequestFactoryInterface $makeHttpRequest)
    {
        parent::__construct();

        $this->httpClient = $httpClient;
        $this->makeHttpRequest = $makeHttpRequest;
    }

    /**
     * @inheritDoc
     */
    public function isValid($value) : bool
    {
        if (! is_string($value)) {
            $this->error(self::NOT_A_STRING);
            return false;
        }

        if ($this->isPwnedPassword($value)) {
            $this->error(self::PASSWORD_BREACHED);
            return false;
        }

        return true;
    }

    private function isPwnedPassword(string $password) : bool
    {
        $sha1Hash = $this->hashPassword($password);
        $rangeHash = $this->getRangeHash($sha1Hash);
        $hashList = $this->retrieveHashList($rangeHash);

        return $this->hashInResponse($sha1Hash, $hashList);
    }

    /**
     * We use a SHA1 hashed password for checking it against
     * the breached data set of HIBP.
     */
    private function hashPassword(string $password) : string
    {
        $hashedPassword = sha1($password);

        return strtoupper($hashedPassword);
    }

    /**
     * Creates a hash range that will be send to HIBP API
     * applying K-Anonymity
     *
     * @see https://www.troyhunt.com/enhancing-pwned-passwords-privacy-by-exclusively-supporting-anonymity/
     */
    private function getRangeHash(string $passwordHash) : string
    {
        return substr($passwordHash, self::HIBP_K_ANONYMITY_HASH_RANGE_BASE, self::HIBP_K_ANONYMITY_HASH_RANGE_LENGTH);
    }

    /**
     * Making a connection to the HIBP API to retrieve a
     * list of hashes that all have the same range as we
     * provided.
     *
     * @throws ClientExceptionInterface
     */
    private function retrieveHashList(string $passwordRange) : string
    {
        $request = $this->makeHttpRequest->createRequest(
            'GET',
            self::HIBP_API_URI . '/range/' . $passwordRange
        );

        $response = $this->httpClient->sendRequest($request);
        return (string) $response->getBody();
    }

    /**
     * Checks if the password is in the response from HIBP
     */
    private function hashInResponse(string $sha1Hash, string $resultStream) : bool
    {
        $data = explode("\r\n", $resultStream);
        $hashes = array_filter($data, static function ($value) use ($sha1Hash) {
            [$hash, $count] = explode(':', $value);

            return strcmp($hash, substr($sha1Hash, self::HIBP_K_ANONYMITY_HASH_RANGE_LENGTH)) === 0;
        });

        return $hashes !== [];
    }
}
laminas-validator/src/Digits.php000064400000003444147361032560012712 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-validator for the canonical source repository
 * @copyright https://github.com/laminas/laminas-validator/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-validator/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Validator;

use Laminas\Filter\Digits as DigitsFilter;

class Digits extends AbstractValidator
{
    const NOT_DIGITS   = 'notDigits';
    const STRING_EMPTY = 'digitsStringEmpty';
    const INVALID      = 'digitsInvalid';

    /**
     * Digits filter used for validation
     *
     * @var \Laminas\Filter\Digits
     */
    protected static $filter = null;

    /**
     * Validation failure message template definitions
     *
     * @var array
     */
    protected $messageTemplates = [
        self::NOT_DIGITS   => 'The input must contain only digits',
        self::STRING_EMPTY => 'The input is an empty string',
        self::INVALID      => 'Invalid type given. String, integer or float expected',
    ];

    /**
     * Returns true if and only if $value only contains digit characters
     *
     * @param  string $value
     * @return bool
     */
    public function isValid($value)
    {
        if (! is_string($value) && ! is_int($value) && ! is_float($value)) {
            $this->error(self::INVALID);
            return false;
        }

        $this->setValue((string) $value);

        if ('' === $this->getValue()) {
            $this->error(self::STRING_EMPTY);
            return false;
        }

        if (null === static::$filter) {
            static::$filter = new DigitsFilter();
        }

        if ($this->getValue() !== static::$filter->filter($this->getValue())) {
            $this->error(self::NOT_DIGITS);
            return false;
        }

        return true;
    }
}
laminas-validator/src/Exception/InvalidMagicMimeFileException.php000064400000000626147361032560021242 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-validator for the canonical source repository
 * @copyright https://github.com/laminas/laminas-validator/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-validator/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Validator\Exception;

class InvalidMagicMimeFileException extends InvalidArgumentException
{
}
laminas-validator/src/Exception/ExceptionInterface.php000064400000000556147361032560017205 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-validator for the canonical source repository
 * @copyright https://github.com/laminas/laminas-validator/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-validator/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Validator\Exception;

interface ExceptionInterface
{
}
laminas-validator/src/Exception/InvalidArgumentException.php000064400000000660147361032560020372 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-validator for the canonical source repository
 * @copyright https://github.com/laminas/laminas-validator/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-validator/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Validator\Exception;

class InvalidArgumentException extends \InvalidArgumentException implements ExceptionInterface
{
}
laminas-validator/src/Exception/ExtensionNotLoadedException.php000064400000000614147361032560021046 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-validator for the canonical source repository
 * @copyright https://github.com/laminas/laminas-validator/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-validator/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Validator\Exception;

class ExtensionNotLoadedException extends RuntimeException
{
}
laminas-validator/src/Exception/BadMethodCallException.php000064400000000654147361032560017727 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-validator for the canonical source repository
 * @copyright https://github.com/laminas/laminas-validator/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-validator/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Validator\Exception;

class BadMethodCallException extends \BadMethodCallException implements ExceptionInterface
{
}
laminas-validator/src/Exception/RuntimeException.php000064400000000640147361032560016722 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-validator for the canonical source repository
 * @copyright https://github.com/laminas/laminas-validator/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-validator/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Validator\Exception;

class RuntimeException extends \RuntimeException implements ExceptionInterface
{
}
laminas-validator/src/CreditCard.php000064400000024561147361032560013476 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-validator for the canonical source repository
 * @copyright https://github.com/laminas/laminas-validator/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-validator/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Validator;

use Laminas\Stdlib\ArrayUtils;
use Traversable;

class CreditCard extends AbstractValidator
{
    /**
     * Detected CCI list
     *
     * @var string
     */
    const ALL              = 'All';
    const AMERICAN_EXPRESS = 'American_Express';
    const UNIONPAY         = 'Unionpay';
    const DINERS_CLUB      = 'Diners_Club';
    const DINERS_CLUB_US   = 'Diners_Club_US';
    const DISCOVER         = 'Discover';
    const JCB              = 'JCB';
    const LASER            = 'Laser';
    const MAESTRO          = 'Maestro';
    const MASTERCARD       = 'Mastercard';
    const SOLO             = 'Solo';
    const VISA             = 'Visa';
    const MIR              = 'Mir';

    const CHECKSUM       = 'creditcardChecksum';
    const CONTENT        = 'creditcardContent';
    const INVALID        = 'creditcardInvalid';
    const LENGTH         = 'creditcardLength';
    const PREFIX         = 'creditcardPrefix';
    const SERVICE        = 'creditcardService';
    const SERVICEFAILURE = 'creditcardServiceFailure';

    /**
     * Validation failure message template definitions
     *
     * @var array
     */
    protected $messageTemplates = [
        self::CHECKSUM       => 'The input seems to contain an invalid checksum',
        self::CONTENT        => 'The input must contain only digits',
        self::INVALID        => 'Invalid type given. String expected',
        self::LENGTH         => 'The input contains an invalid amount of digits',
        self::PREFIX         => 'The input is not from an allowed institute',
        self::SERVICE        => 'The input seems to be an invalid credit card number',
        self::SERVICEFAILURE => 'An exception has been raised while validating the input',
    ];

    /**
     * List of CCV names
     *
     * @var array
     */
    protected $cardName = [
        0  => self::AMERICAN_EXPRESS,
        1  => self::DINERS_CLUB,
        2  => self::DINERS_CLUB_US,
        3  => self::DISCOVER,
        4  => self::JCB,
        5  => self::LASER,
        6  => self::MAESTRO,
        7  => self::MASTERCARD,
        8  => self::SOLO,
        9  => self::UNIONPAY,
        10 => self::VISA,
        11 => self::MIR,
    ];

    /**
     * List of allowed CCV lengths
     *
     * @var array
     */
    protected $cardLength = [
        self::AMERICAN_EXPRESS => [15],
        self::DINERS_CLUB      => [14],
        self::DINERS_CLUB_US   => [16],
        self::DISCOVER         => [16, 19],
        self::JCB              => [15, 16],
        self::LASER            => [16, 17, 18, 19],
        self::MAESTRO          => [12, 13, 14, 15, 16, 17, 18, 19],
        self::MASTERCARD       => [16],
        self::SOLO             => [16, 18, 19],
        self::UNIONPAY         => [16, 17, 18, 19],
        self::VISA             => [13, 16, 19],
        self::MIR              => [13, 16],
    ];

    /**
     * List of accepted CCV provider tags
     *
     * @var array
     */
    protected $cardType = [
        self::AMERICAN_EXPRESS => ['34', '37'],
        self::DINERS_CLUB      => ['300', '301', '302', '303', '304', '305', '36'],
        self::DINERS_CLUB_US   => ['54', '55'],
        self::DISCOVER         => ['6011', '622126', '622127', '622128', '622129', '62213',
                                        '62214', '62215', '62216', '62217', '62218', '62219',
                                        '6222', '6223', '6224', '6225', '6226', '6227', '6228',
                                        '62290', '62291', '622920', '622921', '622922', '622923',
                                        '622924', '622925', '644', '645', '646', '647', '648',
                                        '649', '65'],
        self::JCB              => ['1800', '2131', '3528', '3529', '353', '354', '355', '356', '357', '358'],
        self::LASER            => ['6304', '6706', '6771', '6709'],
        self::MAESTRO          => ['5018', '5020', '5038', '6304', '6759', '6761', '6762', '6763',
                                        '6764', '6765', '6766', '6772'],
        self::MASTERCARD       => ['2221', '2222', '2223', '2224', '2225', '2226', '2227', '2228', '2229',
                                        '223', '224', '225', '226', '227', '228', '229',
                                        '23', '24', '25', '26', '271', '2720',
                                        '51', '52', '53', '54', '55'],
        self::SOLO             => ['6334', '6767'],
        self::UNIONPAY         => ['622126', '622127', '622128', '622129', '62213', '62214',
                                        '62215', '62216', '62217', '62218', '62219', '6222', '6223',
                                        '6224', '6225', '6226', '6227', '6228', '62290', '62291',
                                        '622920', '622921', '622922', '622923', '622924', '622925'],
        self::VISA             => ['4'],
        self::MIR              => ['2200', '2201', '2202', '2203', '2204'],
    ];

    /**
     * Options for this validator
     *
     * @var array
     */
    protected $options = [
        'service' => null,     // Service callback for additional validation
        'type'    => [],  // CCIs which are accepted by validation
    ];

    /**
     * Constructor
     *
     * @param string|array|Traversable $options OPTIONAL Type of CCI to allow
     */
    public function __construct($options = [])
    {
        if ($options instanceof Traversable) {
            $options = ArrayUtils::iteratorToArray($options);
        } elseif (! is_array($options)) {
            $options = func_get_args();
            $temp['type'] = array_shift($options);
            if (! empty($options)) {
                $temp['service'] = array_shift($options);
            }

            $options = $temp;
        }

        if (! array_key_exists('type', $options)) {
            $options['type'] = self::ALL;
        }

        $this->setType($options['type']);
        unset($options['type']);

        if (array_key_exists('service', $options)) {
            $this->setService($options['service']);
            unset($options['service']);
        }

        parent::__construct($options);
    }

    /**
     * Returns a list of accepted CCIs
     *
     * @return array
     */
    public function getType()
    {
        return $this->options['type'];
    }

    /**
     * Sets CCIs which are accepted by validation
     *
     * @param  string|array $type Type to allow for validation
     * @return CreditCard Provides a fluid interface
     */
    public function setType($type)
    {
        $this->options['type'] = [];
        return $this->addType($type);
    }

    /**
     * Adds a CCI to be accepted by validation
     *
     * @param  string|array $type Type to allow for validation
     * @return $this Provides a fluid interface
     */
    public function addType($type)
    {
        if (is_string($type)) {
            $type = [$type];
        }

        foreach ($type as $typ) {
            if ($typ == self::ALL) {
                $this->options['type'] = array_keys($this->cardLength);
                continue;
            }

            if (in_array($typ, $this->options['type'])) {
                continue;
            }

            $constant = 'static::' . strtoupper($typ);
            if (! defined($constant) || in_array(constant($constant), $this->options['type'])) {
                continue;
            }
            $this->options['type'][] = constant($constant);
        }

        return $this;
    }

    /**
     * Returns the actual set service
     *
     * @return callable
     */
    public function getService()
    {
        return $this->options['service'];
    }

    /**
     * Sets a new callback for service validation
     *
     * @param  callable $service
     * @return $this
     * @throws Exception\InvalidArgumentException on invalid service callback
     */
    public function setService($service)
    {
        if (! is_callable($service)) {
            throw new Exception\InvalidArgumentException('Invalid callback given');
        }

        $this->options['service'] = $service;
        return $this;
    }

    /**
     * Returns true if and only if $value follows the Luhn algorithm (mod-10 checksum)
     *
     * @param  string $value
     * @return bool
     */
    public function isValid($value)
    {
        $this->setValue($value);

        if (! is_string($value)) {
            $this->error(self::INVALID, $value);
            return false;
        }

        if (! ctype_digit($value)) {
            $this->error(self::CONTENT, $value);
            return false;
        }

        $length = strlen($value);
        $types  = $this->getType();
        $foundp = false;
        $foundl = false;
        foreach ($types as $type) {
            foreach ($this->cardType[$type] as $prefix) {
                if (0 === strpos($value, $prefix)) {
                    $foundp = true;
                    if (in_array($length, $this->cardLength[$type])) {
                        $foundl = true;
                        break 2;
                    }
                }
            }
        }

        if ($foundp == false) {
            $this->error(self::PREFIX, $value);
            return false;
        }

        if ($foundl == false) {
            $this->error(self::LENGTH, $value);
            return false;
        }

        $sum    = 0;
        $weight = 2;

        for ($i = $length - 2; $i >= 0; $i--) {
            $digit = $weight * $value[$i];
            $sum += floor($digit / 10) + $digit % 10;
            $weight = $weight % 2 + 1;
        }

        if ((10 - $sum % 10) % 10 != $value[$length - 1]) {
            $this->error(self::CHECKSUM, $value);
            return false;
        }

        $service = $this->getService();
        if (! empty($service)) {
            try {
                $callback = new Callback($service);
                $callback->setOptions($this->getType());
                if (! $callback->isValid($value)) {
                    $this->error(self::SERVICE, $value);
                    return false;
                }
            } catch (\Exception $e) {
                $this->error(self::SERVICEFAILURE, $value);
                return false;
            }
        }

        return true;
    }
}
laminas-validator/src/Step.php000064400000007710147361032560012402 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-validator for the canonical source repository
 * @copyright https://github.com/laminas/laminas-validator/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-validator/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Validator;

use Traversable;

class Step extends AbstractValidator
{
    const INVALID = 'typeInvalid';
    const NOT_STEP = 'stepInvalid';

    /**
     * @var array
     */
    protected $messageTemplates = [
        self::INVALID => 'Invalid value given. Scalar expected',
        self::NOT_STEP => 'The input is not a valid step',
    ];

    /**
     * @var mixed
     */
    protected $baseValue = 0;

    /**
     * @var mixed
     */
    protected $step = 1;

    /**
     * Set default options for this instance
     *
     * @param array $options
     */
    public function __construct($options = [])
    {
        if ($options instanceof Traversable) {
            $options = iterator_to_array($options);
        } elseif (! is_array($options)) {
            $options = func_get_args();
            $temp['baseValue'] = array_shift($options);
            if (! empty($options)) {
                $temp['step'] = array_shift($options);
            }

            $options = $temp;
        }

        if (isset($options['baseValue'])) {
            $this->setBaseValue($options['baseValue']);
        }
        if (isset($options['step'])) {
            $this->setStep($options['step']);
        }

        parent::__construct($options);
    }

    /**
     * Sets the base value from which the step should be computed
     *
     * @param mixed $baseValue
     * @return $this
     */
    public function setBaseValue($baseValue)
    {
        $this->baseValue = $baseValue;
        return $this;
    }

    /**
     * Returns the base value from which the step should be computed
     *
     * @return string
     */
    public function getBaseValue()
    {
        return $this->baseValue;
    }

    /**
     * Sets the step value
     *
     * @param mixed $step
     * @return $this
     */
    public function setStep($step)
    {
        $this->step = (float) $step;
        return $this;
    }

    /**
     * Returns the step value
     *
     * @return string
     */
    public function getStep()
    {
        return $this->step;
    }

    /**
     * Returns true if $value is a scalar and a valid step value
     *
     * @param mixed $value
     * @return bool
     */
    public function isValid($value)
    {
        if (! is_numeric($value)) {
            $this->error(self::INVALID);
            return false;
        }

        $this->setValue($value);

        $substract = $this->sub($value, $this->baseValue);

        $fmod = $this->fmod($substract, $this->step);

        if ($fmod !== 0.0 && $fmod !== $this->step) {
            $this->error(self::NOT_STEP);
            return false;
        }

        return true;
    }

    /**
     * replaces the internal fmod function which give wrong results on many cases
     *
     * @param float $x
     * @param float $y
     * @return float
     */
    protected function fmod($x, $y)
    {
        if ($y == 0.0) {
            return 1.0;
        }

        //find the maximum precision from both input params to give accurate results
        $precision = $this->getPrecision($x) + $this->getPrecision($y);

        return round($x - $y * floor($x / $y), $precision);
    }

    /**
     * replaces the internal substraction operation which give wrong results on some cases
     *
     * @param float $x
     * @param float $y
     * @return float
     */
    private function sub($x, $y)
    {
        $precision = $this->getPrecision($x) + $this->getPrecision($y);
        return round($x - $y, $precision);
    }

    /**
     * @param  float $float
     * @return int
     */
    private function getPrecision($float)
    {
        $segment = substr($float, strpos($float, '.') + 1);
        return $segment ? strlen($segment) : 0;
    }
}
laminas-validator/src/Sitemap/Lastmod.php000064400000003747147361032560014502 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-validator for the canonical source repository
 * @copyright https://github.com/laminas/laminas-validator/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-validator/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Validator\Sitemap;

use Laminas\Stdlib\ErrorHandler;
use Laminas\Validator\AbstractValidator;

/**
 * Validates whether a given value is valid as a sitemap <lastmod> value
 *
 * @link       http://www.sitemaps.org/protocol.php Sitemaps XML format
 */
class Lastmod extends AbstractValidator
{
    /**
     * Regular expression to use when validating
     *
     */
    // @codingStandardsIgnoreStart
    const LASTMOD_REGEX = '/^[0-9]{4}-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])(T([0-1][0-9]|2[0-3])(:[0-5][0-9])(:[0-5][0-9])?(\\+|-)([0-1][0-9]|2[0-3]):[0-5][0-9])?$/';
    // @codingStandardsIgnoreEnd

    /**
     * Validation key for not valid
     *
     */
    const NOT_VALID = 'sitemapLastmodNotValid';
    const INVALID   = 'sitemapLastmodInvalid';

    /**
     * Validation failure message template definitions
     *
     * @var array
     */
    protected $messageTemplates = [
        self::NOT_VALID => 'The input is not a valid sitemap lastmod',
        self::INVALID   => 'Invalid type given. String expected',
    ];

    /**
     * Validates if a string is valid as a sitemap lastmod
     *
     * @link http://www.sitemaps.org/protocol.php#lastmoddef <lastmod>
     *
     * @param  string  $value  value to validate
     * @return bool
     */
    public function isValid($value)
    {
        if (! is_string($value)) {
            $this->error(self::INVALID);
            return false;
        }

        $this->setValue($value);
        ErrorHandler::start();
        $result = preg_match(self::LASTMOD_REGEX, $value);
        ErrorHandler::stop();
        if ($result != 1) {
            $this->error(self::NOT_VALID);
            return false;
        }

        return true;
    }
}
laminas-validator/src/Sitemap/Loc.php000064400000003147147361032560013606 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-validator for the canonical source repository
 * @copyright https://github.com/laminas/laminas-validator/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-validator/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Validator\Sitemap;

use Laminas\Uri;
use Laminas\Validator\AbstractValidator;

/**
 * Validates whether a given value is valid as a sitemap <loc> value
 *
 * @link       http://www.sitemaps.org/protocol.php Sitemaps XML format
 *
 * @see        Laminas\Uri\Uri
 */
class Loc extends AbstractValidator
{
    /**
     * Validation key for not valid
     *
     */
    const NOT_VALID = 'sitemapLocNotValid';
    const INVALID   = 'sitemapLocInvalid';

    /**
     * Validation failure message template definitions
     *
     * @var array
     */
    protected $messageTemplates = [
        self::NOT_VALID => 'The input is not a valid sitemap location',
        self::INVALID   => 'Invalid type given. String expected',
    ];

    /**
     * Validates if a string is valid as a sitemap location
     *
     * @link http://www.sitemaps.org/protocol.php#locdef <loc>
     *
     * @param  string  $value  value to validate
     * @return bool
     */
    public function isValid($value)
    {
        if (! is_string($value)) {
            $this->error(self::INVALID);
            return false;
        }

        $this->setValue($value);
        $uri = Uri\UriFactory::factory($value);
        if (! $uri->isValid()) {
            $this->error(self::NOT_VALID);
            return false;
        }

        return true;
    }
}
laminas-validator/src/Sitemap/Changefreq.php000064400000003533147361032560015133 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-validator for the canonical source repository
 * @copyright https://github.com/laminas/laminas-validator/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-validator/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Validator\Sitemap;

use Laminas\Validator\AbstractValidator;

/**
 * Validates whether a given value is valid as a sitemap <changefreq> value
 *
 * @link       http://www.sitemaps.org/protocol.php Sitemaps XML format
 */
class Changefreq extends AbstractValidator
{
    /**
     * Validation key for not valid
     *
     */
    const NOT_VALID = 'sitemapChangefreqNotValid';
    const INVALID   = 'sitemapChangefreqInvalid';

    /**
     * Validation failure message template definitions
     *
     * @var array
     */
    protected $messageTemplates = [
        self::NOT_VALID => 'The input is not a valid sitemap changefreq',
        self::INVALID   => 'Invalid type given. String expected',
    ];

    /**
     * Valid change frequencies
     *
     * @var array
     */
    protected $changeFreqs = [
        'always',  'hourly', 'daily', 'weekly',
        'monthly', 'yearly', 'never',
    ];

    /**
     * Validates if a string is valid as a sitemap changefreq
     *
     * @link http://www.sitemaps.org/protocol.php#changefreqdef <changefreq>
     *
     * @param  string  $value  value to validate
     * @return bool
     */
    public function isValid($value)
    {
        if (! is_string($value)) {
            $this->error(self::INVALID);
            return false;
        }

        $this->setValue($value);
        if (! is_string($value)) {
            return false;
        }

        if (! in_array($value, $this->changeFreqs, true)) {
            $this->error(self::NOT_VALID);
            return false;
        }

        return true;
    }
}
laminas-validator/src/Sitemap/Priority.php000064400000003145147361032560014710 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-validator for the canonical source repository
 * @copyright https://github.com/laminas/laminas-validator/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-validator/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Validator\Sitemap;

use Laminas\Validator\AbstractValidator;

/**
 * Validates whether a given value is valid as a sitemap <priority> value
 *
 * @link       http://www.sitemaps.org/protocol.php Sitemaps XML format
 */
class Priority extends AbstractValidator
{
    /**
     * Validation key for not valid
     *
     */
    const NOT_VALID = 'sitemapPriorityNotValid';
    const INVALID   = 'sitemapPriorityInvalid';

    /**
     * Validation failure message template definitions
     *
     * @var array
     */
    protected $messageTemplates = [
        self::NOT_VALID => 'The input is not a valid sitemap priority',
        self::INVALID   => 'Invalid type given. Numeric string, integer or float expected',
    ];

    /**
     * Validates if a string is valid as a sitemap priority
     *
     * @link http://www.sitemaps.org/protocol.php#prioritydef <priority>
     *
     * @param  string  $value  value to validate
     * @return bool
     */
    public function isValid($value)
    {
        if (! is_numeric($value)) {
            $this->error(self::INVALID);
            return false;
        }

        $this->setValue($value);
        $value = (float) $value;
        if ($value < 0 || $value > 1) {
            $this->error(self::NOT_VALID);
            return false;
        }

        return true;
    }
}
laminas-validator/src/IsCountable.php000064400000012611147361032560013673 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-validator for the canonical source repository
 * @copyright https://github.com/laminas/laminas-validator/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-validator/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Validator;

use Countable;

/**
 * Validate that a value is countable and the count meets expectations.
 *
 * The validator has five specific behaviors:
 *
 * - You can determine if a value is countable only
 * - You can test if the value is an exact count
 * - You can test if the value is greater than a minimum count value
 * - You can test if the value is greater than a maximum count value
 * - You can test if the value is between the minimum and maximum count values
 *
 * When creating the instance or calling `setOptions()`, if you specify a
 * "count" option, specifying either "min" or "max" leads to an inconsistent
 * state and, as such will raise an Exception\InvalidArgumentException.
 */
class IsCountable extends AbstractValidator
{
    const NOT_COUNTABLE = 'notCountable';
    const NOT_EQUALS    = 'notEquals';
    const GREATER_THAN  = 'greaterThan';
    const LESS_THAN     = 'lessThan';

    /**
     * Validation failure message template definitions
     *
     * @var array
     */
    protected $messageTemplates = [
        self::NOT_COUNTABLE => 'The input must be an array or an instance of \\Countable',
        self::NOT_EQUALS    => "The input count must equal '%count%'",
        self::GREATER_THAN  => "The input count must be less than '%max%', inclusively",
        self::LESS_THAN     => "The input count must be greater than '%min%', inclusively",
    ];

    /**
     * Additional variables available for validation failure messages
     *
     * @var array
     */
    protected $messageVariables = [
        'count' => ['options' => 'count'],
        'min'   => ['options' => 'min'],
        'max'   => ['options' => 'max'],
    ];

    /**
     * Options for the between validator
     *
     * @var array
     */
    protected $options = [
        'count' => null,
        'min'   => null,
        'max'   => null,
    ];

    public function setOptions($options = [])
    {
        foreach (['count', 'min', 'max'] as $option) {
            if (! is_array($options) || ! isset($options[$option])) {
                continue;
            }

            $method = sprintf('set%s', ucfirst($option));
            $this->$method($options[$option]);
            unset($options[$option]);
        }

        return parent::setOptions($options);
    }

    /**
     * Returns true if and only if $value is countable (and the count validates against optional values).
     *
     * @param  iterable $value
     * @return bool
     */
    public function isValid($value)
    {
        if (! (is_array($value) || $value instanceof Countable)) {
            $this->error(self::NOT_COUNTABLE);
            return false;
        }

        $count = count($value);

        if (is_numeric($this->getCount())) {
            if ($count != $this->getCount()) {
                $this->error(self::NOT_EQUALS);
                return false;
            }

            return true;
        }

        if (is_numeric($this->getMax()) && $count > $this->getMax()) {
            $this->error(self::GREATER_THAN);
            return false;
        }

        if (is_numeric($this->getMin()) && $count < $this->getMin()) {
            $this->error(self::LESS_THAN);
            return false;
        }

        return true;
    }

    /**
     * Returns the count option
     *
     * @return mixed
     */
    public function getCount()
    {
        return $this->options['count'];
    }

    /**
     * Returns the min option
     *
     * @return mixed
     */
    public function getMin()
    {
        return $this->options['min'];
    }

    /**
     * Returns the max option
     *
     * @return mixed
     */
    public function getMax()
    {
        return $this->options['max'];
    }

    /**
     * @param mixed $value
     * @return void
     * @throws Exception\InvalidArgumentException if either a min or max option
     *     was previously set.
     */
    private function setCount($value)
    {
        if (isset($this->options['min']) || isset($this->options['max'])) {
            throw new Exception\InvalidArgumentException(
                'Cannot set count; conflicts with either a min or max option previously set'
            );
        }
        $this->options['count'] = $value;
    }

    /**
     * @param mixed $value
     * @return void
     * @throws Exception\InvalidArgumentException if either a count or max option
     *     was previously set.
     */
    private function setMin($value)
    {
        if (isset($this->options['count'])) {
            throw new Exception\InvalidArgumentException(
                'Cannot set count; conflicts with either a count option previously set'
            );
        }
        $this->options['min'] = $value;
    }

    /**
     * @param mixed $value
     * @return void
     * @throws Exception\InvalidArgumentException if either a count or min option
     *     was previously set.
     */
    private function setMax($value)
    {
        if (isset($this->options['count'])) {
            throw new Exception\InvalidArgumentException(
                'Cannot set count; conflicts with either a count option previously set'
            );
        }
        $this->options['max'] = $value;
    }
}
laminas-validator/src/ValidatorPluginManagerFactory.php000064400000004437147361032560017421 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-validator for the canonical source repository
 * @copyright https://github.com/laminas/laminas-validator/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-validator/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Validator;

use Interop\Container\ContainerInterface;
use Laminas\ServiceManager\Config;
use Laminas\ServiceManager\FactoryInterface;
use Laminas\ServiceManager\ServiceLocatorInterface;

class ValidatorPluginManagerFactory implements FactoryInterface
{
    /**
     * laminas-servicemanager v2 support for invocation options.
     *
     * @param array
     */
    protected $creationOptions;

    /**
     * {@inheritDoc}
     *
     * @return ValidatorPluginManager
     */
    public function __invoke(ContainerInterface $container, $name, array $options = null)
    {
        $pluginManager = new ValidatorPluginManager($container, $options ?: []);

        // If this is in a laminas-mvc application, the ServiceListener will inject
        // merged configuration during bootstrap.
        if ($container->has('ServiceListener')) {
            return $pluginManager;
        }

        // If we do not have a config service, nothing more to do
        if (! $container->has('config')) {
            return $pluginManager;
        }

        $config = $container->get('config');

        // If we do not have validators configuration, nothing more to do
        if (! isset($config['validators']) || ! is_array($config['validators'])) {
            return $pluginManager;
        }

        // Wire service configuration for validators
        (new Config($config['validators']))->configureServiceManager($pluginManager);

        return $pluginManager;
    }

    /**
     * {@inheritDoc}
     *
     * @return ValidatorPluginManager
     */
    public function createService(ServiceLocatorInterface $container, $name = null, $requestedName = null)
    {
        return $this($container, $requestedName ?: ValidatorPluginManager::class, $this->creationOptions);
    }

    /**
     * laminas-servicemanager v2 support for invocation options.
     *
     * @param array $options
     * @return void
     */
    public function setCreationOptions(array $options)
    {
        $this->creationOptions = $options;
    }
}
laminas-validator/src/Ip.php000064400000014106147361032560012034 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-validator for the canonical source repository
 * @copyright https://github.com/laminas/laminas-validator/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-validator/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Validator;

use Traversable;

class Ip extends AbstractValidator
{
    const INVALID        = 'ipInvalid';
    const NOT_IP_ADDRESS = 'notIpAddress';

    /**
     * @var array
     */
    protected $messageTemplates = [
        self::INVALID        => 'Invalid type given. String expected',
        self::NOT_IP_ADDRESS => 'The input does not appear to be a valid IP address',
    ];

    /**
     * Internal options
     *
     * @var array
     */
    protected $options = [
        'allowipv4'      => true, // Enable IPv4 Validation
        'allowipv6'      => true, // Enable IPv6 Validation
        'allowipvfuture' => false, // Enable IPvFuture Validation
        'allowliteral'   => true, // Enable IPs in literal format (only IPv6 and IPvFuture)
    ];

    /**
     * Sets the options for this validator
     *
     * @param array|Traversable $options
     * @throws Exception\InvalidArgumentException If there is any kind of IP allowed or $options is not an array
     *                                            or Traversable.
     * @return AbstractValidator
     */
    public function setOptions($options = [])
    {
        parent::setOptions($options);

        if (! $this->options['allowipv4'] && ! $this->options['allowipv6'] && ! $this->options['allowipvfuture']) {
            throw new Exception\InvalidArgumentException('Nothing to validate. Check your options');
        }

        return $this;
    }

    /**
     * Returns true if and only if $value is a valid IP address
     *
     * @param  mixed $value
     * @return bool
     */
    public function isValid($value)
    {
        if (! is_string($value)) {
            $this->error(self::INVALID);
            return false;
        }

        $this->setValue($value);

        if ($this->options['allowipv4'] && $this->validateIPv4($value)) {
            return true;
        } else {
            if ((bool) $this->options['allowliteral']) {
                static $regex = '/^\[(.*)\]$/';
                if ((bool) preg_match($regex, $value, $matches)) {
                    $value = $matches[1];
                }
            }

            if (($this->options['allowipv6'] && $this->validateIPv6($value)) ||
                ($this->options['allowipvfuture'] && $this->validateIPvFuture($value))
            ) {
                return true;
            }
        }
        $this->error(self::NOT_IP_ADDRESS);
        return false;
    }

    /**
     * Validates an IPv4 address
     *
     * @param string $value
     * @return bool
     */
    protected function validateIPv4($value)
    {
        if (preg_match('/^([01]{8}\.){3}[01]{8}\z/i', $value)) {
            // binary format  00000000.00000000.00000000.00000000
            $value = bindec(substr($value, 0, 8)) . '.' . bindec(substr($value, 9, 8)) . '.'
                   . bindec(substr($value, 18, 8)) . '.' . bindec(substr($value, 27, 8));
        } elseif (preg_match('/^([0-9]{3}\.){3}[0-9]{3}\z/i', $value)) {
            // octet format 777.777.777.777
            $value = (int) substr($value, 0, 3) . '.' . (int) substr($value, 4, 3) . '.'
                   . (int) substr($value, 8, 3) . '.' . (int) substr($value, 12, 3);
        } elseif (preg_match('/^([0-9a-f]{2}\.){3}[0-9a-f]{2}\z/i', $value)) {
            // hex format ff.ff.ff.ff
            $value = hexdec(substr($value, 0, 2)) . '.' . hexdec(substr($value, 3, 2)) . '.'
                   . hexdec(substr($value, 6, 2)) . '.' . hexdec(substr($value, 9, 2));
        }

        $ip2long = ip2long($value);
        if ($ip2long === false) {
            return false;
        }

        return $value == long2ip($ip2long);
    }

    /**
     * Validates an IPv6 address
     *
     * @param  string $value Value to check against
     * @return bool True when $value is a valid ipv6 address
     *                 False otherwise
     */
    protected function validateIPv6($value)
    {
        if (strlen($value) < 3) {
            return $value == '::';
        }

        if (strpos($value, '.')) {
            $lastcolon = strrpos($value, ':');
            if (! ($lastcolon && $this->validateIPv4(substr($value, $lastcolon + 1)))) {
                return false;
            }

            $value = substr($value, 0, $lastcolon) . ':0:0';
        }

        if (strpos($value, '::') === false) {
            return preg_match('/\A(?:[a-f0-9]{1,4}:){7}[a-f0-9]{1,4}\z/i', $value);
        }

        $colonCount = substr_count($value, ':');
        if ($colonCount < 8) {
            return preg_match('/\A(?::|(?:[a-f0-9]{1,4}:)+):(?:(?:[a-f0-9]{1,4}:)*[a-f0-9]{1,4})?\z/i', $value);
        }

        // special case with ending or starting double colon
        if ($colonCount == 8) {
            return preg_match('/\A(?:::)?(?:[a-f0-9]{1,4}:){6}[a-f0-9]{1,4}(?:::)?\z/i', $value);
        }

        return false;
    }

    /**
     * Validates an IPvFuture address.
     *
     * IPvFuture is loosely defined in the Section 3.2.2 of RFC 3986
     *
     * @param  string $value Value to check against
     * @return bool True when $value is a valid IPvFuture address
     *                 False otherwise
     */
    protected function validateIPvFuture($value)
    {
        /*
         * ABNF:
         * IPvFuture  = "v" 1*HEXDIG "." 1*( unreserved / sub-delims / ":" )
         * unreserved    = ALPHA / DIGIT / "-" / "." / "_" / "~"
         * sub-delims    = "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / ","
         *               / ";" / "="
         */
        static $regex = '/^v([[:xdigit:]]+)\.[[:alnum:]\-\._~!\$&\'\(\)\*\+,;=:]+$/';

        $result = (bool) preg_match($regex, $value, $matches);

        /*
         * "As such, implementations must not provide the version flag for the
         *  existing IPv4 and IPv6 literal address forms described below."
         */
        return $result && $matches[1] != 4 && $matches[1] != 6;
    }
}
laminas-validator/src/ValidatorPluginManager.php000064400000101366147361032560016070 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-validator for the canonical source repository
 * @copyright https://github.com/laminas/laminas-validator/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-validator/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Validator;

use Interop\Container\ContainerInterface;
use Laminas\I18n\Validator as I18nValidator;
use Laminas\ServiceManager\AbstractPluginManager;
use Laminas\ServiceManager\Exception\InvalidServiceException;
use Laminas\ServiceManager\Factory\InvokableFactory;

class ValidatorPluginManager extends AbstractPluginManager
{
    /**
     * Default set of aliases
     *
     * @var array
     */
    protected $aliases = [
        'alnum'                    => I18nValidator\Alnum::class,
        'Alnum'                    => I18nValidator\Alnum::class,
        'alpha'                    => I18nValidator\Alpha::class,
        'Alpha'                    => I18nValidator\Alpha::class,
        'barcode'                  => Barcode::class,
        'Barcode'                  => Barcode::class,
        'between'                  => Between::class,
        'Between'                  => Between::class,
        'bitwise'                  => Bitwise::class,
        'Bitwise'                  => Bitwise::class,
        'callback'                 => Callback::class,
        'Callback'                 => Callback::class,
        'creditcard'               => CreditCard::class,
        'creditCard'               => CreditCard::class,
        'CreditCard'               => CreditCard::class,
        'csrf'                     => Csrf::class,
        'Csrf'                     => Csrf::class,
        'date'                     => Date::class,
        'Date'                     => Date::class,
        'datestep'                 => DateStep::class,
        'dateStep'                 => DateStep::class,
        'DateStep'                 => DateStep::class,
        'datetime'                 => I18nValidator\DateTime::class,
        'dateTime'                 => I18nValidator\DateTime::class,
        'DateTime'                 => I18nValidator\DateTime::class,
        'dbnorecordexists'         => Db\NoRecordExists::class,
        'dbNoRecordExists'         => Db\NoRecordExists::class,
        'DbNoRecordExists'         => Db\NoRecordExists::class,
        'dbrecordexists'           => Db\RecordExists::class,
        'dbRecordExists'           => Db\RecordExists::class,
        'DbRecordExists'           => Db\RecordExists::class,
        'digits'                   => Digits::class,
        'Digits'                   => Digits::class,
        'emailaddress'             => EmailAddress::class,
        'emailAddress'             => EmailAddress::class,
        'EmailAddress'             => EmailAddress::class,
        'explode'                  => Explode::class,
        'Explode'                  => Explode::class,
        'filecount'                => File\Count::class,
        'fileCount'                => File\Count::class,
        'FileCount'                => File\Count::class,
        'filecrc32'                => File\Crc32::class,
        'fileCrc32'                => File\Crc32::class,
        'FileCrc32'                => File\Crc32::class,
        'fileexcludeextension'     => File\ExcludeExtension::class,
        'fileExcludeExtension'     => File\ExcludeExtension::class,
        'FileExcludeExtension'     => File\ExcludeExtension::class,
        'fileexcludemimetype'      => File\ExcludeMimeType::class,
        'fileExcludeMimeType'      => File\ExcludeMimeType::class,
        'FileExcludeMimeType'      => File\ExcludeMimeType::class,
        'fileexists'               => File\Exists::class,
        'fileExists'               => File\Exists::class,
        'FileExists'               => File\Exists::class,
        'fileextension'            => File\Extension::class,
        'fileExtension'            => File\Extension::class,
        'FileExtension'            => File\Extension::class,
        'filefilessize'            => File\FilesSize::class,
        'fileFilesSize'            => File\FilesSize::class,
        'FileFilesSize'            => File\FilesSize::class,
        'filehash'                 => File\Hash::class,
        'fileHash'                 => File\Hash::class,
        'FileHash'                 => File\Hash::class,
        'fileimagesize'            => File\ImageSize::class,
        'fileImageSize'            => File\ImageSize::class,
        'FileImageSize'            => File\ImageSize::class,
        'fileiscompressed'         => File\IsCompressed::class,
        'fileIsCompressed'         => File\IsCompressed::class,
        'FileIsCompressed'         => File\IsCompressed::class,
        'fileisimage'              => File\IsImage::class,
        'fileIsImage'              => File\IsImage::class,
        'FileIsImage'              => File\IsImage::class,
        'filemd5'                  => File\Md5::class,
        'fileMd5'                  => File\Md5::class,
        'FileMd5'                  => File\Md5::class,
        'filemimetype'             => File\MimeType::class,
        'fileMimeType'             => File\MimeType::class,
        'FileMimeType'             => File\MimeType::class,
        'filenotexists'            => File\NotExists::class,
        'fileNotExists'            => File\NotExists::class,
        'FileNotExists'            => File\NotExists::class,
        'filesha1'                 => File\Sha1::class,
        'fileSha1'                 => File\Sha1::class,
        'FileSha1'                 => File\Sha1::class,
        'filesize'                 => File\Size::class,
        'fileSize'                 => File\Size::class,
        'FileSize'                 => File\Size::class,
        'fileupload'               => File\Upload::class,
        'fileUpload'               => File\Upload::class,
        'FileUpload'               => File\Upload::class,
        'fileuploadfile'           => File\UploadFile::class,
        'fileUploadFile'           => File\UploadFile::class,
        'FileUploadFile'           => File\UploadFile::class,
        'filewordcount'            => File\WordCount::class,
        'fileWordCount'            => File\WordCount::class,
        'FileWordCount'            => File\WordCount::class,
        'float'                    => I18nValidator\IsFloat::class,
        'Float'                    => I18nValidator\IsFloat::class,
        'gpspoint'                 => GpsPoint::class,
        'gpsPoint'                 => GpsPoint::class,
        'GpsPoint'                 => GpsPoint::class,
        'greaterthan'              => GreaterThan::class,
        'greaterThan'              => GreaterThan::class,
        'GreaterThan'              => GreaterThan::class,
        'hex'                      => Hex::class,
        'Hex'                      => Hex::class,
        'hostname'                 => Hostname::class,
        'Hostname'                 => Hostname::class,
        'iban'                     => Iban::class,
        'Iban'                     => Iban::class,
        'identical'                => Identical::class,
        'Identical'                => Identical::class,
        'inarray'                  => InArray::class,
        'inArray'                  => InArray::class,
        'InArray'                  => InArray::class,
        'int'                      => I18nValidator\IsInt::class,
        'Int'                      => I18nValidator\IsInt::class,
        'ip'                       => Ip::class,
        'Ip'                       => Ip::class,
        'isbn'                     => Isbn::class,
        'Isbn'                     => Isbn::class,
        'isfloat'                  => I18nValidator\IsFloat::class,
        'isFloat'                  => I18nValidator\IsFloat::class,
        'IsFloat'                  => I18nValidator\IsFloat::class,
        'isinstanceof'             => IsInstanceOf::class,
        'isInstanceOf'             => IsInstanceOf::class,
        'IsInstanceOf'             => IsInstanceOf::class,
        'isint'                    => I18nValidator\IsInt::class,
        'isInt'                    => I18nValidator\IsInt::class,
        'IsInt'                    => I18nValidator\IsInt::class,
        'lessthan'                 => LessThan::class,
        'lessThan'                 => LessThan::class,
        'LessThan'                 => LessThan::class,
        'notempty'                 => NotEmpty::class,
        'notEmpty'                 => NotEmpty::class,
        'NotEmpty'                 => NotEmpty::class,
        'phonenumber'              => I18nValidator\PhoneNumber::class,
        'phoneNumber'              => I18nValidator\PhoneNumber::class,
        'PhoneNumber'              => I18nValidator\PhoneNumber::class,
        'postcode'                 => I18nValidator\PostCode::class,
        'postCode'                 => I18nValidator\PostCode::class,
        'PostCode'                 => I18nValidator\PostCode::class,
        'regex'                    => Regex::class,
        'Regex'                    => Regex::class,
        'sitemapchangefreq'        => Sitemap\Changefreq::class,
        'sitemapChangefreq'        => Sitemap\Changefreq::class,
        'SitemapChangefreq'        => Sitemap\Changefreq::class,
        'sitemaplastmod'           => Sitemap\Lastmod::class,
        'sitemapLastmod'           => Sitemap\Lastmod::class,
        'SitemapLastmod'           => Sitemap\Lastmod::class,
        'sitemaploc'               => Sitemap\Loc::class,
        'sitemapLoc'               => Sitemap\Loc::class,
        'SitemapLoc'               => Sitemap\Loc::class,
        'sitemappriority'          => Sitemap\Priority::class,
        'sitemapPriority'          => Sitemap\Priority::class,
        'SitemapPriority'          => Sitemap\Priority::class,
        'stringlength'             => StringLength::class,
        'stringLength'             => StringLength::class,
        'StringLength'             => StringLength::class,
        'step'                     => Step::class,
        'Step'                     => Step::class,
        'timezone'                 => Timezone::class,
        'Timezone'                 => Timezone::class,
        'uri'                      => Uri::class,
        'Uri'                      => Uri::class,
        'uuid'                     => Uuid::class,
        'Uuid'                     => Uuid::class,

        // Legacy Zend Framework aliases
        \Zend\I18n\Validator\Alnum::class => I18nValidator\Alnum::class,
        \Zend\I18n\Validator\Alpha::class => I18nValidator\Alpha::class,
        \Zend\Validator\Barcode::class => Barcode::class,
        \Zend\Validator\Between::class => Between::class,
        \Zend\Validator\Bitwise::class => Bitwise::class,
        \Zend\Validator\Callback::class => Callback::class,
        \Zend\Validator\CreditCard::class => CreditCard::class,
        \Zend\Validator\Csrf::class => Csrf::class,
        \Zend\Validator\DateStep::class => DateStep::class,
        \Zend\Validator\Date::class => Date::class,
        \Zend\I18n\Validator\DateTime::class => I18nValidator\DateTime::class,
        \Zend\Validator\Db\NoRecordExists::class => Db\NoRecordExists::class,
        \Zend\Validator\Db\RecordExists::class => Db\RecordExists::class,
        \Zend\Validator\Digits::class => Digits::class,
        \Zend\Validator\EmailAddress::class => EmailAddress::class,
        \Zend\Validator\Explode::class => Explode::class,
        \Zend\Validator\File\Count::class => File\Count::class,
        \Zend\Validator\File\Crc32::class => File\Crc32::class,
        \Zend\Validator\File\ExcludeExtension::class => File\ExcludeExtension::class,
        \Zend\Validator\File\ExcludeMimeType::class => File\ExcludeMimeType::class,
        \Zend\Validator\File\Exists::class => File\Exists::class,
        \Zend\Validator\File\Extension::class => File\Extension::class,
        \Zend\Validator\File\FilesSize::class => File\FilesSize::class,
        \Zend\Validator\File\Hash::class => File\Hash::class,
        \Zend\Validator\File\ImageSize::class => File\ImageSize::class,
        \Zend\Validator\File\IsCompressed::class => File\IsCompressed::class,
        \Zend\Validator\File\IsImage::class => File\IsImage::class,
        \Zend\Validator\File\Md5::class => File\Md5::class,
        \Zend\Validator\File\MimeType::class => File\MimeType::class,
        \Zend\Validator\File\NotExists::class => File\NotExists::class,
        \Zend\Validator\File\Sha1::class => File\Sha1::class,
        \Zend\Validator\File\Size::class => File\Size::class,
        \Zend\Validator\File\Upload::class => File\Upload::class,
        \Zend\Validator\File\UploadFile::class => File\UploadFile::class,
        \Zend\Validator\File\WordCount::class => File\WordCount::class,
        \Zend\I18n\Validator\IsFloat::class => I18nValidator\IsFloat::class,
        \Zend\Validator\GpsPoint::class => GpsPoint::class,
        \Zend\Validator\GreaterThan::class => GreaterThan::class,
        \Zend\Validator\Hex::class => Hex::class,
        \Zend\Validator\Hostname::class => Hostname::class,
        \Zend\Validator\Iban::class => Iban::class,
        \Zend\Validator\Identical::class => Identical::class,
        \Zend\Validator\InArray::class => InArray::class,
        \Zend\I18n\Validator\IsInt::class => I18nValidator\IsInt::class,
        \Zend\Validator\Ip::class => Ip::class,
        \Zend\Validator\Isbn::class => Isbn::class,
        \Zend\Validator\IsInstanceOf::class => IsInstanceOf::class,
        \Zend\Validator\LessThan::class => LessThan::class,
        \Zend\Validator\NotEmpty::class => NotEmpty::class,
        \Zend\I18n\Validator\PhoneNumber::class => I18nValidator\PhoneNumber::class,
        \Zend\I18n\Validator\PostCode::class => I18nValidator\PostCode::class,
        \Zend\Validator\Regex::class => Regex::class,
        \Zend\Validator\Sitemap\Changefreq::class => Sitemap\Changefreq::class,
        \Zend\Validator\Sitemap\Lastmod::class => Sitemap\Lastmod::class,
        \Zend\Validator\Sitemap\Loc::class => Sitemap\Loc::class,
        \Zend\Validator\Sitemap\Priority::class => Sitemap\Priority::class,
        \Zend\Validator\StringLength::class => StringLength::class,
        \Zend\Validator\Step::class => Step::class,
        \Zend\Validator\Timezone::class => Timezone::class,
        \Zend\Validator\Uri::class => Uri::class,
        \Zend\Validator\Uuid::class => Uuid::class,

        // v2 normalized FQCNs
        'zendvalidatorbarcode' => Barcode::class,
        'zendvalidatorbetween' => Between::class,
        'zendvalidatorbitwise' => Bitwise::class,
        'zendvalidatorcallback' => Callback::class,
        'zendvalidatorcreditcard' => CreditCard::class,
        'zendvalidatorcsrf' => Csrf::class,
        'zendvalidatordatestep' => DateStep::class,
        'zendvalidatordate' => Date::class,
        'zendvalidatordbnorecordexists' => Db\NoRecordExists::class,
        'zendvalidatordbrecordexists' => Db\RecordExists::class,
        'zendvalidatordigits' => Digits::class,
        'zendvalidatoremailaddress' => EmailAddress::class,
        'zendvalidatorexplode' => Explode::class,
        'zendvalidatorfilecount' => File\Count::class,
        'zendvalidatorfilecrc32' => File\Crc32::class,
        'zendvalidatorfileexcludeextension' => File\ExcludeExtension::class,
        'zendvalidatorfileexcludemimetype' => File\ExcludeMimeType::class,
        'zendvalidatorfileexists' => File\Exists::class,
        'zendvalidatorfileextension' => File\Extension::class,
        'zendvalidatorfilefilessize' => File\FilesSize::class,
        'zendvalidatorfilehash' => File\Hash::class,
        'zendvalidatorfileimagesize' => File\ImageSize::class,
        'zendvalidatorfileiscompressed' => File\IsCompressed::class,
        'zendvalidatorfileisimage' => File\IsImage::class,
        'zendvalidatorfilemd5' => File\Md5::class,
        'zendvalidatorfilemimetype' => File\MimeType::class,
        'zendvalidatorfilenotexists' => File\NotExists::class,
        'zendvalidatorfilesha1' => File\Sha1::class,
        'zendvalidatorfilesize' => File\Size::class,
        'zendvalidatorfileupload' => File\Upload::class,
        'zendvalidatorfileuploadfile' => File\UploadFile::class,
        'zendvalidatorfilewordcount' => File\WordCount::class,
        'zendvalidatorgpspoint' => GpsPoint::class,
        'zendvalidatorgreaterthan' => GreaterThan::class,
        'zendvalidatorhex' => Hex::class,
        'zendvalidatorhostname' => Hostname::class,
        'zendi18nvalidatoralnum' => I18nValidator\Alnum::class,
        'zendi18nvalidatoralpha' => I18nValidator\Alpha::class,
        'zendi18nvalidatordatetime' => I18nValidator\DateTime::class,
        'zendi18nvalidatorisfloat' => I18nValidator\IsFloat::class,
        'zendi18nvalidatorisint' => I18nValidator\IsInt::class,
        'zendi18nvalidatorphonenumber' => I18nValidator\PhoneNumber::class,
        'zendi18nvalidatorpostcode' => I18nValidator\PostCode::class,
        'zendvalidatoriban' => Iban::class,
        'zendvalidatoridentical' => Identical::class,
        'zendvalidatorinarray' => InArray::class,
        'zendvalidatorip' => Ip::class,
        'zendvalidatorisbn' => Isbn::class,
        'zendvalidatorisinstanceof' => IsInstanceOf::class,
        'zendvalidatorlessthan' => LessThan::class,
        'zendvalidatornotempty' => NotEmpty::class,
        'zendvalidatorregex' => Regex::class,
        'zendvalidatorsitemapchangefreq' => Sitemap\Changefreq::class,
        'zendvalidatorsitemaplastmod' => Sitemap\Lastmod::class,
        'zendvalidatorsitemaploc' => Sitemap\Loc::class,
        'zendvalidatorsitemappriority' => Sitemap\Priority::class,
        'zendvalidatorstringlength' => StringLength::class,
        'zendvalidatorstep' => Step::class,
        'zendvalidatortimezone' => Timezone::class,
        'zendvalidatoruri' => Uri::class,
        'zendvalidatoruuid' => Uuid::class,
    ];

    /**
     * Default set of factories
     *
     * @var array
     */
    protected $factories = [
        I18nValidator\Alnum::class             => InvokableFactory::class,
        I18nValidator\Alpha::class             => InvokableFactory::class,
        Barcode::class                         => InvokableFactory::class,
        Between::class                         => InvokableFactory::class,
        Bitwise::class                         => InvokableFactory::class,
        Callback::class                        => InvokableFactory::class,
        CreditCard::class                      => InvokableFactory::class,
        Csrf::class                            => InvokableFactory::class,
        DateStep::class                        => InvokableFactory::class,
        Date::class                            => InvokableFactory::class,
        I18nValidator\DateTime::class          => InvokableFactory::class,
        Db\NoRecordExists::class               => InvokableFactory::class,
        Db\RecordExists::class                 => InvokableFactory::class,
        Digits::class                          => InvokableFactory::class,
        EmailAddress::class                    => InvokableFactory::class,
        Explode::class                         => InvokableFactory::class,
        File\Count::class                      => InvokableFactory::class,
        File\Crc32::class                      => InvokableFactory::class,
        File\ExcludeExtension::class           => InvokableFactory::class,
        File\ExcludeMimeType::class            => InvokableFactory::class,
        File\Exists::class                     => InvokableFactory::class,
        File\Extension::class                  => InvokableFactory::class,
        File\FilesSize::class                  => InvokableFactory::class,
        File\Hash::class                       => InvokableFactory::class,
        File\ImageSize::class                  => InvokableFactory::class,
        File\IsCompressed::class               => InvokableFactory::class,
        File\IsImage::class                    => InvokableFactory::class,
        File\Md5::class                        => InvokableFactory::class,
        File\MimeType::class                   => InvokableFactory::class,
        File\NotExists::class                  => InvokableFactory::class,
        File\Sha1::class                       => InvokableFactory::class,
        File\Size::class                       => InvokableFactory::class,
        File\Upload::class                     => InvokableFactory::class,
        File\UploadFile::class                 => InvokableFactory::class,
        File\WordCount::class                  => InvokableFactory::class,
        I18nValidator\IsFloat::class           => InvokableFactory::class,
        GpsPoint::class                        => InvokableFactory::class,
        GreaterThan::class                     => InvokableFactory::class,
        Hex::class                             => InvokableFactory::class,
        Hostname::class                        => InvokableFactory::class,
        Iban::class                            => InvokableFactory::class,
        Identical::class                       => InvokableFactory::class,
        InArray::class                         => InvokableFactory::class,
        I18nValidator\IsInt::class             => InvokableFactory::class,
        Ip::class                              => InvokableFactory::class,
        Isbn::class                            => InvokableFactory::class,
        I18nValidator\IsFloat::class           => InvokableFactory::class,
        IsInstanceOf::class                    => InvokableFactory::class,
        I18nValidator\IsInt::class             => InvokableFactory::class,
        LessThan::class                        => InvokableFactory::class,
        NotEmpty::class                        => InvokableFactory::class,
        I18nValidator\PhoneNumber::class       => InvokableFactory::class,
        I18nValidator\PostCode::class          => InvokableFactory::class,
        Regex::class                           => InvokableFactory::class,
        Sitemap\Changefreq::class              => InvokableFactory::class,
        Sitemap\Lastmod::class                 => InvokableFactory::class,
        Sitemap\Loc::class                     => InvokableFactory::class,
        Sitemap\Priority::class                => InvokableFactory::class,
        StringLength::class                    => InvokableFactory::class,
        Step::class                            => InvokableFactory::class,
        Timezone::class                        => InvokableFactory::class,
        Uri::class                             => InvokableFactory::class,
        Uuid::class                            => InvokableFactory::class,

        // v2 canonical FQCNs

        'laminasvalidatorbarcodecode25interleaved' => InvokableFactory::class,
        'laminasvalidatorbarcodecode25'            => InvokableFactory::class,
        'laminasvalidatorbarcodecode39ext'         => InvokableFactory::class,
        'laminasvalidatorbarcodecode39'            => InvokableFactory::class,
        'laminasvalidatorbarcodecode93ext'         => InvokableFactory::class,
        'laminasvalidatorbarcodecode93'            => InvokableFactory::class,
        'laminasvalidatorbarcodeean12'             => InvokableFactory::class,
        'laminasvalidatorbarcodeean13'             => InvokableFactory::class,
        'laminasvalidatorbarcodeean14'             => InvokableFactory::class,
        'laminasvalidatorbarcodeean18'             => InvokableFactory::class,
        'laminasvalidatorbarcodeean2'              => InvokableFactory::class,
        'laminasvalidatorbarcodeean5'              => InvokableFactory::class,
        'laminasvalidatorbarcodeean8'              => InvokableFactory::class,
        'laminasvalidatorbarcodegtin12'            => InvokableFactory::class,
        'laminasvalidatorbarcodegtin13'            => InvokableFactory::class,
        'laminasvalidatorbarcodegtin14'            => InvokableFactory::class,
        'laminasvalidatorbarcodeidentcode'         => InvokableFactory::class,
        'laminasvalidatorbarcodeintelligentmail'   => InvokableFactory::class,
        'laminasvalidatorbarcodeissn'              => InvokableFactory::class,
        'laminasvalidatorbarcodeitf14'             => InvokableFactory::class,
        'laminasvalidatorbarcodeleitcode'          => InvokableFactory::class,
        'laminasvalidatorbarcodeplanet'            => InvokableFactory::class,
        'laminasvalidatorbarcodepostnet'           => InvokableFactory::class,
        'laminasvalidatorbarcoderoyalmail'         => InvokableFactory::class,
        'laminasvalidatorbarcodesscc'              => InvokableFactory::class,
        'laminasvalidatorbarcodeupca'              => InvokableFactory::class,
        'laminasvalidatorbarcodeupce'              => InvokableFactory::class,
        'laminasvalidatorbarcode'                  => InvokableFactory::class,
        'laminasvalidatorbetween'                  => InvokableFactory::class,
        'laminasvalidatorbitwise'                  => InvokableFactory::class,
        'laminasvalidatorcallback'                 => InvokableFactory::class,
        'laminasvalidatorcreditcard'               => InvokableFactory::class,
        'laminasvalidatorcsrf'                     => InvokableFactory::class,
        'laminasvalidatordatestep'                 => InvokableFactory::class,
        'laminasvalidatordate'                     => InvokableFactory::class,
        'laminasvalidatordbnorecordexists'         => InvokableFactory::class,
        'laminasvalidatordbrecordexists'           => InvokableFactory::class,
        'laminasvalidatordigits'                   => InvokableFactory::class,
        'laminasvalidatoremailaddress'             => InvokableFactory::class,
        'laminasvalidatorexplode'                  => InvokableFactory::class,
        'laminasvalidatorfilecount'                => InvokableFactory::class,
        'laminasvalidatorfilecrc32'                => InvokableFactory::class,
        'laminasvalidatorfileexcludeextension'     => InvokableFactory::class,
        'laminasvalidatorfileexcludemimetype'      => InvokableFactory::class,
        'laminasvalidatorfileexists'               => InvokableFactory::class,
        'laminasvalidatorfileextension'            => InvokableFactory::class,
        'laminasvalidatorfilefilessize'            => InvokableFactory::class,
        'laminasvalidatorfilehash'                 => InvokableFactory::class,
        'laminasvalidatorfileimagesize'            => InvokableFactory::class,
        'laminasvalidatorfileiscompressed'         => InvokableFactory::class,
        'laminasvalidatorfileisimage'              => InvokableFactory::class,
        'laminasvalidatorfilemd5'                  => InvokableFactory::class,
        'laminasvalidatorfilemimetype'             => InvokableFactory::class,
        'laminasvalidatorfilenotexists'            => InvokableFactory::class,
        'laminasvalidatorfilesha1'                 => InvokableFactory::class,
        'laminasvalidatorfilesize'                 => InvokableFactory::class,
        'laminasvalidatorfileupload'               => InvokableFactory::class,
        'laminasvalidatorfileuploadfile'           => InvokableFactory::class,
        'laminasvalidatorfilewordcount'            => InvokableFactory::class,
        'laminasvalidatorgpspoint'                 => InvokableFactory::class,
        'laminasvalidatorgreaterthan'              => InvokableFactory::class,
        'laminasvalidatorhex'                      => InvokableFactory::class,
        'laminasvalidatorhostname'                 => InvokableFactory::class,
        'laminasi18nvalidatoralnum'                => InvokableFactory::class,
        'laminasi18nvalidatoralpha'                => InvokableFactory::class,
        'laminasi18nvalidatordatetime'             => InvokableFactory::class,
        'laminasi18nvalidatorisfloat'              => InvokableFactory::class,
        'laminasi18nvalidatorisint'                => InvokableFactory::class,
        'laminasi18nvalidatorphonenumber'          => InvokableFactory::class,
        'laminasi18nvalidatorpostcode'             => InvokableFactory::class,
        'laminasvalidatoriban'                     => InvokableFactory::class,
        'laminasvalidatoridentical'                => InvokableFactory::class,
        'laminasvalidatorinarray'                  => InvokableFactory::class,
        'laminasvalidatorip'                       => InvokableFactory::class,
        'laminasvalidatorisbn'                     => InvokableFactory::class,
        'laminasvalidatorisinstanceof'             => InvokableFactory::class,
        'laminasvalidatorlessthan'                 => InvokableFactory::class,
        'laminasvalidatornotempty'                 => InvokableFactory::class,
        'laminasvalidatorregex'                    => InvokableFactory::class,
        'laminasvalidatorsitemapchangefreq'        => InvokableFactory::class,
        'laminasvalidatorsitemaplastmod'           => InvokableFactory::class,
        'laminasvalidatorsitemaploc'               => InvokableFactory::class,
        'laminasvalidatorsitemappriority'          => InvokableFactory::class,
        'laminasvalidatorstringlength'             => InvokableFactory::class,
        'laminasvalidatorstep'                     => InvokableFactory::class,
        'laminasvalidatortimezone'                 => InvokableFactory::class,
        'laminasvalidatoruri'                      => InvokableFactory::class,
        'laminasvalidatoruuid'                     => InvokableFactory::class,
    ];

    /**
     * Whether or not to share by default; default to false (v2)
     *
     * @var bool
     */
    protected $shareByDefault = false;

    /**
     * Whether or not to share by default; default to false (v3)
     *
     * @var bool
     */
    protected $sharedByDefault = false;

    /**
     * Default instance type
     *
     * @var string
     */
    protected $instanceOf = ValidatorInterface::class;

    /**
     * Constructor
     *
     * After invoking parent constructor, add an initializer to inject the
     * attached translator, if any, to the currently requested helper.
     *
     * {@inheritDoc}
     */
    public function __construct($configOrContainerInstance = null, array $v3config = [])
    {
        parent::__construct($configOrContainerInstance, $v3config);

        $this->addInitializer([$this, 'injectTranslator']);
        $this->addInitializer([$this, 'injectValidatorPluginManager']);
    }

    /**
     * Validate plugin instance
     *
     * {@inheritDoc}
     */
    public function validate($plugin)
    {
        if (! $plugin instanceof $this->instanceOf) {
            throw new InvalidServiceException(sprintf(
                '%s expects only to create instances of %s; %s is invalid',
                get_class($this),
                $this->instanceOf,
                is_object($plugin) ? get_class($plugin) : gettype($plugin)
            ));
        }
    }

    /**
     * For v2 compatibility: validate plugin instance.
     *
     * Proxies to `validate()`.
     *
     * @param mixed $plugin
     * @throws Exception\RuntimeException
     */
    public function validatePlugin($plugin)
    {
        try {
            $this->validate($plugin);
        } catch (InvalidServiceException $e) {
            throw new Exception\RuntimeException(sprintf(
                'Plugin of type %s is invalid; must implement %s',
                is_object($plugin) ? get_class($plugin) : gettype($plugin),
                ValidatorInterface::class
            ), $e->getCode(), $e);
        }
    }

    /**
     * Inject a validator instance with the registered translator
     *
     * @param  ContainerInterface|object $first
     * @param  ContainerInterface|object $second
     * @return void
     */
    public function injectTranslator($first, $second)
    {
        if ($first instanceof ContainerInterface) {
            $container = $first;
            $validator = $second;
        } else {
            $container = $second;
            $validator = $first;
        }

        // V2 means we pull it from the parent container
        if ($container === $this && method_exists($container, 'getServiceLocator') && $container->getServiceLocator()) {
            $container = $container->getServiceLocator();
        }

        if ($validator instanceof Translator\TranslatorAwareInterface) {
            if ($container && $container->has('MvcTranslator')) {
                $validator->setTranslator($container->get('MvcTranslator'));
            }
        }
    }

    /**
     * Inject a validator plugin manager
     *
     * @param  ContainerInterface|object $first
     * @param  ContainerInterface|object $second
     * @return void
     */
    public function injectValidatorPluginManager($first, $second)
    {
        if ($first instanceof ContainerInterface) {
            $container = $first;
            $validator = $second;
        } else {
            $container = $second;
            $validator = $first;
        }
        if ($validator instanceof ValidatorPluginManagerAwareInterface) {
            $validator->setValidatorPluginManager($this);
        }
    }
}
laminas-validator/src/Hostname.php000064400000172633147361032560013254 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-validator for the canonical source repository
 * @copyright https://github.com/laminas/laminas-validator/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-validator/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Validator;

use Laminas\Stdlib\StringUtils;

/**
 * Please note there are two standalone test scripts for testing IDN characters due to problems
 * with file encoding.
 *
 * The first is tests/Laminas/Validator/HostnameTestStandalone.php which is designed to be run on
 * the command line.
 *
 * The second is tests/Laminas/Validator/HostnameTestForm.php which is designed to be run via HTML
 * to allow users to test entering UTF-8 characters in a form.
 */
class Hostname extends AbstractValidator
{
    const CANNOT_DECODE_PUNYCODE  = 'hostnameCannotDecodePunycode';
    const INVALID                 = 'hostnameInvalid';
    const INVALID_DASH            = 'hostnameDashCharacter';
    const INVALID_HOSTNAME        = 'hostnameInvalidHostname';
    const INVALID_HOSTNAME_SCHEMA = 'hostnameInvalidHostnameSchema';
    const INVALID_LOCAL_NAME      = 'hostnameInvalidLocalName';
    const INVALID_URI             = 'hostnameInvalidUri';
    const IP_ADDRESS_NOT_ALLOWED  = 'hostnameIpAddressNotAllowed';
    const LOCAL_NAME_NOT_ALLOWED  = 'hostnameLocalNameNotAllowed';
    const UNDECIPHERABLE_TLD      = 'hostnameUndecipherableTld';
    const UNKNOWN_TLD             = 'hostnameUnknownTld';

    // @codingStandardsIgnoreStart
    /**
     * @var array
     */
    protected $messageTemplates = [
        self::CANNOT_DECODE_PUNYCODE  => "The input appears to be a DNS hostname but the given punycode notation cannot be decoded",
        self::INVALID                 => "Invalid type given. String expected",
        self::INVALID_DASH            => "The input appears to be a DNS hostname but contains a dash in an invalid position",
        self::INVALID_HOSTNAME        => "The input does not match the expected structure for a DNS hostname",
        self::INVALID_HOSTNAME_SCHEMA => "The input appears to be a DNS hostname but cannot match against hostname schema for TLD '%tld%'",
        self::INVALID_LOCAL_NAME      => "The input does not appear to be a valid local network name",
        self::INVALID_URI             => "The input does not appear to be a valid URI hostname",
        self::IP_ADDRESS_NOT_ALLOWED  => "The input appears to be an IP address, but IP addresses are not allowed",
        self::LOCAL_NAME_NOT_ALLOWED  => "The input appears to be a local network name but local network names are not allowed",
        self::UNDECIPHERABLE_TLD      => "The input appears to be a DNS hostname but cannot extract TLD part",
        self::UNKNOWN_TLD             => "The input appears to be a DNS hostname but cannot match TLD against known list",
    ];
    // @codingStandardsIgnoreEnd

    /**
     * @var array
     */
    protected $messageVariables = [
        'tld' => 'tld',
    ];

    const ALLOW_DNS   = 1;  // Allows Internet domain names (e.g., example.com)
    const ALLOW_IP    = 2;  // Allows IP addresses
    const ALLOW_LOCAL = 4;  // Allows local network names (e.g., localhost, www.localdomain)
    const ALLOW_URI   = 8;  // Allows URI hostnames
    const ALLOW_ALL   = 15;  // Allows all types of hostnames

    /**
     * Array of valid top-level-domains
     * IanaVersion 2020033100
     *
     * @see ftp://data.iana.org/TLD/tlds-alpha-by-domain.txt  List of all TLDs by domain
     * @see http://www.iana.org/domains/root/db/ Official list of supported TLDs
     * @var array
     */
    protected $validTlds = [
        'aaa',
        'aarp',
        'abarth',
        'abb',
        'abbott',
        'abbvie',
        'abc',
        'able',
        'abogado',
        'abudhabi',
        'ac',
        'academy',
        'accenture',
        'accountant',
        'accountants',
        'aco',
        'actor',
        'ad',
        'adac',
        'ads',
        'adult',
        'ae',
        'aeg',
        'aero',
        'aetna',
        'af',
        'afamilycompany',
        'afl',
        'africa',
        'ag',
        'agakhan',
        'agency',
        'ai',
        'aig',
        'aigo',
        'airbus',
        'airforce',
        'airtel',
        'akdn',
        'al',
        'alfaromeo',
        'alibaba',
        'alipay',
        'allfinanz',
        'allstate',
        'ally',
        'alsace',
        'alstom',
        'am',
        'americanexpress',
        'americanfamily',
        'amex',
        'amfam',
        'amica',
        'amsterdam',
        'analytics',
        'android',
        'anquan',
        'anz',
        'ao',
        'aol',
        'apartments',
        'app',
        'apple',
        'aq',
        'aquarelle',
        'ar',
        'arab',
        'aramco',
        'archi',
        'army',
        'arpa',
        'art',
        'arte',
        'as',
        'asda',
        'asia',
        'associates',
        'at',
        'athleta',
        'attorney',
        'au',
        'auction',
        'audi',
        'audible',
        'audio',
        'auspost',
        'author',
        'auto',
        'autos',
        'avianca',
        'aw',
        'aws',
        'ax',
        'axa',
        'az',
        'azure',
        'ba',
        'baby',
        'baidu',
        'banamex',
        'bananarepublic',
        'band',
        'bank',
        'bar',
        'barcelona',
        'barclaycard',
        'barclays',
        'barefoot',
        'bargains',
        'baseball',
        'basketball',
        'bauhaus',
        'bayern',
        'bb',
        'bbc',
        'bbt',
        'bbva',
        'bcg',
        'bcn',
        'bd',
        'be',
        'beats',
        'beauty',
        'beer',
        'bentley',
        'berlin',
        'best',
        'bestbuy',
        'bet',
        'bf',
        'bg',
        'bh',
        'bharti',
        'bi',
        'bible',
        'bid',
        'bike',
        'bing',
        'bingo',
        'bio',
        'biz',
        'bj',
        'black',
        'blackfriday',
        'blockbuster',
        'blog',
        'bloomberg',
        'blue',
        'bm',
        'bms',
        'bmw',
        'bn',
        'bnpparibas',
        'bo',
        'boats',
        'boehringer',
        'bofa',
        'bom',
        'bond',
        'boo',
        'book',
        'booking',
        'bosch',
        'bostik',
        'boston',
        'bot',
        'boutique',
        'box',
        'br',
        'bradesco',
        'bridgestone',
        'broadway',
        'broker',
        'brother',
        'brussels',
        'bs',
        'bt',
        'budapest',
        'bugatti',
        'build',
        'builders',
        'business',
        'buy',
        'buzz',
        'bv',
        'bw',
        'by',
        'bz',
        'bzh',
        'ca',
        'cab',
        'cafe',
        'cal',
        'call',
        'calvinklein',
        'cam',
        'camera',
        'camp',
        'cancerresearch',
        'canon',
        'capetown',
        'capital',
        'capitalone',
        'car',
        'caravan',
        'cards',
        'care',
        'career',
        'careers',
        'cars',
        'casa',
        'case',
        'caseih',
        'cash',
        'casino',
        'cat',
        'catering',
        'catholic',
        'cba',
        'cbn',
        'cbre',
        'cbs',
        'cc',
        'cd',
        'ceb',
        'center',
        'ceo',
        'cern',
        'cf',
        'cfa',
        'cfd',
        'cg',
        'ch',
        'chanel',
        'channel',
        'charity',
        'chase',
        'chat',
        'cheap',
        'chintai',
        'christmas',
        'chrome',
        'church',
        'ci',
        'cipriani',
        'circle',
        'cisco',
        'citadel',
        'citi',
        'citic',
        'city',
        'cityeats',
        'ck',
        'cl',
        'claims',
        'cleaning',
        'click',
        'clinic',
        'clinique',
        'clothing',
        'cloud',
        'club',
        'clubmed',
        'cm',
        'cn',
        'co',
        'coach',
        'codes',
        'coffee',
        'college',
        'cologne',
        'com',
        'comcast',
        'commbank',
        'community',
        'company',
        'compare',
        'computer',
        'comsec',
        'condos',
        'construction',
        'consulting',
        'contact',
        'contractors',
        'cooking',
        'cookingchannel',
        'cool',
        'coop',
        'corsica',
        'country',
        'coupon',
        'coupons',
        'courses',
        'cpa',
        'cr',
        'credit',
        'creditcard',
        'creditunion',
        'cricket',
        'crown',
        'crs',
        'cruise',
        'cruises',
        'csc',
        'cu',
        'cuisinella',
        'cv',
        'cw',
        'cx',
        'cy',
        'cymru',
        'cyou',
        'cz',
        'dabur',
        'dad',
        'dance',
        'data',
        'date',
        'dating',
        'datsun',
        'day',
        'dclk',
        'dds',
        'de',
        'deal',
        'dealer',
        'deals',
        'degree',
        'delivery',
        'dell',
        'deloitte',
        'delta',
        'democrat',
        'dental',
        'dentist',
        'desi',
        'design',
        'dev',
        'dhl',
        'diamonds',
        'diet',
        'digital',
        'direct',
        'directory',
        'discount',
        'discover',
        'dish',
        'diy',
        'dj',
        'dk',
        'dm',
        'dnp',
        'do',
        'docs',
        'doctor',
        'dog',
        'domains',
        'dot',
        'download',
        'drive',
        'dtv',
        'dubai',
        'duck',
        'dunlop',
        'dupont',
        'durban',
        'dvag',
        'dvr',
        'dz',
        'earth',
        'eat',
        'ec',
        'eco',
        'edeka',
        'edu',
        'education',
        'ee',
        'eg',
        'email',
        'emerck',
        'energy',
        'engineer',
        'engineering',
        'enterprises',
        'epson',
        'equipment',
        'er',
        'ericsson',
        'erni',
        'es',
        'esq',
        'estate',
        'esurance',
        'et',
        'etisalat',
        'eu',
        'eurovision',
        'eus',
        'events',
        'exchange',
        'expert',
        'exposed',
        'express',
        'extraspace',
        'fage',
        'fail',
        'fairwinds',
        'faith',
        'family',
        'fan',
        'fans',
        'farm',
        'farmers',
        'fashion',
        'fast',
        'fedex',
        'feedback',
        'ferrari',
        'ferrero',
        'fi',
        'fiat',
        'fidelity',
        'fido',
        'film',
        'final',
        'finance',
        'financial',
        'fire',
        'firestone',
        'firmdale',
        'fish',
        'fishing',
        'fit',
        'fitness',
        'fj',
        'fk',
        'flickr',
        'flights',
        'flir',
        'florist',
        'flowers',
        'fly',
        'fm',
        'fo',
        'foo',
        'food',
        'foodnetwork',
        'football',
        'ford',
        'forex',
        'forsale',
        'forum',
        'foundation',
        'fox',
        'fr',
        'free',
        'fresenius',
        'frl',
        'frogans',
        'frontdoor',
        'frontier',
        'ftr',
        'fujitsu',
        'fujixerox',
        'fun',
        'fund',
        'furniture',
        'futbol',
        'fyi',
        'ga',
        'gal',
        'gallery',
        'gallo',
        'gallup',
        'game',
        'games',
        'gap',
        'garden',
        'gay',
        'gb',
        'gbiz',
        'gd',
        'gdn',
        'ge',
        'gea',
        'gent',
        'genting',
        'george',
        'gf',
        'gg',
        'ggee',
        'gh',
        'gi',
        'gift',
        'gifts',
        'gives',
        'giving',
        'gl',
        'glade',
        'glass',
        'gle',
        'global',
        'globo',
        'gm',
        'gmail',
        'gmbh',
        'gmo',
        'gmx',
        'gn',
        'godaddy',
        'gold',
        'goldpoint',
        'golf',
        'goo',
        'goodyear',
        'goog',
        'google',
        'gop',
        'got',
        'gov',
        'gp',
        'gq',
        'gr',
        'grainger',
        'graphics',
        'gratis',
        'green',
        'gripe',
        'grocery',
        'group',
        'gs',
        'gt',
        'gu',
        'guardian',
        'gucci',
        'guge',
        'guide',
        'guitars',
        'guru',
        'gw',
        'gy',
        'hair',
        'hamburg',
        'hangout',
        'haus',
        'hbo',
        'hdfc',
        'hdfcbank',
        'health',
        'healthcare',
        'help',
        'helsinki',
        'here',
        'hermes',
        'hgtv',
        'hiphop',
        'hisamitsu',
        'hitachi',
        'hiv',
        'hk',
        'hkt',
        'hm',
        'hn',
        'hockey',
        'holdings',
        'holiday',
        'homedepot',
        'homegoods',
        'homes',
        'homesense',
        'honda',
        'horse',
        'hospital',
        'host',
        'hosting',
        'hot',
        'hoteles',
        'hotels',
        'hotmail',
        'house',
        'how',
        'hr',
        'hsbc',
        'ht',
        'hu',
        'hughes',
        'hyatt',
        'hyundai',
        'ibm',
        'icbc',
        'ice',
        'icu',
        'id',
        'ie',
        'ieee',
        'ifm',
        'ikano',
        'il',
        'im',
        'imamat',
        'imdb',
        'immo',
        'immobilien',
        'in',
        'inc',
        'industries',
        'infiniti',
        'info',
        'ing',
        'ink',
        'institute',
        'insurance',
        'insure',
        'int',
        'intel',
        'international',
        'intuit',
        'investments',
        'io',
        'ipiranga',
        'iq',
        'ir',
        'irish',
        'is',
        'ismaili',
        'ist',
        'istanbul',
        'it',
        'itau',
        'itv',
        'iveco',
        'jaguar',
        'java',
        'jcb',
        'jcp',
        'je',
        'jeep',
        'jetzt',
        'jewelry',
        'jio',
        'jll',
        'jm',
        'jmp',
        'jnj',
        'jo',
        'jobs',
        'joburg',
        'jot',
        'joy',
        'jp',
        'jpmorgan',
        'jprs',
        'juegos',
        'juniper',
        'kaufen',
        'kddi',
        'ke',
        'kerryhotels',
        'kerrylogistics',
        'kerryproperties',
        'kfh',
        'kg',
        'kh',
        'ki',
        'kia',
        'kim',
        'kinder',
        'kindle',
        'kitchen',
        'kiwi',
        'km',
        'kn',
        'koeln',
        'komatsu',
        'kosher',
        'kp',
        'kpmg',
        'kpn',
        'kr',
        'krd',
        'kred',
        'kuokgroup',
        'kw',
        'ky',
        'kyoto',
        'kz',
        'la',
        'lacaixa',
        'lamborghini',
        'lamer',
        'lancaster',
        'lancia',
        'land',
        'landrover',
        'lanxess',
        'lasalle',
        'lat',
        'latino',
        'latrobe',
        'law',
        'lawyer',
        'lb',
        'lc',
        'lds',
        'lease',
        'leclerc',
        'lefrak',
        'legal',
        'lego',
        'lexus',
        'lgbt',
        'li',
        'lidl',
        'life',
        'lifeinsurance',
        'lifestyle',
        'lighting',
        'like',
        'lilly',
        'limited',
        'limo',
        'lincoln',
        'linde',
        'link',
        'lipsy',
        'live',
        'living',
        'lixil',
        'lk',
        'llc',
        'llp',
        'loan',
        'loans',
        'locker',
        'locus',
        'loft',
        'lol',
        'london',
        'lotte',
        'lotto',
        'love',
        'lpl',
        'lplfinancial',
        'lr',
        'ls',
        'lt',
        'ltd',
        'ltda',
        'lu',
        'lundbeck',
        'lupin',
        'luxe',
        'luxury',
        'lv',
        'ly',
        'ma',
        'macys',
        'madrid',
        'maif',
        'maison',
        'makeup',
        'man',
        'management',
        'mango',
        'map',
        'market',
        'marketing',
        'markets',
        'marriott',
        'marshalls',
        'maserati',
        'mattel',
        'mba',
        'mc',
        'mckinsey',
        'md',
        'me',
        'med',
        'media',
        'meet',
        'melbourne',
        'meme',
        'memorial',
        'men',
        'menu',
        'merckmsd',
        'metlife',
        'mg',
        'mh',
        'miami',
        'microsoft',
        'mil',
        'mini',
        'mint',
        'mit',
        'mitsubishi',
        'mk',
        'ml',
        'mlb',
        'mls',
        'mm',
        'mma',
        'mn',
        'mo',
        'mobi',
        'mobile',
        'moda',
        'moe',
        'moi',
        'mom',
        'monash',
        'money',
        'monster',
        'mormon',
        'mortgage',
        'moscow',
        'moto',
        'motorcycles',
        'mov',
        'movie',
        'mp',
        'mq',
        'mr',
        'ms',
        'msd',
        'mt',
        'mtn',
        'mtr',
        'mu',
        'museum',
        'mutual',
        'mv',
        'mw',
        'mx',
        'my',
        'mz',
        'na',
        'nab',
        'nagoya',
        'name',
        'nationwide',
        'natura',
        'navy',
        'nba',
        'nc',
        'ne',
        'nec',
        'net',
        'netbank',
        'netflix',
        'network',
        'neustar',
        'new',
        'newholland',
        'news',
        'next',
        'nextdirect',
        'nexus',
        'nf',
        'nfl',
        'ng',
        'ngo',
        'nhk',
        'ni',
        'nico',
        'nike',
        'nikon',
        'ninja',
        'nissan',
        'nissay',
        'nl',
        'no',
        'nokia',
        'northwesternmutual',
        'norton',
        'now',
        'nowruz',
        'nowtv',
        'np',
        'nr',
        'nra',
        'nrw',
        'ntt',
        'nu',
        'nyc',
        'nz',
        'obi',
        'observer',
        'off',
        'office',
        'okinawa',
        'olayan',
        'olayangroup',
        'oldnavy',
        'ollo',
        'om',
        'omega',
        'one',
        'ong',
        'onl',
        'online',
        'onyourside',
        'ooo',
        'open',
        'oracle',
        'orange',
        'org',
        'organic',
        'origins',
        'osaka',
        'otsuka',
        'ott',
        'ovh',
        'pa',
        'page',
        'panasonic',
        'paris',
        'pars',
        'partners',
        'parts',
        'party',
        'passagens',
        'pay',
        'pccw',
        'pe',
        'pet',
        'pf',
        'pfizer',
        'pg',
        'ph',
        'pharmacy',
        'phd',
        'philips',
        'phone',
        'photo',
        'photography',
        'photos',
        'physio',
        'pics',
        'pictet',
        'pictures',
        'pid',
        'pin',
        'ping',
        'pink',
        'pioneer',
        'pizza',
        'pk',
        'pl',
        'place',
        'play',
        'playstation',
        'plumbing',
        'plus',
        'pm',
        'pn',
        'pnc',
        'pohl',
        'poker',
        'politie',
        'porn',
        'post',
        'pr',
        'pramerica',
        'praxi',
        'press',
        'prime',
        'pro',
        'prod',
        'productions',
        'prof',
        'progressive',
        'promo',
        'properties',
        'property',
        'protection',
        'pru',
        'prudential',
        'ps',
        'pt',
        'pub',
        'pw',
        'pwc',
        'py',
        'qa',
        'qpon',
        'quebec',
        'quest',
        'qvc',
        'racing',
        'radio',
        'raid',
        're',
        'read',
        'realestate',
        'realtor',
        'realty',
        'recipes',
        'red',
        'redstone',
        'redumbrella',
        'rehab',
        'reise',
        'reisen',
        'reit',
        'reliance',
        'ren',
        'rent',
        'rentals',
        'repair',
        'report',
        'republican',
        'rest',
        'restaurant',
        'review',
        'reviews',
        'rexroth',
        'rich',
        'richardli',
        'ricoh',
        'rightathome',
        'ril',
        'rio',
        'rip',
        'rmit',
        'ro',
        'rocher',
        'rocks',
        'rodeo',
        'rogers',
        'room',
        'rs',
        'rsvp',
        'ru',
        'rugby',
        'ruhr',
        'run',
        'rw',
        'rwe',
        'ryukyu',
        'sa',
        'saarland',
        'safe',
        'safety',
        'sakura',
        'sale',
        'salon',
        'samsclub',
        'samsung',
        'sandvik',
        'sandvikcoromant',
        'sanofi',
        'sap',
        'sarl',
        'sas',
        'save',
        'saxo',
        'sb',
        'sbi',
        'sbs',
        'sc',
        'sca',
        'scb',
        'schaeffler',
        'schmidt',
        'scholarships',
        'school',
        'schule',
        'schwarz',
        'science',
        'scjohnson',
        'scor',
        'scot',
        'sd',
        'se',
        'search',
        'seat',
        'secure',
        'security',
        'seek',
        'select',
        'sener',
        'services',
        'ses',
        'seven',
        'sew',
        'sex',
        'sexy',
        'sfr',
        'sg',
        'sh',
        'shangrila',
        'sharp',
        'shaw',
        'shell',
        'shia',
        'shiksha',
        'shoes',
        'shop',
        'shopping',
        'shouji',
        'show',
        'showtime',
        'shriram',
        'si',
        'silk',
        'sina',
        'singles',
        'site',
        'sj',
        'sk',
        'ski',
        'skin',
        'sky',
        'skype',
        'sl',
        'sling',
        'sm',
        'smart',
        'smile',
        'sn',
        'sncf',
        'so',
        'soccer',
        'social',
        'softbank',
        'software',
        'sohu',
        'solar',
        'solutions',
        'song',
        'sony',
        'soy',
        'space',
        'sport',
        'spot',
        'spreadbetting',
        'sr',
        'srl',
        'ss',
        'st',
        'stada',
        'staples',
        'star',
        'statebank',
        'statefarm',
        'stc',
        'stcgroup',
        'stockholm',
        'storage',
        'store',
        'stream',
        'studio',
        'study',
        'style',
        'su',
        'sucks',
        'supplies',
        'supply',
        'support',
        'surf',
        'surgery',
        'suzuki',
        'sv',
        'swatch',
        'swiftcover',
        'swiss',
        'sx',
        'sy',
        'sydney',
        'symantec',
        'systems',
        'sz',
        'tab',
        'taipei',
        'talk',
        'taobao',
        'target',
        'tatamotors',
        'tatar',
        'tattoo',
        'tax',
        'taxi',
        'tc',
        'tci',
        'td',
        'tdk',
        'team',
        'tech',
        'technology',
        'tel',
        'temasek',
        'tennis',
        'teva',
        'tf',
        'tg',
        'th',
        'thd',
        'theater',
        'theatre',
        'tiaa',
        'tickets',
        'tienda',
        'tiffany',
        'tips',
        'tires',
        'tirol',
        'tj',
        'tjmaxx',
        'tjx',
        'tk',
        'tkmaxx',
        'tl',
        'tm',
        'tmall',
        'tn',
        'to',
        'today',
        'tokyo',
        'tools',
        'top',
        'toray',
        'toshiba',
        'total',
        'tours',
        'town',
        'toyota',
        'toys',
        'tr',
        'trade',
        'trading',
        'training',
        'travel',
        'travelchannel',
        'travelers',
        'travelersinsurance',
        'trust',
        'trv',
        'tt',
        'tube',
        'tui',
        'tunes',
        'tushu',
        'tv',
        'tvs',
        'tw',
        'tz',
        'ua',
        'ubank',
        'ubs',
        'ug',
        'uk',
        'unicom',
        'university',
        'uno',
        'uol',
        'ups',
        'us',
        'uy',
        'uz',
        'va',
        'vacations',
        'vana',
        'vanguard',
        'vc',
        've',
        'vegas',
        'ventures',
        'verisign',
        'versicherung',
        'vet',
        'vg',
        'vi',
        'viajes',
        'video',
        'vig',
        'viking',
        'villas',
        'vin',
        'vip',
        'virgin',
        'visa',
        'vision',
        'viva',
        'vivo',
        'vlaanderen',
        'vn',
        'vodka',
        'volkswagen',
        'volvo',
        'vote',
        'voting',
        'voto',
        'voyage',
        'vu',
        'vuelos',
        'wales',
        'walmart',
        'walter',
        'wang',
        'wanggou',
        'watch',
        'watches',
        'weather',
        'weatherchannel',
        'webcam',
        'weber',
        'website',
        'wed',
        'wedding',
        'weibo',
        'weir',
        'wf',
        'whoswho',
        'wien',
        'wiki',
        'williamhill',
        'win',
        'windows',
        'wine',
        'winners',
        'wme',
        'wolterskluwer',
        'woodside',
        'work',
        'works',
        'world',
        'wow',
        'ws',
        'wtc',
        'wtf',
        'xbox',
        'xerox',
        'xfinity',
        'xihuan',
        'xin',
        'कॉम',
        'セール',
        '佛山',
        'ಭಾರತ',
        '慈善',
        '集团',
        '在线',
        '한국',
        'ଭାରତ',
        '大众汽车',
        '点看',
        'คอม',
        'ভাৰত',
        'ভারত',
        '八卦',
        'موقع',
        'বাংলা',
        '公益',
        '公司',
        '香格里拉',
        '网站',
        '移动',
        '我爱你',
        'москва',
        'қаз',
        'католик',
        'онлайн',
        'сайт',
        '联通',
        'срб',
        'бг',
        'бел',
        'קום',
        '时尚',
        '微博',
        '淡马锡',
        'ファッション',
        'орг',
        'नेट',
        'ストア',
        '삼성',
        'சிங்கப்பூர்',
        '商标',
        '商店',
        '商城',
        'дети',
        'мкд',
        'ею',
        'ポイント',
        '新闻',
        '工行',
        '家電',
        'كوم',
        '中文网',
        '中信',
        '中国',
        '中國',
        '娱乐',
        '谷歌',
        'భారత్',
        'ලංකා',
        '電訊盈科',
        '购物',
        'クラウド',
        'ભારત',
        '通販',
        'भारतम्',
        'भारत',
        'भारोत',
        '网店',
        'संगठन',
        '餐厅',
        '网络',
        'ком',
        'укр',
        '香港',
        '诺基亚',
        '食品',
        '飞利浦',
        '台湾',
        '台灣',
        '手表',
        '手机',
        'мон',
        'الجزائر',
        'عمان',
        'ارامكو',
        'ایران',
        'العليان',
        'اتصالات',
        'امارات',
        'بازار',
        'موريتانيا',
        'پاکستان',
        'الاردن',
        'بارت',
        'بھارت',
        'المغرب',
        'ابوظبي',
        'البحرين',
        'السعودية',
        'ڀارت',
        'كاثوليك',
        'سودان',
        'همراه',
        'عراق',
        'مليسيا',
        '澳門',
        '닷컴',
        '政府',
        'شبكة',
        'بيتك',
        'عرب',
        'გე',
        '机构',
        '组织机构',
        '健康',
        'ไทย',
        'سورية',
        '招聘',
        'рус',
        'рф',
        '珠宝',
        'تونس',
        '大拿',
        'ລາວ',
        'みんな',
        'グーグル',
        'ευ',
        'ελ',
        '世界',
        '書籍',
        'ഭാരതം',
        'ਭਾਰਤ',
        '网址',
        '닷넷',
        'コム',
        '天主教',
        '游戏',
        'vermögensberater',
        'vermögensberatung',
        '企业',
        '信息',
        '嘉里大酒店',
        '嘉里',
        'مصر',
        'قطر',
        '广东',
        'இலங்கை',
        'இந்தியா',
        'հայ',
        '新加坡',
        'فلسطين',
        '政务',
        'xxx',
        'xyz',
        'yachts',
        'yahoo',
        'yamaxun',
        'yandex',
        'ye',
        'yodobashi',
        'yoga',
        'yokohama',
        'you',
        'youtube',
        'yt',
        'yun',
        'za',
        'zappos',
        'zara',
        'zero',
        'zip',
        'zm',
        'zone',
        'zuerich',
        'zw',
    ];

    // @codingStandardsIgnoreStart
    /**
     * Array for valid Idns
     * @see http://www.iana.org/domains/idn-tables/ Official list of supported IDN Chars
     * (.AC) Ascension Island http://www.nic.ac/pdf/AC-IDN-Policy.pdf
     * (.AR) Argentina http://www.nic.ar/faqidn.html
     * (.AS) American Samoa http://www.nic.as/idn/chars.cfm
     * (.AT) Austria http://www.nic.at/en/service/technical_information/idn/charset_converter/
     * (.BIZ) International http://www.iana.org/domains/idn-tables/
     * (.BR) Brazil http://registro.br/faq/faq6.html
     * (.BV) Bouvett Island http://www.norid.no/domeneregistrering/idn/idn_nyetegn.en.html
     * (.CAT) Catalan http://www.iana.org/domains/idn-tables/tables/cat_ca_1.0.html
     * (.CH) Switzerland https://nic.switch.ch/reg/ocView.action?res=EF6GW2JBPVTG67DLNIQXU234MN6SC33JNQQGI7L6#anhang1
     * (.CL) Chile http://www.iana.org/domains/idn-tables/tables/cl_latn_1.0.html
     * (.COM) International http://www.verisign.com/information-services/naming-services/internationalized-domain-names/index.html
     * (.DE) Germany https://www.denic.de/en/know-how/idn-domains/idn-character-list/
     * (.DK) Danmark http://www.dk-hostmaster.dk/index.php?id=151
     * (.EE) Estonia https://www.iana.org/domains/idn-tables/tables/pl_et-pl_1.0.html
     * (.ES) Spain https://www.nic.es/media/2008-05/1210147705287.pdf
     * (.FI) Finland http://www.ficora.fi/en/index/palvelut/fiverkkotunnukset/aakkostenkaytto.html
     * (.GR) Greece https://grweb.ics.forth.gr/CharacterTable1_en.jsp
     * (.HR) Croatia https://www.dns.hr/en/portal/files/Odluka-1,2alfanum-dijak.pdf
     * (.HU) Hungary http://www.domain.hu/domain/English/szabalyzat/szabalyzat.html
     * (.IL) Israel http://www.isoc.org.il/domains/il-domain-rules.html
     * (.INFO) International http://www.nic.info/info/idn
     * (.IO) British Indian Ocean Territory http://www.nic.io/IO-IDN-Policy.pdf
     * (.IR) Iran http://www.nic.ir/Allowable_Characters_dot-iran
     * (.IS) Iceland https://www.isnic.is/en/domain/rules#2
     * (.KR) Korea http://www.iana.org/domains/idn-tables/tables/kr_ko-kr_1.0.html
     * (.LI) Liechtenstein https://nic.switch.ch/reg/ocView.action?res=EF6GW2JBPVTG67DLNIQXU234MN6SC33JNQQGI7L6#anhang1
     * (.LT) Lithuania http://www.domreg.lt/static/doc/public/idn_symbols-en.pdf
     * (.MD) Moldova http://www.register.md/
     * (.MUSEUM) International http://www.iana.org/domains/idn-tables/tables/museum_latn_1.0.html
     * (.NET) International http://www.verisign.com/information-services/naming-services/internationalized-domain-names/index.html
     * (.NO) Norway http://www.norid.no/domeneregistrering/idn/idn_nyetegn.en.html
     * (.NU) Niue http://www.worldnames.net/
     * (.ORG) International http://www.pir.org/index.php?db=content/FAQs&tbl=FAQs_Registrant&id=2
     * (.PE) Peru https://www.nic.pe/nuevas_politicas_faq_2.php
     * (.PL) Poland http://www.dns.pl/IDN/allowed_character_sets.pdf
     * (.PR) Puerto Rico http://www.nic.pr/idn_rules.asp
     * (.PT) Portugal https://online.dns.pt/dns_2008/do?com=DS;8216320233;111;+PAGE(4000058)+K-CAT-CODIGO(C.125)+RCNT(100);
     * (.RU) Russia http://www.iana.org/domains/idn-tables/tables/ru_ru-ru_1.0.html
     * (.SA) Saudi Arabia http://www.iana.org/domains/idn-tables/tables/sa_ar_1.0.html
     * (.SE) Sweden http://www.iis.se/english/IDN_campaignsite.shtml?lang=en
     * (.SH) Saint Helena http://www.nic.sh/SH-IDN-Policy.pdf
     * (.SJ) Svalbard and Jan Mayen http://www.norid.no/domeneregistrering/idn/idn_nyetegn.en.html
     * (.TH) Thailand http://www.iana.org/domains/idn-tables/tables/th_th-th_1.0.html
     * (.TM) Turkmenistan http://www.nic.tm/TM-IDN-Policy.pdf
     * (.TR) Turkey https://www.nic.tr/index.php
     * (.UA) Ukraine http://www.iana.org/domains/idn-tables/tables/ua_cyrl_1.2.html
     * (.VE) Venice http://www.iana.org/domains/idn-tables/tables/ve_es_1.0.html
     * (.VN) Vietnam http://www.vnnic.vn/english/5-6-300-2-2-04-20071115.htm#1.%20Introduction
     *
     * @var array
     */
    protected $validIdns = [
        'AC'  => [1 => '/^[\x{002d}0-9a-zà-öø-ÿāăąćĉċčďđēėęěĝġģĥħīįĵķĺļľŀłńņňŋőœŕŗřśŝşšţťŧūŭůűųŵŷźżž]{1,63}$/iu'],
        'AR'  => [1 => '/^[\x{002d}0-9a-zà-ãç-êìíñ-õü]{1,63}$/iu'],
        'AS'  => [1 => '/^[\x{002d}0-9a-zà-öø-ÿāăąćĉċčďđēĕėęěĝğġģĥħĩīĭįıĵķĸĺļľłńņňŋōŏőœŕŗřśŝşšţťŧũūŭůűųŵŷźż]{1,63}$/iu'],
        'AT'  => [1 => '/^[\x{002d}0-9a-zà-öø-ÿœšž]{1,63}$/iu'],
        'BIZ' => 'Hostname/Biz.php',
        'BR'  => [1 => '/^[\x{002d}0-9a-zà-ãçéíó-õúü]{1,63}$/iu'],
        'BV'  => [1 => '/^[\x{002d}0-9a-zàáä-éêñ-ôöøüčđńŋšŧž]{1,63}$/iu'],
        'CAT' => [1 => '/^[\x{002d}0-9a-z·àç-éíïòóúü]{1,63}$/iu'],
        'CH'  => [1 => '/^[\x{002d}0-9a-zà-öø-ÿœ]{1,63}$/iu'],
        'CL'  => [1 => '/^[\x{002d}0-9a-záéíñóúü]{1,63}$/iu'],
        'CN'  => 'Hostname/Cn.php',
        'COM' => 'Hostname/Com.php',
        'DE'  => [1 => '/^[\x{002d}0-9a-záàăâåäãąāæćĉčċçďđéèĕêěëėęēğĝġģĥħíìĭîïĩįīıĵķĺľļłńňñņŋóòŏôöőõøōœĸŕřŗśŝšşßťţŧúùŭûůüűũųūŵýŷÿźžżðþ]{1,63}$/iu'],
        'DK'  => [1 => '/^[\x{002d}0-9a-zäåæéöøü]{1,63}$/iu'],
        'EE'  => [1 => '/^[\x{002d}0-9a-zäõöüšž]{1,63}$/iu'],
        'ES'  => [1 => '/^[\x{002d}0-9a-zàáçèéíïñòóúü·]{1,63}$/iu'],
        'EU'  => [1 => '/^[\x{002d}0-9a-zà-öø-ÿ]{1,63}$/iu',
            2 => '/^[\x{002d}0-9a-zāăąćĉċčďđēĕėęěĝğġģĥħĩīĭįıĵķĺļľŀłńņňʼnŋōŏőœŕŗřśŝšťŧũūŭůűųŵŷźżž]{1,63}$/iu',
            3 => '/^[\x{002d}0-9a-zșț]{1,63}$/iu',
            4 => '/^[\x{002d}0-9a-zΐάέήίΰαβγδεζηθικλμνξοπρςστυφχψωϊϋόύώ]{1,63}$/iu',
            5 => '/^[\x{002d}0-9a-zабвгдежзийклмнопрстуфхцчшщъыьэюя]{1,63}$/iu',
            6 => '/^[\x{002d}0-9a-zἀ-ἇἐ-ἕἠ-ἧἰ-ἷὀ-ὅὐ-ὗὠ-ὧὰ-ὼώᾀ-ᾇᾐ-ᾗᾠ-ᾧᾰ-ᾴᾶᾷῂῃῄῆῇῐ-ῒΐῖῗῠ-ῧῲῳῴῶῷ]{1,63}$/iu'],
        'FI'  => [1 => '/^[\x{002d}0-9a-zäåö]{1,63}$/iu'],
        'GR'  => [1 => '/^[\x{002d}0-9a-zΆΈΉΊΌΎ-ΡΣ-ώἀ-ἕἘ-Ἕἠ-ὅὈ-Ὅὐ-ὗὙὛὝὟ-ώᾀ-ᾴᾶ-ᾼῂῃῄῆ-ῌῐ-ΐῖ-Ίῠ-Ῥῲῳῴῶ-ῼ]{1,63}$/iu'],
        'HK'  => 'Hostname/Cn.php',
        'HR'  => [1 => '/^[\x{002d}0-9a-zžćčđš]{1,63}$/iu'],
        'HU'  => [1 => '/^[\x{002d}0-9a-záéíóöúüőű]{1,63}$/iu'],
        'IL'  => [1 => '/^[\x{002d}0-9\x{05D0}-\x{05EA}]{1,63}$/iu',
            2 => '/^[\x{002d}0-9a-z]{1,63}$/i'],
        'INFO' => [1 => '/^[\x{002d}0-9a-zäåæéöøü]{1,63}$/iu',
            2 => '/^[\x{002d}0-9a-záéíóöúüőű]{1,63}$/iu',
            3 => '/^[\x{002d}0-9a-záæéíðóöúýþ]{1,63}$/iu',
            4 => '/^[\x{AC00}-\x{D7A3}]{1,17}$/iu',
            5 => '/^[\x{002d}0-9a-zāčēģīķļņōŗšūž]{1,63}$/iu',
            6 => '/^[\x{002d}0-9a-ząčėęįšūųž]{1,63}$/iu',
            7 => '/^[\x{002d}0-9a-zóąćęłńśźż]{1,63}$/iu',
            8 => '/^[\x{002d}0-9a-záéíñóúü]{1,63}$/iu'],
        'IO'  => [1 => '/^[\x{002d}0-9a-zà-öø-ÿăąāćĉčċďđĕěėęēğĝġģĥħĭĩįīıĵķĺľļłńňņŋŏőōœĸŕřŗśŝšşťţŧŭůűũųūŵŷźžż]{1,63}$/iu'],
        'IS'  => [1 => '/^[\x{002d}0-9a-záéýúíóþæöð]{1,63}$/iu'],
        'IT'  => [1 => '/^[\x{002d}0-9a-zàâäèéêëìîïòôöùûüæœçÿß-]{1,63}$/iu'],
        'JP'  => 'Hostname/Jp.php',
        'KR'  => [1 => '/^[\x{AC00}-\x{D7A3}]{1,17}$/iu'],
        'LI'  => [1 => '/^[\x{002d}0-9a-zà-öø-ÿœ]{1,63}$/iu'],
        'LT'  => [1 => '/^[\x{002d}0-9ąčęėįšųūž]{1,63}$/iu'],
        'MD'  => [1 => '/^[\x{002d}0-9ăâîşţ]{1,63}$/iu'],
        'MUSEUM' => [1 => '/^[\x{002d}0-9a-zà-öø-ÿāăąćċčďđēėęěğġģħīįıķĺļľłńņňŋōőœŕŗřśşšţťŧūůűųŵŷźżžǎǐǒǔ\x{01E5}\x{01E7}\x{01E9}\x{01EF}ə\x{0292}ẁẃẅỳ]{1,63}$/iu'],
        'NET' => 'Hostname/Com.php',
        'NO'  => [1 => '/^[\x{002d}0-9a-zàáä-éêñ-ôöøüčđńŋšŧž]{1,63}$/iu'],
        'NU'  => 'Hostname/Com.php',
        'ORG' => [1 => '/^[\x{002d}0-9a-záéíñóúü]{1,63}$/iu',
            2 => '/^[\x{002d}0-9a-zóąćęłńśźż]{1,63}$/iu',
            3 => '/^[\x{002d}0-9a-záäåæéëíðóöøúüýþ]{1,63}$/iu',
            4 => '/^[\x{002d}0-9a-záéíóöúüőű]{1,63}$/iu',
            5 => '/^[\x{002d}0-9a-ząčėęįšūųž]{1,63}$/iu',
            6 => '/^[\x{AC00}-\x{D7A3}]{1,17}$/iu',
            7 => '/^[\x{002d}0-9a-zāčēģīķļņōŗšūž]{1,63}$/iu'],
        'PE'  => [1 => '/^[\x{002d}0-9a-zñáéíóúü]{1,63}$/iu'],
        'PL'  => [1 => '/^[\x{002d}0-9a-zāčēģīķļņōŗšūž]{1,63}$/iu',
            2 => '/^[\x{002d}а-ик-ш\x{0450}ѓѕјљњќџ]{1,63}$/iu',
            3 => '/^[\x{002d}0-9a-zâîăşţ]{1,63}$/iu',
            4 => '/^[\x{002d}0-9а-яё\x{04C2}]{1,63}$/iu',
            5 => '/^[\x{002d}0-9a-zàáâèéêìíîòóôùúûċġħż]{1,63}$/iu',
            6 => '/^[\x{002d}0-9a-zàäåæéêòóôöøü]{1,63}$/iu',
            7 => '/^[\x{002d}0-9a-zóąćęłńśźż]{1,63}$/iu',
            8 => '/^[\x{002d}0-9a-zàáâãçéêíòóôõúü]{1,63}$/iu',
            9 => '/^[\x{002d}0-9a-zâîăşţ]{1,63}$/iu',
            10 => '/^[\x{002d}0-9a-záäéíóôúýčďĺľňŕšťž]{1,63}$/iu',
            11 => '/^[\x{002d}0-9a-zçë]{1,63}$/iu',
            12 => '/^[\x{002d}0-9а-ик-шђјљњћџ]{1,63}$/iu',
            13 => '/^[\x{002d}0-9a-zćčđšž]{1,63}$/iu',
            14 => '/^[\x{002d}0-9a-zâçöûüğış]{1,63}$/iu',
            15 => '/^[\x{002d}0-9a-záéíñóúü]{1,63}$/iu',
            16 => '/^[\x{002d}0-9a-zäõöüšž]{1,63}$/iu',
            17 => '/^[\x{002d}0-9a-zĉĝĥĵŝŭ]{1,63}$/iu',
            18 => '/^[\x{002d}0-9a-zâäéëîô]{1,63}$/iu',
            19 => '/^[\x{002d}0-9a-zàáâäåæçèéêëìíîïðñòôöøùúûüýćčłńřśš]{1,63}$/iu',
            20 => '/^[\x{002d}0-9a-zäåæõöøüšž]{1,63}$/iu',
            21 => '/^[\x{002d}0-9a-zàáçèéìíòóùú]{1,63}$/iu',
            22 => '/^[\x{002d}0-9a-zàáéíóöúüőű]{1,63}$/iu',
            23 => '/^[\x{002d}0-9ΐά-ώ]{1,63}$/iu',
            24 => '/^[\x{002d}0-9a-zàáâåæçèéêëðóôöøüþœ]{1,63}$/iu',
            25 => '/^[\x{002d}0-9a-záäéíóöúüýčďěňřšťůž]{1,63}$/iu',
            26 => '/^[\x{002d}0-9a-z·àçèéíïòóúü]{1,63}$/iu',
            27 => '/^[\x{002d}0-9а-ъьюя\x{0450}\x{045D}]{1,63}$/iu',
            28 => '/^[\x{002d}0-9а-яёіў]{1,63}$/iu',
            29 => '/^[\x{002d}0-9a-ząčėęįšūųž]{1,63}$/iu',
            30 => '/^[\x{002d}0-9a-záäåæéëíðóöøúüýþ]{1,63}$/iu',
            31 => '/^[\x{002d}0-9a-zàâæçèéêëîïñôùûüÿœ]{1,63}$/iu',
            32 => '/^[\x{002d}0-9а-щъыьэюяёєіїґ]{1,63}$/iu',
            33 => '/^[\x{002d}0-9א-ת]{1,63}$/iu'],
        'PR'  => [1 => '/^[\x{002d}0-9a-záéíóúñäëïüöâêîôûàèùæçœãõ]{1,63}$/iu'],
        'PT'  => [1 => '/^[\x{002d}0-9a-záàâãçéêíóôõú]{1,63}$/iu'],
        'RS'  => [1 => '/^[\x{002d}0-9a-zßáâäçéëíîóôöúüýăąćčďđęěĺľłńňőŕřśşšţťůűźżž]{1,63}$/iu'],
        'RU'  => [1 => '/^[\x{002d}0-9а-яё]{1,63}$/iu'],
        'SA'  => [1 => '/^[\x{002d}.0-9\x{0621}-\x{063A}\x{0641}-\x{064A}\x{0660}-\x{0669}]{1,63}$/iu'],
        'SE'  => [1 => '/^[\x{002d}0-9a-zäåéöü]{1,63}$/iu'],
        'SH'  => [1 => '/^[\x{002d}0-9a-zà-öø-ÿăąāćĉčċďđĕěėęēğĝġģĥħĭĩįīıĵķĺľļłńňņŋŏőōœĸŕřŗśŝšşťţŧŭůűũųūŵŷźžż]{1,63}$/iu'],
        'SI'  => [
            1 => '/^[\x{002d}0-9a-zà-öø-ÿ]{1,63}$/iu',
            2 => '/^[\x{002d}0-9a-zāăąćĉċčďđēĕėęěĝğġģĥħĩīĭįıĵķĺļľŀłńņňʼnŋōŏőœŕŗřśŝšťŧũūŭůűųŵŷźżž]{1,63}$/iu',
            3 => '/^[\x{002d}0-9a-zșț]{1,63}$/iu'],
        'SJ'  => [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',
        'TR'  => [1 => '/^[\x{002d}0-9a-zğıüşöç]{1,63}$/iu'],
        'UA'  => [1 => '/^[\x{002d}0-9a-zабвгдежзийклмнопрстуфхцчшщъыьэюяѐёђѓєѕіїјљњћќѝўџґӂʼ]{1,63}$/iu'],
        'VE'  => [1 => '/^[\x{002d}0-9a-záéíóúüñ]{1,63}$/iu'],
        'VN'  => [1 => '/^[ÀÁÂÃÈÉÊÌÍÒÓÔÕÙÚÝàáâãèéêìíòóôõùúýĂăĐđĨĩŨũƠơƯư\x{1EA0}-\x{1EF9}]{1,63}$/iu'],
        'мон' => [1 => '/^[\x{002d}0-9\x{0430}-\x{044F}]{1,63}$/iu'],
        'срб' => [1 => '/^[\x{002d}0-9а-ик-шђјљњћџ]{1,63}$/iu'],
        'сайт' => [1 => '/^[\x{002d}0-9а-яёіїѝйўґг]{1,63}$/iu'],
        'онлайн' => [1 => '/^[\x{002d}0-9а-яёіїѝйўґг]{1,63}$/iu'],
        '中国' => 'Hostname/Cn.php',
        '中國' => 'Hostname/Cn.php',
        'ලංකා' => [1 => '/^[\x{0d80}-\x{0dff}]{1,63}$/iu'],
        '香港' => 'Hostname/Cn.php',
        '台湾' => 'Hostname/Cn.php',
        '台灣' => 'Hostname/Cn.php',
        'امارات'   => [1 => '/^[\x{0621}-\x{0624}\x{0626}-\x{063A}\x{0641}\x{0642}\x{0644}-\x{0648}\x{067E}\x{0686}\x{0698}\x{06A9}\x{06AF}\x{06CC}\x{06F0}-\x{06F9}]{1,30}$/iu'],
        'الاردن'    => [1 => '/^[\x{0621}-\x{0624}\x{0626}-\x{063A}\x{0641}\x{0642}\x{0644}-\x{0648}\x{067E}\x{0686}\x{0698}\x{06A9}\x{06AF}\x{06CC}\x{06F0}-\x{06F9}]{1,30}$/iu'],
        'السعودية' => [1 => '/^[\x{0621}-\x{0624}\x{0626}-\x{063A}\x{0641}\x{0642}\x{0644}-\x{0648}\x{067E}\x{0686}\x{0698}\x{06A9}\x{06AF}\x{06CC}\x{06F0}-\x{06F9}]{1,30}$/iu'],
        'ไทย' => [1 => '/^[\x{002d}0-9a-z\x{0E01}-\x{0E3A}\x{0E40}-\x{0E4D}\x{0E50}-\x{0E59}]{1,63}$/iu'],
        'рф' => [1 => '/^[\x{002d}0-9а-яё]{1,63}$/iu'],
        'تونس' => [1 => '/^[\x{0621}-\x{0624}\x{0626}-\x{063A}\x{0641}\x{0642}\x{0644}-\x{0648}\x{067E}\x{0686}\x{0698}\x{06A9}\x{06AF}\x{06CC}\x{06F0}-\x{06F9}]{1,30}$/iu'],
        'مصر' => [1 => '/^[\x{0621}-\x{0624}\x{0626}-\x{063A}\x{0641}\x{0642}\x{0644}-\x{0648}\x{067E}\x{0686}\x{0698}\x{06A9}\x{06AF}\x{06CC}\x{06F0}-\x{06F9}]{1,30}$/iu'],
        'இலங்கை' => [1 => '/^[\x{0b80}-\x{0bff}]{1,63}$/iu'],
        'فلسطين' => [1 => '/^[\x{0621}-\x{0624}\x{0626}-\x{063A}\x{0641}\x{0642}\x{0644}-\x{0648}\x{067E}\x{0686}\x{0698}\x{06A9}\x{06AF}\x{06CC}\x{06F0}-\x{06F9}]{1,30}$/iu'],
        'شبكة'  => [1 => '/^[\x{0621}-\x{0624}\x{0626}-\x{063A}\x{0641}\x{0642}\x{0644}-\x{0648}\x{067E}\x{0686}\x{0698}\x{06A9}\x{06AF}\x{06CC}\x{06F0}-\x{06F9}]{1,30}$/iu'],
    ];
    // @codingStandardsIgnoreEnd

    protected $idnLength = [
        'BIZ' => [5 => 17, 11 => 15, 12 => 20],
        'CN'  => [1 => 20],
        'COM' => [3 => 17, 5 => 20],
        'HK'  => [1 => 15],
        'INFO' => [4 => 17],
        'KR'  => [1 => 17],
        'NET' => [3 => 17, 5 => 20],
        'ORG' => [6 => 17],
        'TW'  => [1 => 20],
        'امارات' => [1 => 30],
        'الاردن' => [1 => 30],
        'السعودية' => [1 => 30],
        'تونس' => [1 => 30],
        'مصر' => [1 => 30],
        'فلسطين' => [1 => 30],
        'شبكة' => [1 => 30],
        '中国' => [1 => 20],
        '中國' => [1 => 20],
        '香港' => [1 => 20],
        '台湾' => [1 => 20],
        '台灣' => [1 => 20],
    ];

    protected $tld;

    /**
     * Options for the hostname validator
     *
     * @var array
     */
    protected $options = [
        'allow'       => self::ALLOW_DNS, // Allow these hostnames
        'useIdnCheck' => true,  // Check IDN domains
        'useTldCheck' => true,  // Check TLD elements
        'ipValidator' => null,  // IP validator to use
    ];

    /**
     * Sets validator options.
     *
     * @param int  $allow       OPTIONAL Set what types of hostname to allow (default ALLOW_DNS)
     * @param bool $useIdnCheck OPTIONAL Set whether IDN domains are validated (default true)
     * @param bool $useTldCheck Set whether the TLD element of a hostname is validated (default true)
     * @param Ip   $ipValidator OPTIONAL
     * @see http://www.iana.org/cctld/specifications-policies-cctlds-01apr02.htm  Technical Specifications for ccTLDs
     */
    public function __construct($options = [])
    {
        if (! is_array($options)) {
            $options = func_get_args();
            $temp['allow'] = array_shift($options);
            if (! empty($options)) {
                $temp['useIdnCheck'] = array_shift($options);
            }

            if (! empty($options)) {
                $temp['useTldCheck'] = array_shift($options);
            }

            if (! empty($options)) {
                $temp['ipValidator'] = array_shift($options);
            }

            $options = $temp;
        }

        if (! array_key_exists('ipValidator', $options)) {
            $options['ipValidator'] = null;
        }

        parent::__construct($options);
    }

    /**
     * Returns the set ip validator
     *
     * @return Ip
     */
    public function getIpValidator()
    {
        return $this->options['ipValidator'];
    }

    /**
     *
     * @param Ip $ipValidator OPTIONAL
     * @return Hostname;
     */
    public function setIpValidator(Ip $ipValidator = null)
    {
        if ($ipValidator === null) {
            $ipValidator = new Ip();
        }

        $this->options['ipValidator'] = $ipValidator;
        return $this;
    }

    /**
     * Returns the allow option
     *
     * @return int
     */
    public function getAllow()
    {
        return $this->options['allow'];
    }

    /**
     * Sets the allow option
     *
     * @param  int $allow
     * @return $this Provides a fluent interface
     */
    public function setAllow($allow)
    {
        $this->options['allow'] = $allow;
        return $this;
    }

    /**
     * Returns the set idn option
     *
     * @return bool
     */
    public function getIdnCheck()
    {
        return $this->options['useIdnCheck'];
    }

    /**
     * Set whether IDN domains are validated
     *
     * This only applies when DNS hostnames are validated
     *
     * @param  bool $useIdnCheck Set to true to validate IDN domains
     * @return $this
     */
    public function useIdnCheck($useIdnCheck)
    {
        $this->options['useIdnCheck'] = (bool) $useIdnCheck;
        return $this;
    }

    /**
     * Returns the set tld option
     *
     * @return bool
     */
    public function getTldCheck()
    {
        return $this->options['useTldCheck'];
    }

    /**
     * Set whether the TLD element of a hostname is validated
     *
     * This only applies when DNS hostnames are validated
     *
     * @param  bool $useTldCheck Set to true to validate TLD elements
     * @return $this
     */
    public function useTldCheck($useTldCheck)
    {
        $this->options['useTldCheck'] = (bool) $useTldCheck;
        return $this;
    }

    /**
     * Defined by Interface
     *
     * Returns true if and only if the $value is a valid hostname with respect to the current allow option
     *
     * @param  string $value
     * @return bool
     */
    public function isValid($value)
    {
        if (! is_string($value)) {
            $this->error(self::INVALID);
            return false;
        }

        $this->setValue($value);
        // Check input against IP address schema
        if (((preg_match('/^[0-9.]*$/', $value) && strpos($value, '.') !== false)
                || (preg_match('/^[0-9a-f:.]*$/i', $value) && strpos($value, ':') !== false))
            && $this->getIpValidator()->setTranslator($this->getTranslator())->isValid($value)
        ) {
            if (! ($this->getAllow() & self::ALLOW_IP)) {
                $this->error(self::IP_ADDRESS_NOT_ALLOWED);
                return false;
            }

            return true;
        }

        // Local hostnames are allowed to be partial (ending '.')
        if ($this->getAllow() & self::ALLOW_LOCAL) {
            if (substr($value, -1) === '.') {
                $value = substr($value, 0, -1);
                if (substr($value, -1) === '.') {
                    // Empty hostnames (ending '..') are not allowed
                    $this->error(self::INVALID_LOCAL_NAME);
                    return false;
                }
            }
        }

        $domainParts = explode('.', $value);

        // Prevent partial IP V4 addresses (ending '.')
        if (count($domainParts) == 4 && preg_match('/^[0-9.a-e:.]*$/i', $value)
            && $this->getIpValidator()->setTranslator($this->getTranslator())->isValid($value)
        ) {
            $this->error(self::INVALID_LOCAL_NAME);
        }

        $utf8StrWrapper = StringUtils::getWrapper('UTF-8');

        // Check input against DNS hostname schema
        if (count($domainParts) > 1
            && $utf8StrWrapper->strlen($value) >= 4
            && $utf8StrWrapper->strlen($value) <= 254
        ) {
            $status = false;

            do {
                // First check TLD
                $matches = [];
                if (preg_match('/([^.]{2,63})$/u', end($domainParts), $matches)
                    || (array_key_exists(end($domainParts), $this->validIdns))
                ) {
                    reset($domainParts);

                    // Hostname characters are: *(label dot)(label dot label); max 254 chars
                    // label: id-prefix [*ldh{61} id-prefix]; max 63 chars
                    // id-prefix: alpha / digit
                    // ldh: alpha / digit / dash

                    $this->tld = $matches[1];
                    // Decode Punycode TLD to IDN
                    if (strpos($this->tld, 'xn--') === 0) {
                        $this->tld = $this->decodePunycode(substr($this->tld, 4));
                        if ($this->tld === false) {
                            return false;
                        }
                    } else {
                        $this->tld = strtoupper($this->tld);
                    }

                    // Match TLD against known list
                    $removedTld = false;
                    if ($this->getTldCheck()) {
                        if (! in_array(strtolower($this->tld), $this->validTlds)
                            && ! in_array($this->tld, $this->validTlds)) {
                            $this->error(self::UNKNOWN_TLD);
                            $status = false;
                            break;
                        }
                        // We have already validated that the TLD is fine. We don't want it to go through the below
                        // checks as new UTF-8 TLDs will incorrectly fail if there is no IDN regex for it.
                        array_pop($domainParts);
                        $removedTld = true;
                    }

                    /**
                     * Match against IDN hostnames
                     * Note: Keep label regex short to avoid issues with long patterns when matching IDN hostnames
                     *
                     * @see Hostname\Interface
                     */
                    $regexChars = [0 => '/^[a-z0-9\x2d]{1,63}$/i'];
                    if ($this->getIdnCheck() && isset($this->validIdns[$this->tld])) {
                        if (is_string($this->validIdns[$this->tld])) {
                            $regexChars += include __DIR__ . '/' . $this->validIdns[$this->tld];
                        } else {
                            $regexChars += $this->validIdns[$this->tld];
                        }
                    }

                    // Check each hostname part
                    $check = 0;
                    $lastDomainPart = end($domainParts);
                    if (! $removedTld) {
                        $lastDomainPart = prev($domainParts);
                    }
                    foreach ($domainParts as $domainPart) {
                        // Decode Punycode domain names to IDN
                        if (strpos($domainPart, 'xn--') === 0) {
                            $domainPart = $this->decodePunycode(substr($domainPart, 4));
                            if ($domainPart === false) {
                                return false;
                            }
                        }

                        // Skip following checks if domain part is empty, as it definitely is not a valid hostname then
                        if ($domainPart === '') {
                            $this->error(self::INVALID_HOSTNAME);
                            $status = false;
                            break 2;
                        }

                        // Check dash (-) does not start, end or appear in 3rd and 4th positions
                        if ($utf8StrWrapper->strpos($domainPart, '-') === 0
                            || ($utf8StrWrapper->strlen($domainPart) > 2
                                && $utf8StrWrapper->strpos($domainPart, '-', 2) == 2
                                && $utf8StrWrapper->strpos($domainPart, '-', 3) == 3
                            )
                            || $utf8StrWrapper->substr($domainPart, -1) === '-'
                        ) {
                            $this->error(self::INVALID_DASH);
                            $status = false;
                            break 2;
                        }

                        // Check each domain part
                        $checked = false;
                        $isSubDomain = $domainPart != $lastDomainPart;
                        $partRegexChars = $isSubDomain ? ['/^[a-z0-9_\x2d]{1,63}$/i'] + $regexChars : $regexChars;
                        foreach ($partRegexChars as $regexKey => $regexChar) {
                            $status = preg_match($regexChar, $domainPart);
                            if ($status > 0) {
                                $length = 63;
                                if (array_key_exists($this->tld, $this->idnLength)
                                    && array_key_exists($regexKey, $this->idnLength[$this->tld])
                                ) {
                                    $length = $this->idnLength[$this->tld];
                                }

                                if ($utf8StrWrapper->strlen($domainPart) > $length) {
                                    $this->error(self::INVALID_HOSTNAME);
                                    $status = false;
                                } else {
                                    $checked = true;
                                    break;
                                }
                            }
                        }

                        if ($checked) {
                            ++$check;
                        }
                    }

                    // If one of the labels doesn't match, the hostname is invalid
                    if ($check !== count($domainParts)) {
                        $this->error(self::INVALID_HOSTNAME_SCHEMA);
                        $status = false;
                    }
                } else {
                    // Hostname not long enough
                    $this->error(self::UNDECIPHERABLE_TLD);
                    $status = false;
                }
            } while (false);

            // If the input passes as an Internet domain name, and domain names are allowed, then the hostname
            // passes validation
            if ($status && ($this->getAllow() & self::ALLOW_DNS)) {
                return true;
            }
        } elseif ($this->getAllow() & self::ALLOW_DNS) {
            $this->error(self::INVALID_HOSTNAME);
        }

        // Check for URI Syntax (RFC3986)
        if ($this->getAllow() & self::ALLOW_URI) {
            if (preg_match("/^([a-zA-Z0-9-._~!$&\'()*+,;=]|%[[:xdigit:]]{2}){1,254}$/i", $value)) {
                return true;
            }

            $this->error(self::INVALID_URI);
        }

        // Check input against local network name schema; last chance to pass validation
        $regexLocal = '/^(([a-zA-Z0-9\x2d]{1,63}\x2e)*[a-zA-Z0-9\x2d]{1,63}[\x2e]{0,1}){1,254}$/';
        $status = preg_match($regexLocal, $value);

        // If the input passes as a local network name, and local network names are allowed, then the
        // hostname passes validation
        $allowLocal = $this->getAllow() & self::ALLOW_LOCAL;
        if ($status && $allowLocal) {
            return true;
        }

        // If the input does not pass as a local network name, add a message
        if (! $status) {
            $this->error(self::INVALID_LOCAL_NAME);
        }

        // If local network names are not allowed, add a message
        if ($status && ! $allowLocal) {
            $this->error(self::LOCAL_NAME_NOT_ALLOWED);
        }

        return false;
    }

    /**
     * Decodes a punycode encoded string to it's original utf8 string
     * Returns false in case of a decoding failure.
     *
     * @param  string $encoded Punycode encoded string to decode
     * @return string|false
     */
    protected function decodePunycode($encoded)
    {
        if (! preg_match('/^[a-z0-9-]+$/i', $encoded)) {
            // no punycode encoded string
            $this->error(self::CANNOT_DECODE_PUNYCODE);
            return false;
        }

        $decoded = [];
        $separator = strrpos($encoded, '-');
        if ($separator > 0) {
            for ($x = 0; $x < $separator; ++$x) {
                // prepare decoding matrix
                $decoded[] = ord($encoded[$x]);
            }
        }

        $lengthd = count($decoded);
        $lengthe = strlen($encoded);

        // decoding
        $init  = true;
        $base  = 72;
        $index = 0;
        $char  = 0x80;

        for ($indexe = ($separator) ? ($separator + 1) : 0; $indexe < $lengthe; ++$lengthd) {
            for ($oldIndex = $index, $pos = 1, $key = 36; 1; $key += 36) {
                $hex   = ord($encoded[$indexe++]);
                $digit = ($hex - 48 < 10) ? $hex - 22
                       : (($hex - 65 < 26) ? $hex - 65
                       : (($hex - 97 < 26) ? $hex - 97
                       : 36));

                $index += $digit * $pos;
                $tag    = ($key <= $base) ? 1 : (($key >= $base + 26) ? 26 : ($key - $base));
                if ($digit < $tag) {
                    break;
                }

                $pos = (int) ($pos * (36 - $tag));
            }

            $delta   = intval($init ? (($index - $oldIndex) / 700) : (($index - $oldIndex) / 2));
            $delta  += intval($delta / ($lengthd + 1));
            for ($key = 0; $delta > 910 / 2; $key += 36) {
                $delta = intval($delta / 35);
            }

            $base   = intval($key + 36 * $delta / ($delta + 38));
            $init   = false;
            $char  += (int) ($index / ($lengthd + 1));
            $index %= ($lengthd + 1);
            if ($lengthd > 0) {
                for ($i = $lengthd; $i > $index; $i--) {
                    $decoded[$i] = $decoded[($i - 1)];
                }
            }

            $decoded[$index++] = $char;
        }

        // convert decoded ucs4 to utf8 string
        foreach ($decoded as $key => $value) {
            if ($value < 128) {
                $decoded[$key] = chr($value);
            } elseif ($value < (1 << 11)) {
                $decoded[$key]  = chr(192 + ($value >> 6));
                $decoded[$key] .= chr(128 + ($value & 63));
            } elseif ($value < (1 << 16)) {
                $decoded[$key]  = chr(224 + ($value >> 12));
                $decoded[$key] .= chr(128 + (($value >> 6) & 63));
                $decoded[$key] .= chr(128 + ($value & 63));
            } elseif ($value < (1 << 21)) {
                $decoded[$key]  = chr(240 + ($value >> 18));
                $decoded[$key] .= chr(128 + (($value >> 12) & 63));
                $decoded[$key] .= chr(128 + (($value >> 6) & 63));
                $decoded[$key] .= chr(128 + ($value & 63));
            } else {
                $this->error(self::CANNOT_DECODE_PUNYCODE);
                return false;
            }
        }

        return implode($decoded);
    }
}
laminas-validator/src/Uuid.php000064400000003250147361032560012370 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-validator for the canonical source repository
 * @copyright https://github.com/laminas/laminas-validator/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-validator/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Validator;

/**
 * Uuid validator.
 */
final class Uuid extends AbstractValidator
{
    /**
     * Matches Uuid's versions 1 to 5.
     */
    const REGEX_UUID = '/^[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}$/';

    const INVALID = 'valueNotUuid';
    const NOT_STRING = 'valueNotString';

    /**
     * @var array
     */
    protected $messageTemplates = [
        self::NOT_STRING => 'Invalid type given; string expected',
        self::INVALID => 'Invalid UUID format',
    ];

    /**
     * Returns true if and only if $value meets the validation requirements.
     *
     * If $value fails validation, then this method returns false, and
     * getMessages() will return an array of messages that explain why the
     * validation failed.
     *
     * @param mixed $value
     *
     * @return bool
     *
     * @throws Exception\RuntimeException If validation of $value is impossible
     */
    public function isValid($value)
    {
        if (! is_string($value)) {
            $this->error(self::NOT_STRING);
            return false;
        }

        $this->setValue($value);

        if (empty($value)
            || $value !== '00000000-0000-0000-0000-000000000000'
            && ! preg_match(self::REGEX_UUID, $value)
        ) {
            $this->error(self::INVALID);
            return false;
        }

        return true;
    }
}
laminas-validator/src/LessThan.php000064400000007202147361032560013204 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-validator for the canonical source repository
 * @copyright https://github.com/laminas/laminas-validator/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-validator/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Validator;

use Laminas\Stdlib\ArrayUtils;
use Traversable;

class LessThan extends AbstractValidator
{
    const NOT_LESS           = 'notLessThan';
    const NOT_LESS_INCLUSIVE = 'notLessThanInclusive';

    /**
     * Validation failure message template definitions
     *
     * @var array
     */
    protected $messageTemplates = [
        self::NOT_LESS           => "The input is not less than '%max%'",
        self::NOT_LESS_INCLUSIVE => "The input is not less or equal than '%max%'",
    ];

    /**
     * Additional variables available for validation failure messages
     *
     * @var array
     */
    protected $messageVariables = [
        'max' => 'max',
    ];

    /**
     * Maximum value
     *
     * @var mixed
     */
    protected $max;

    /**
     * Whether to do inclusive comparisons, allowing equivalence to max
     *
     * If false, then strict comparisons are done, and the value may equal
     * the max option
     *
     * @var bool
     */
    protected $inclusive;

    /**
     * Sets validator options
     *
     * @param  array|Traversable $options
     * @throws Exception\InvalidArgumentException
     */
    public function __construct($options = null)
    {
        if ($options instanceof Traversable) {
            $options = ArrayUtils::iteratorToArray($options);
        }
        if (! is_array($options)) {
            $options = func_get_args();
            $temp['max'] = array_shift($options);

            if (! empty($options)) {
                $temp['inclusive'] = array_shift($options);
            }

            $options = $temp;
        }

        if (! array_key_exists('max', $options)) {
            throw new Exception\InvalidArgumentException("Missing option 'max'");
        }

        if (! array_key_exists('inclusive', $options)) {
            $options['inclusive'] = false;
        }

        $this->setMax($options['max'])
             ->setInclusive($options['inclusive']);

        parent::__construct($options);
    }

    /**
     * Returns the max option
     *
     * @return mixed
     */
    public function getMax()
    {
        return $this->max;
    }

    /**
     * Sets the max option
     *
     * @param  mixed $max
     * @return $this Provides a fluent interface
     */
    public function setMax($max)
    {
        $this->max = $max;
        return $this;
    }

    /**
     * Returns the inclusive option
     *
     * @return bool
     */
    public function getInclusive()
    {
        return $this->inclusive;
    }

    /**
     * Sets the inclusive option
     *
     * @param  bool $inclusive
     * @return $this Provides a fluent interface
     */
    public function setInclusive($inclusive)
    {
        $this->inclusive = $inclusive;
        return $this;
    }

    /**
     * Returns true if and only if $value is less than max option, inclusively
     * when the inclusive option is true
     *
     * @param  mixed $value
     * @return bool
     */
    public function isValid($value)
    {
        $this->setValue($value);

        if ($this->inclusive) {
            if ($value > $this->max) {
                $this->error(self::NOT_LESS_INCLUSIVE);
                return false;
            }
        } else {
            if ($value >= $this->max) {
                $this->error(self::NOT_LESS);
                return false;
            }
        }

        return true;
    }
}
laminas-validator/src/NotEmpty.php000064400000017332147361032560013247 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-validator for the canonical source repository
 * @copyright https://github.com/laminas/laminas-validator/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-validator/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Validator;

use Laminas\Stdlib\ArrayUtils;
use Traversable;

class NotEmpty extends AbstractValidator
{
    const BOOLEAN       = 0b000000000001;
    const INTEGER       = 0b000000000010;
    const FLOAT         = 0b000000000100;
    const STRING        = 0b000000001000;
    const ZERO          = 0b000000010000;
    const EMPTY_ARRAY   = 0b000000100000;
    const NULL          = 0b000001000000;
    const PHP           = 0b000001111111;
    const SPACE         = 0b000010000000;
    const OBJECT        = 0b000100000000;
    const OBJECT_STRING = 0b001000000000;
    const OBJECT_COUNT  = 0b010000000000;
    const ALL           = 0b011111111111;

    const INVALID  = 'notEmptyInvalid';
    const IS_EMPTY = 'isEmpty';

    protected $constants = [
        self::BOOLEAN       => 'boolean',
        self::INTEGER       => 'integer',
        self::FLOAT         => 'float',
        self::STRING        => 'string',
        self::ZERO          => 'zero',
        self::EMPTY_ARRAY   => 'array',
        self::NULL          => 'null',
        self::PHP           => 'php',
        self::SPACE         => 'space',
        self::OBJECT        => 'object',
        self::OBJECT_STRING => 'objectstring',
        self::OBJECT_COUNT  => 'objectcount',
        self::ALL           => 'all',
    ];

    /**
     * Default value for types; value = 0b000111101001
     *
     * @var array
     */
    protected $defaultType = [
        self::OBJECT,
        self::SPACE,
        self::NULL,
        self::EMPTY_ARRAY,
        self::STRING,
        self::BOOLEAN,
    ];

    /**
     * @var array
     */
    protected $messageTemplates = [
        self::IS_EMPTY => "Value is required and can't be empty",
        self::INVALID  => 'Invalid type given. String, integer, float, boolean or array expected',
    ];

    /**
     * Options for this validator
     *
     * @var array
     */
    protected $options = [];

    /**
     * Constructor
     *
     * @param  array|Traversable|int $options OPTIONAL
     */
    public function __construct($options = null)
    {
        if ($options instanceof Traversable) {
            $options = ArrayUtils::iteratorToArray($options);
        }

        if (! is_array($options)) {
            $options = func_get_args();
            $temp    = [];
            if (! empty($options)) {
                $temp['type'] = array_shift($options);
            }

            $options = $temp;
        }

        if (! isset($options['type'])) {
            if (($type = $this->calculateTypeValue($options)) != 0) {
                $options['type'] = $type;
            } else {
                $options['type'] = $this->defaultType;
            }
        }

        parent::__construct($options);
    }

    /**
     * Returns the set types
     *
     * @return array
     */
    public function getType()
    {
        return $this->options['type'];
    }

    /**
     * @return int
     */
    public function getDefaultType()
    {
        return $this->calculateTypeValue($this->defaultType);
    }

    /**
     * @param array|int|string $type
     * @return int
     */
    protected function calculateTypeValue($type)
    {
        if (is_array($type)) {
            $detected = 0;
            foreach ($type as $value) {
                if (is_int($value)) {
                    $detected |= $value;
                } elseif (in_array($value, $this->constants, true)) {
                    $detected |= array_search($value, $this->constants, true);
                }
            }

            $type = $detected;
        } elseif (is_string($type) && in_array($type, $this->constants, true)) {
            $type = array_search($type, $this->constants, true);
        }

        return $type;
    }

    /**
     * Set the types
     *
     * @param  int|array $type
     * @throws Exception\InvalidArgumentException
     * @return $this
     */
    public function setType($type = null)
    {
        $type = $this->calculateTypeValue($type);

        if (! is_int($type) || ($type < 0) || ($type > self::ALL)) {
            throw new Exception\InvalidArgumentException('Unknown type');
        }

        $this->options['type'] = $type;

        return $this;
    }

    /**
     * Returns true if and only if $value is not an empty value.
     *
     * @param  string $value
     * @return bool
     */
    public function isValid($value)
    {
        if ($value !== null && ! is_string($value) && ! is_int($value) && ! is_float($value) &&
            ! is_bool($value) && ! is_array($value) && ! is_object($value)
        ) {
            $this->error(self::INVALID);
            return false;
        }

        $type    = $this->getType();
        $this->setValue($value);
        $object  = false;

        // OBJECT_COUNT (countable object)
        if ($type & self::OBJECT_COUNT) {
            $object = true;

            if (is_object($value) && $value instanceof \Countable && (count($value) == 0)) {
                $this->error(self::IS_EMPTY);
                return false;
            }
        }

        // OBJECT_STRING (object's toString)
        if ($type & self::OBJECT_STRING) {
            $object = true;

            if ((is_object($value) && (! method_exists($value, '__toString'))) ||
                (is_object($value) && (method_exists($value, '__toString')) && (((string) $value) == ''))) {
                $this->error(self::IS_EMPTY);
                return false;
            }
        }

        // OBJECT (object)
        if ($type & self::OBJECT) {
            // fall trough, objects are always not empty
        } elseif ($object === false) {
            // object not allowed but object given -> return false
            if (is_object($value)) {
                $this->error(self::IS_EMPTY);
                return false;
            }
        }

        // SPACE ('   ')
        if ($type & self::SPACE) {
            if (is_string($value) && (preg_match('/^\s+$/s', $value))) {
                $this->error(self::IS_EMPTY);
                return false;
            }
        }

        // NULL (null)
        if ($type & self::NULL) {
            if ($value === null) {
                $this->error(self::IS_EMPTY);
                return false;
            }
        }

        // EMPTY_ARRAY (array())
        if ($type & self::EMPTY_ARRAY) {
            if (is_array($value) && ($value == [])) {
                $this->error(self::IS_EMPTY);
                return false;
            }
        }

        // ZERO ('0')
        if ($type & self::ZERO) {
            if (is_string($value) && ($value == '0')) {
                $this->error(self::IS_EMPTY);
                return false;
            }
        }

        // STRING ('')
        if ($type & self::STRING) {
            if (is_string($value) && ($value == '')) {
                $this->error(self::IS_EMPTY);
                return false;
            }
        }

        // FLOAT (0.0)
        if ($type & self::FLOAT) {
            if (is_float($value) && ($value == 0.0)) {
                $this->error(self::IS_EMPTY);
                return false;
            }
        }

        // INTEGER (0)
        if ($type & self::INTEGER) {
            if (is_int($value) && ($value == 0)) {
                $this->error(self::IS_EMPTY);
                return false;
            }
        }

        // BOOLEAN (false)
        if ($type & self::BOOLEAN) {
            if (is_bool($value) && ($value == false)) {
                $this->error(self::IS_EMPTY);
                return false;
            }
        }

        return true;
    }
}
laminas-validator/src/EmailAddress.php000064400000044623147361032560014030 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-validator for the canonical source repository
 * @copyright https://github.com/laminas/laminas-validator/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-validator/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Validator;

use UConverter;

class EmailAddress extends AbstractValidator
{
    const INVALID            = 'emailAddressInvalid';
    const INVALID_FORMAT     = 'emailAddressInvalidFormat';
    const INVALID_HOSTNAME   = 'emailAddressInvalidHostname';
    const INVALID_MX_RECORD  = 'emailAddressInvalidMxRecord';
    const INVALID_SEGMENT    = 'emailAddressInvalidSegment';
    const DOT_ATOM           = 'emailAddressDotAtom';
    const QUOTED_STRING      = 'emailAddressQuotedString';
    const INVALID_LOCAL_PART = 'emailAddressInvalidLocalPart';
    const LENGTH_EXCEEDED    = 'emailAddressLengthExceeded';

    // @codingStandardsIgnoreStart
    /**
     * @var array
     */
    protected $messageTemplates = [
        self::INVALID            => "Invalid type given. String expected",
        self::INVALID_FORMAT     => "The input is not a valid email address. Use the basic format local-part@hostname",
        self::INVALID_HOSTNAME   => "'%hostname%' is not a valid hostname for the email address",
        self::INVALID_MX_RECORD  => "'%hostname%' does not appear to have any valid MX or A records for the email address",
        self::INVALID_SEGMENT    => "'%hostname%' is not in a routable network segment. The email address should not be resolved from public network",
        self::DOT_ATOM           => "'%localPart%' can not be matched against dot-atom format",
        self::QUOTED_STRING      => "'%localPart%' can not be matched against quoted-string format",
        self::INVALID_LOCAL_PART => "'%localPart%' is not a valid local part for the email address",
        self::LENGTH_EXCEEDED    => "The input exceeds the allowed length",
    ];
    // @codingStandardsIgnoreEnd

    /**
     * @var array
     */
    protected $messageVariables = [
        'hostname'  => 'hostname',
        'localPart' => 'localPart',
    ];

    /**
     * @var string
     */
    protected $hostname;

    /**
     * @var string
     */
    protected $localPart;

    /**
     * Returns the found mx record information
     *
     * @var array
     */
    protected $mxRecord = [];

    /**
     * Internal options array
     */
    protected $options = [
        'useMxCheck'        => false,
        'useDeepMxCheck'    => false,
        'useDomainCheck'    => true,
        'allow'             => Hostname::ALLOW_DNS,
        'strict'            => true,
        'hostnameValidator' => null,
    ];

    /**
     * Instantiates hostname validator for local use
     *
     * The following additional option keys are supported:
     * 'hostnameValidator' => A hostname validator, see Laminas\Validator\Hostname
     * 'allow'             => Options for the hostname validator, see Laminas\Validator\Hostname::ALLOW_*
     * 'strict'            => Whether to adhere to strictest requirements in the spec
     * 'useMxCheck'        => If MX check should be enabled, boolean
     * 'useDeepMxCheck'    => If a deep MX check should be done, boolean
     *
     * @param array|\Traversable $options OPTIONAL
     */
    public function __construct($options = [])
    {
        if (! is_array($options)) {
            $options = func_get_args();
            $temp['allow'] = array_shift($options);
            if (! empty($options)) {
                $temp['useMxCheck'] = array_shift($options);
            }

            if (! empty($options)) {
                $temp['hostnameValidator'] = array_shift($options);
            }

            $options = $temp;
        }

        parent::__construct($options);
    }

    /**
     * Sets the validation failure message template for a particular key
     * Adds the ability to set messages to the attached hostname validator
     *
     * @param  string $messageString
     * @param  string $messageKey     OPTIONAL
     * @return AbstractValidator Provides a fluent interface
     */
    public function setMessage($messageString, $messageKey = null)
    {
        if ($messageKey === null) {
            $this->getHostnameValidator()->setMessage($messageString);
            parent::setMessage($messageString);
            return $this;
        }

        if (! isset($this->messageTemplates[$messageKey])) {
            $this->getHostnameValidator()->setMessage($messageString, $messageKey);
        } else {
            parent::setMessage($messageString, $messageKey);
        }

        return $this;
    }

    /**
     * Returns the set hostname validator
     *
     * If was not previously set then lazy load a new one
     *
     * @return Hostname
     */
    public function getHostnameValidator()
    {
        if (! isset($this->options['hostnameValidator'])) {
            $this->options['hostnameValidator'] = new Hostname($this->getAllow());
        }

        return $this->options['hostnameValidator'];
    }

    /**
     * @param Hostname $hostnameValidator OPTIONAL
     * @return $this Provides a fluent interface
     */
    public function setHostnameValidator(Hostname $hostnameValidator = null)
    {
        $this->options['hostnameValidator'] = $hostnameValidator;

        return $this;
    }

    /**
     * Returns the allow option of the attached hostname validator
     *
     * @return int
     */
    public function getAllow()
    {
        return $this->options['allow'];
    }

    /**
     * Sets the allow option of the hostname validator to use
     *
     * @param int $allow
     * @return $this Provides a fluent interface
     */
    public function setAllow($allow)
    {
        $this->options['allow'] = $allow;
        if (isset($this->options['hostnameValidator'])) {
            $this->options['hostnameValidator']->setAllow($allow);
        }

        return $this;
    }

    /**
     * Whether MX checking via getmxrr is supported or not
     *
     * @return bool
     */
    public function isMxSupported()
    {
        return function_exists('getmxrr');
    }

    /**
     * Returns the set validateMx option
     *
     * @return bool
     */
    public function getMxCheck()
    {
        return $this->options['useMxCheck'];
    }

    /**
     * Set whether we check for a valid MX record via DNS
     *
     * This only applies when DNS hostnames are validated
     *
     * @param  bool $mx Set allowed to true to validate for MX records, and false to not validate them
     * @return $this Fluid Interface
     */
    public function useMxCheck($mx)
    {
        $this->options['useMxCheck'] = (bool) $mx;
        return $this;
    }

    /**
     * Returns the set deepMxCheck option
     *
     * @return bool
     */
    public function getDeepMxCheck()
    {
        return $this->options['useDeepMxCheck'];
    }

    /**
     * Use deep validation for MX records
     *
     * @param  bool $deep Set deep to true to perform a deep validation process for MX records
     * @return $this Fluid Interface
     */
    public function useDeepMxCheck($deep)
    {
        $this->options['useDeepMxCheck'] = (bool) $deep;
        return $this;
    }

    /**
     * Returns the set domainCheck option
     *
     * @return bool
     */
    public function getDomainCheck()
    {
        return $this->options['useDomainCheck'];
    }

    /**
     * Sets if the domain should also be checked
     * or only the local part of the email address
     *
     * @param  bool $domain
     * @return $this Fluid Interface
     */
    public function useDomainCheck($domain = true)
    {
        $this->options['useDomainCheck'] = (bool) $domain;
        return $this;
    }

    /**
     * Returns if the given host is reserved
     *
     * The following addresses are seen as reserved
     * '0.0.0.0/8', '10.0.0.0/8', '127.0.0.0/8'
     * '100.64.0.0/10'
     * '172.16.0.0/12'
     * '198.18.0.0/15'
     * '169.254.0.0/16', '192.168.0.0/16'
     * '192.0.2.0/24', '192.88.99.0/24', '198.51.100.0/24', '203.0.113.0/24'
     * '224.0.0.0/4', '240.0.0.0/4'
     * @see http://en.wikipedia.org/wiki/Reserved_IP_addresses
     *
     * As of RFC5753 (JAN 2010), the following blocks are no longer reserved:
     *   - 128.0.0.0/16
     *   - 191.255.0.0/16
     *   - 223.255.255.0/24
     * @see http://tools.ietf.org/html/rfc5735#page-6
     *
     * As of RFC6598 (APR 2012), the following blocks are now reserved:
     *   - 100.64.0.0/10
     * @see http://tools.ietf.org/html/rfc6598#section-7
     *
     * @param string $host
     * @return bool Returns false when minimal one of the given addresses is not reserved
     */
    protected function isReserved($host)
    {
        if (! preg_match('/^([0-9]{1,3}\.){3}[0-9]{1,3}$/', $host)) {
            $host = gethostbynamel($host);
        } else {
            $host = [$host];
        }

        if (empty($host)) {
            return false;
        }

        foreach ($host as $server) {
            // @codingStandardsIgnoreStart
            // Search for 0.0.0.0/8, 10.0.0.0/8, 127.0.0.0/8
            if (!preg_match('/^(0|10|127)(\.([0-9]|[1-9][0-9]|1([0-9][0-9])|2([0-4][0-9]|5[0-5]))){3}$/', $server) &&
                // Search for 100.64.0.0/10
                !preg_match('/^100\.(6[0-4]|[7-9][0-9]|1[0-1][0-9]|12[0-7])(\.([0-9]|[1-9][0-9]|1([0-9][0-9])|2([0-4][0-9]|5[0-5]))){2}$/', $server) &&
                // Search for 172.16.0.0/12
                !preg_match('/^172\.(1[6-9]|2[0-9]|3[0-1])(\.([0-9]|[1-9][0-9]|1([0-9][0-9])|2([0-4][0-9]|5[0-5]))){2}$/', $server) &&
                // Search for 198.18.0.0/15
                !preg_match('/^198\.(1[8-9])(\.([0-9]|[1-9][0-9]|1([0-9][0-9])|2([0-4][0-9]|5[0-5]))){2}$/', $server) &&
                // Search for 169.254.0.0/16, 192.168.0.0/16
                !preg_match('/^(169\.254|192\.168)(\.([0-9]|[1-9][0-9]|1([0-9][0-9])|2([0-4][0-9]|5[0-5]))){2}$/', $server) &&
                // Search for 192.0.2.0/24, 192.88.99.0/24, 198.51.100.0/24, 203.0.113.0/24
                !preg_match('/^(192\.0\.2|192\.88\.99|198\.51\.100|203\.0\.113)\.([0-9]|[1-9][0-9]|1([0-9][0-9])|2([0-4][0-9]|5[0-5]))$/', $server) &&
                // Search for 224.0.0.0/4, 240.0.0.0/4
                !preg_match('/^(2(2[4-9]|[3-4][0-9]|5[0-5]))(\.([0-9]|[1-9][0-9]|1([0-9][0-9])|2([0-4][0-9]|5[0-5]))){3}$/', $server)
            ) {
                return false;
            }
            // @codingStandardsIgnoreEnd
        }

        return true;
    }

    /**
     * Internal method to validate the local part of the email address
     *
     * @return bool
     */
    protected function validateLocalPart()
    {
        // First try to match the local part on the common dot-atom format

        // Dot-atom characters are: 1*atext *("." 1*atext)
        // atext: ALPHA / DIGIT / and "!", "#", "$", "%", "&", "'", "*",
        //        "+", "-", "/", "=", "?", "^", "_", "`", "{", "|", "}", "~"
        $atext = 'a-zA-Z0-9\x21\x23\x24\x25\x26\x27\x2a\x2b\x2d\x2f\x3d\x3f\x5e\x5f\x60\x7b\x7c\x7d\x7e';
        if (preg_match('/^[' . $atext . ']+(\x2e+[' . $atext . ']+)*$/', $this->localPart)) {
            return true;
        }

        if ($this->validateInternationalizedLocalPart($this->localPart)) {
            return true;
        }

        // Try quoted string format (RFC 5321 Chapter 4.1.2)

        // Quoted-string characters are: DQUOTE *(qtext/quoted-pair) DQUOTE
        $qtext      = '\x20-\x21\x23-\x5b\x5d-\x7e'; // %d32-33 / %d35-91 / %d93-126
        $quotedPair = '\x20-\x7e'; // %d92 %d32-126
        if (preg_match('/^"(['. $qtext .']|\x5c[' . $quotedPair . '])*"$/', $this->localPart)) {
            return true;
        }

        $this->error(self::DOT_ATOM);
        $this->error(self::QUOTED_STRING);
        $this->error(self::INVALID_LOCAL_PART);

        return false;
    }

    /**
     * @param string $localPart Address local part to validate.
     * @return bool
     */
    protected function validateInternationalizedLocalPart($localPart)
    {
        if (extension_loaded('intl')
            && false === UConverter::transcode($localPart, 'UTF-8', 'UTF-8')
        ) {
            // invalid utf?
            return false;
        }

        $atext = 'a-zA-Z0-9\x21\x23\x24\x25\x26\x27\x2a\x2b\x2d\x2f\x3d\x3f\x5e\x5f\x60\x7b\x7c\x7d\x7e';
        // RFC 6532 extends atext to include non-ascii utf
        // @see https://tools.ietf.org/html/rfc6532#section-3.1
        $uatext = $atext . '\x{80}-\x{FFFF}';
        return (bool) preg_match('/^[' . $uatext . ']+(\x2e+[' . $uatext . ']+)*$/u', $localPart);
    }

    /**
     * Returns the found MX Record information after validation including weight for further processing
     *
     * @return array
     */
    public function getMXRecord()
    {
        return $this->mxRecord;
    }

    /**
     * Internal method to validate the servers MX records
     *
     * @return bool
     */
    protected function validateMXRecords()
    {
        $mxHosts = [];
        $weight  = [];
        $result = getmxrr($this->hostname, $mxHosts, $weight);
        if (! empty($mxHosts) && ! empty($weight)) {
            $this->mxRecord = array_combine($mxHosts, $weight) ?: [];
        } else {
            $this->mxRecord = [];
        }

        arsort($this->mxRecord);

        // Fallback to IPv4 hosts if no MX record found (RFC 2821 SS 5).
        if (! $result) {
            $result = gethostbynamel($this->hostname);
            if (is_array($result)) {
                $this->mxRecord = array_flip($result);
            }
        }

        if (! $result) {
            $this->error(self::INVALID_MX_RECORD);
            return $result;
        }

        if (! $this->options['useDeepMxCheck']) {
            return $result;
        }

        $validAddress = false;
        $reserved     = true;
        foreach ($this->mxRecord as $hostname => $weight) {
            $res = $this->isReserved($hostname);
            if (! $res) {
                $reserved = false;
            }

            if (! $res
                && (checkdnsrr($hostname, 'A')
                || checkdnsrr($hostname, 'AAAA')
                || checkdnsrr($hostname, 'A6'))
            ) {
                $validAddress = true;
                break;
            }
        }

        if (! $validAddress) {
            $result = false;
            $error  = $reserved ? self::INVALID_SEGMENT : self::INVALID_MX_RECORD;
            $this->error($error);
        }

        return $result;
    }

    /**
     * Internal method to validate the hostname part of the email address
     *
     * @return bool
     */
    protected function validateHostnamePart()
    {
        $hostname = $this->getHostnameValidator()->setTranslator($this->getTranslator())
                         ->isValid($this->hostname);
        if (! $hostname) {
            $this->error(self::INVALID_HOSTNAME);
            // Get messages and errors from hostnameValidator
            foreach ($this->getHostnameValidator()->getMessages() as $code => $message) {
                $this->abstractOptions['messages'][$code] = $message;
            }
        } elseif ($this->options['useMxCheck']) {
            // MX check on hostname
            $hostname = $this->validateMXRecords();
        }

        return $hostname;
    }

    /**
     * Splits the given value in hostname and local part of the email address
     *
     * @param string $value Email address to be split
     * @return bool Returns false when the email can not be split
     */
    protected function splitEmailParts($value)
    {
        $value = is_string($value) ? $value : '';

        // Split email address up and disallow '..'
        if (strpos($value, '..') !== false
            || ! preg_match('/^(.+)@([^@]+)$/', $value, $matches)
        ) {
            return false;
        }

        $this->localPart = $matches[1];
        $this->hostname  = $this->idnToAscii($matches[2]);

        return true;
    }

    /**
     * Defined by Laminas\Validator\ValidatorInterface
     *
     * Returns true if and only if $value is a valid email address
     * according to RFC2822
     *
     * @link   http://www.ietf.org/rfc/rfc2822.txt RFC2822
     * @link   http://www.columbia.edu/kermit/ascii.html US-ASCII characters
     * @param  string $value
     * @return bool
     */
    public function isValid($value)
    {
        if (! is_string($value)) {
            $this->error(self::INVALID);
            return false;
        }

        $length  = true;
        $this->setValue($value);

        // Split email address up and disallow '..'
        if (! $this->splitEmailParts($this->getValue())) {
            $this->error(self::INVALID_FORMAT);
            return false;
        }

        if ($this->getOption('strict') && (strlen($this->localPart) > 64) || (strlen($this->hostname) > 255)) {
            $length = false;
            $this->error(self::LENGTH_EXCEEDED);
        }

        // Match hostname part
        $hostname = false;
        if ($this->options['useDomainCheck']) {
            $hostname = $this->validateHostnamePart();
        }

        $local = $this->validateLocalPart();

        // If both parts valid, return true
        return ($local && $length) && (! $this->options['useDomainCheck'] || $hostname);
    }

    /**
     * Safely convert UTF-8 encoded domain name to ASCII
     * @param string $email  the UTF-8 encoded email
     * @return string
     */
    protected function idnToAscii($email)
    {
        if (extension_loaded('intl')) {
            if (defined('INTL_IDNA_VARIANT_UTS46')) {
                return idn_to_ascii($email, 0, INTL_IDNA_VARIANT_UTS46) ?: $email;
            }
            return idn_to_ascii($email) ?: $email;
        }
        return $email;
    }

    /**
     * Safely convert ASCII encoded domain name to UTF-8
     * @param string $email the ASCII encoded email
     * @return string
     */
    protected function idnToUtf8($email)
    {
        if (strlen($email) == 0) {
            return $email;
        }

        if (extension_loaded('intl')) {
            // The documentation does not clarify what kind of failure
            // can happen in idn_to_utf8. One can assume if the source
            // is not IDN encoded, it would fail, but it usually returns
            // the source string in those cases.
            // But not when the source string is long enough.
            // Thus we default to source string ourselves.
            if (defined('INTL_IDNA_VARIANT_UTS46')) {
                return idn_to_utf8($email, 0, INTL_IDNA_VARIANT_UTS46) ?: $email;
            }
            return idn_to_utf8($email) ?: $email;
        }
        return $email;
    }
}
laminas-validator/src/ValidatorChain.php000064400000021352147361032560014355 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-validator for the canonical source repository
 * @copyright https://github.com/laminas/laminas-validator/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-validator/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Validator;

use Countable;
use Laminas\ServiceManager\ServiceManager;
use Laminas\Stdlib\PriorityQueue;

class ValidatorChain implements
    Countable,
    ValidatorInterface
{
    /**
     * Default priority at which validators are added
     */
    const DEFAULT_PRIORITY = 1;

    /**
     * @var ValidatorPluginManager
     */
    protected $plugins;

    /**
     * Validator chain
     *
     * @var PriorityQueue
     */
    protected $validators;

    /**
     * Array of validation failure messages
     *
     * @var array
     */
    protected $messages = [];

    /**
     * Initialize validator chain
     */
    public function __construct()
    {
        $this->validators = new PriorityQueue();
    }

    /**
     * Return the count of attached validators
     *
     * @return int
     */
    public function count()
    {
        return count($this->validators);
    }

    /**
     * Get plugin manager instance
     *
     * @return ValidatorPluginManager
     */
    public function getPluginManager()
    {
        if (! $this->plugins) {
            $this->setPluginManager(new ValidatorPluginManager(new ServiceManager));
        }
        return $this->plugins;
    }

    /**
     * Set plugin manager instance
     *
     * @param  ValidatorPluginManager $plugins Plugin manager
     * @return $this
     */
    public function setPluginManager(ValidatorPluginManager $plugins)
    {
        $this->plugins = $plugins;
        return $this;
    }

    /**
     * Retrieve a validator by name
     *
     * @param  string     $name    Name of validator to return
     * @param  null|array $options Options to pass to validator constructor (if not already instantiated)
     * @return ValidatorInterface
     */
    public function plugin($name, array $options = null)
    {
        $plugins = $this->getPluginManager();
        return $plugins->get($name, $options);
    }

    /**
     * Attach a validator to the end of the chain
     *
     * If $breakChainOnFailure is true, then if the validator fails, the next validator in the chain,
     * if one exists, will not be executed.
     *
     * @param  ValidatorInterface $validator
     * @param  bool               $breakChainOnFailure
     * @param  int                $priority            Priority at which to enqueue validator; defaults to
     *                                                          1 (higher executes earlier)
     *
     * @throws Exception\InvalidArgumentException
     *
     * @return $this
     */
    public function attach(
        ValidatorInterface $validator,
        $breakChainOnFailure = false,
        $priority = self::DEFAULT_PRIORITY
    ) {
        $this->validators->insert(
            [
                'instance'            => $validator,
                'breakChainOnFailure' => (bool) $breakChainOnFailure,
            ],
            $priority
        );

        return $this;
    }

    /**
     * Proxy to attach() to keep BC
     *
     * @deprecated Please use attach()
     * @param  ValidatorInterface      $validator
     * @param  bool                 $breakChainOnFailure
     * @param  int                  $priority
     * @return ValidatorChain Provides a fluent interface
     */
    public function addValidator(
        ValidatorInterface $validator,
        $breakChainOnFailure = false,
        $priority = self::DEFAULT_PRIORITY
    ) {
        return $this->attach($validator, $breakChainOnFailure, $priority);
    }

    /**
     * Adds a validator to the beginning of the chain
     *
     * If $breakChainOnFailure is true, then if the validator fails, the next validator in the chain,
     * if one exists, will not be executed.
     *
     * @param  ValidatorInterface      $validator
     * @param  bool                 $breakChainOnFailure
     * @return $this Provides a fluent interface
     */
    public function prependValidator(ValidatorInterface $validator, $breakChainOnFailure = false)
    {
        $priority = self::DEFAULT_PRIORITY;

        if (! $this->validators->isEmpty()) {
            $extractedNodes = $this->validators->toArray(PriorityQueue::EXTR_PRIORITY);
            rsort($extractedNodes, SORT_NUMERIC);
            $priority = $extractedNodes[0] + 1;
        }

        $this->validators->insert(
            [
                'instance'            => $validator,
                'breakChainOnFailure' => (bool) $breakChainOnFailure,
            ],
            $priority
        );
        return $this;
    }

    /**
     * Use the plugin manager to add a validator by name
     *
     * @param  string $name
     * @param  array $options
     * @param  bool $breakChainOnFailure
     * @param  int $priority
     * @return $this
     */
    public function attachByName($name, $options = [], $breakChainOnFailure = false, $priority = self::DEFAULT_PRIORITY)
    {
        if (isset($options['break_chain_on_failure'])) {
            $breakChainOnFailure = (bool) $options['break_chain_on_failure'];
        }

        if (isset($options['breakchainonfailure'])) {
            $breakChainOnFailure = (bool) $options['breakchainonfailure'];
        }

        $this->attach($this->plugin($name, $options), $breakChainOnFailure, $priority);

        return $this;
    }

    /**
     * Proxy to attachByName() to keep BC
     *
     * @deprecated Please use attachByName()
     * @param  string $name
     * @param  array  $options
     * @param  bool   $breakChainOnFailure
     * @return ValidatorChain
     */
    public function addByName($name, $options = [], $breakChainOnFailure = false)
    {
        return $this->attachByName($name, $options, $breakChainOnFailure);
    }

    /**
     * Use the plugin manager to prepend a validator by name
     *
     * @param  string $name
     * @param  array  $options
     * @param  bool   $breakChainOnFailure
     * @return $this
     */
    public function prependByName($name, $options = [], $breakChainOnFailure = false)
    {
        $validator = $this->plugin($name, $options);
        $this->prependValidator($validator, $breakChainOnFailure);
        return $this;
    }

    /**
     * Returns true if and only if $value passes all validations in the chain
     *
     * Validators are run in the order in which they were added to the chain (FIFO).
     *
     * @param  mixed $value
     * @param  mixed $context Extra "context" to provide the validator
     * @return bool
     */
    public function isValid($value, $context = null)
    {
        $this->messages = [];
        $result         = true;
        foreach ($this->validators as $element) {
            $validator = $element['instance'];
            if ($validator->isValid($value, $context)) {
                continue;
            }
            $result         = false;
            $messages       = $validator->getMessages();
            $this->messages = array_replace_recursive($this->messages, $messages);
            if ($element['breakChainOnFailure']) {
                break;
            }
        }
        return $result;
    }

    /**
     * Merge the validator chain with the one given in parameter
     *
     * @param ValidatorChain $validatorChain
     * @return $this
     */
    public function merge(ValidatorChain $validatorChain)
    {
        foreach ($validatorChain->validators->toArray(PriorityQueue::EXTR_BOTH) as $item) {
            $this->attach($item['data']['instance'], $item['data']['breakChainOnFailure'], $item['priority']);
        }

        return $this;
    }

    /**
     * Returns array of validation failure messages
     *
     * @return array
     */
    public function getMessages()
    {
        return $this->messages;
    }

    /**
     * Get all the validators
     *
     * @return array
     */
    public function getValidators()
    {
        return $this->validators->toArray(PriorityQueue::EXTR_DATA);
    }

    /**
     * Invoke chain as command
     *
     * @param  mixed $value
     * @return bool
     */
    public function __invoke($value)
    {
        return $this->isValid($value);
    }

    /**
     * Deep clone handling
     */
    public function __clone()
    {
        $this->validators = clone $this->validators;
    }

    /**
     * Prepare validator chain for serialization
     *
     * Plugin manager (property 'plugins') cannot
     * be serialized. On wakeup the property remains unset
     * and next invocation to getPluginManager() sets
     * the default plugin manager instance (ValidatorPluginManager).
     *
     * @return array
     */
    public function __sleep()
    {
        return ['validators', 'messages'];
    }
}
laminas-validator/src/Uri.php000064400000011543147361032560012225 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-validator for the canonical source repository
 * @copyright https://github.com/laminas/laminas-validator/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-validator/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Validator;

use Laminas\Uri\Exception\ExceptionInterface as UriException;
use Laminas\Uri\Uri as UriHandler;
use Laminas\Validator\Exception\InvalidArgumentException;
use Traversable;

class Uri extends AbstractValidator
{
    const INVALID = 'uriInvalid';
    const NOT_URI = 'notUri';

    /**
     * @var array
     */
    protected $messageTemplates = [
        self::INVALID => 'Invalid type given. String expected',
        self::NOT_URI => 'The input does not appear to be a valid Uri',
    ];

    /**
     * @var UriHandler
     */
    protected $uriHandler;

    /**
     * @var bool
     */
    protected $allowRelative = true;

    /**
     * @var bool
     */
    protected $allowAbsolute = true;

    /**
     * Sets default option values for this instance
     *
     * @param array|Traversable $options
     */
    public function __construct($options = [])
    {
        if ($options instanceof Traversable) {
            $options = iterator_to_array($options);
        } elseif (! is_array($options)) {
            $options = func_get_args();
            $temp['uriHandler'] = array_shift($options);
            if (! empty($options)) {
                $temp['allowRelative'] = array_shift($options);
            }
            if (! empty($options)) {
                $temp['allowAbsolute'] = array_shift($options);
            }

            $options = $temp;
        }

        if (isset($options['uriHandler'])) {
            $this->setUriHandler($options['uriHandler']);
        }
        if (isset($options['allowRelative'])) {
            $this->setAllowRelative($options['allowRelative']);
        }
        if (isset($options['allowAbsolute'])) {
            $this->setAllowAbsolute($options['allowAbsolute']);
        }

        parent::__construct($options);
    }

    /**
     * @throws InvalidArgumentException
     * @return UriHandler
     */
    public function getUriHandler()
    {
        if (null === $this->uriHandler) {
            // Lazy load the base Uri handler
            $this->uriHandler = new UriHandler();
        } elseif (is_string($this->uriHandler) && class_exists($this->uriHandler)) {
            // Instantiate string Uri handler that references a class
            $this->uriHandler = new $this->uriHandler;
        }
        return $this->uriHandler;
    }

    /**
     * @param  UriHandler|string $uriHandler
     * @throws InvalidArgumentException
     * @return $this
     */
    public function setUriHandler($uriHandler)
    {
        if (! is_a($uriHandler, UriHandler::class, true)) {
            throw new InvalidArgumentException(sprintf(
                'Expecting a subclass name or instance of %s as $uriHandler',
                UriHandler::class
            ));
        }

        $this->uriHandler = $uriHandler;
        return $this;
    }

    /**
     * Returns the allowAbsolute option
     *
     * @return bool
     */
    public function getAllowAbsolute()
    {
        return $this->allowAbsolute;
    }

    /**
     * Sets the allowAbsolute option
     *
     * @param  bool $allowAbsolute
     * @return $this
     */
    public function setAllowAbsolute($allowAbsolute)
    {
        $this->allowAbsolute = (bool) $allowAbsolute;
        return $this;
    }

    /**
     * Returns the allowRelative option
     *
     * @return bool
     */
    public function getAllowRelative()
    {
        return $this->allowRelative;
    }

    /**
     * Sets the allowRelative option
     *
     * @param  bool $allowRelative
     * @return $this
     */
    public function setAllowRelative($allowRelative)
    {
        $this->allowRelative = (bool) $allowRelative;
        return $this;
    }

    /**
     * Returns true if and only if $value validates as a Uri
     *
     * @param  string $value
     * @return bool
     */
    public function isValid($value)
    {
        if (! is_string($value)) {
            $this->error(self::INVALID);
            return false;
        }

        $uriHandler = $this->getUriHandler();
        try {
            $uriHandler->parse($value);
            if ($uriHandler->isValid()) {
                // It will either be a valid absolute or relative URI
                if (($this->allowRelative && $this->allowAbsolute)
                    || ($this->allowAbsolute && $uriHandler->isAbsolute())
                    || ($this->allowRelative && $uriHandler->isValidRelative())
                ) {
                    return true;
                }
            }
        } catch (UriException $ex) {
            // Error parsing URI, it must be invalid
        }

        $this->error(self::NOT_URI);
        return false;
    }
}
laminas-validator/src/Callback.php000064400000007303147361032560013161 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-validator for the canonical source repository
 * @copyright https://github.com/laminas/laminas-validator/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-validator/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Validator;

class Callback extends AbstractValidator
{
    /**
     * Invalid callback
     */
    const INVALID_CALLBACK = 'callbackInvalid';

    /**
     * Invalid value
     */
    const INVALID_VALUE = 'callbackValue';

    /**
     * Validation failure message template definitions
     *
     * @var array
     */
    protected $messageTemplates = [
        self::INVALID_VALUE    => 'The input is not valid',
        self::INVALID_CALLBACK => 'An exception has been raised within the callback',
    ];

    /**
     * Default options to set for the validator
     *
     * @var mixed
     */
    protected $options = [
        'callback'         => null,     // Callback in a call_user_func format, string || array
        'callbackOptions'  => [],  // Options for the callback
    ];

    /**
     * Constructor
     *
     * @param array|callable $options
     */
    public function __construct($options = null)
    {
        if (is_callable($options)) {
            $options = ['callback' => $options];
        }

        parent::__construct($options);
    }

    /**
     * Returns the set callback
     *
     * @return mixed
     */
    public function getCallback()
    {
        return $this->options['callback'];
    }

    /**
     * Sets the callback
     *
     * @param  string|array|callable $callback
     * @return $this Provides a fluent interface
     * @throws Exception\InvalidArgumentException
     */
    public function setCallback($callback)
    {
        if (! is_callable($callback)) {
            throw new Exception\InvalidArgumentException('Invalid callback given');
        }

        $this->options['callback'] = $callback;
        return $this;
    }

    /**
     * Returns the set options for the callback
     *
     * @return mixed
     */
    public function getCallbackOptions()
    {
        return $this->options['callbackOptions'];
    }

    /**
     * Sets options for the callback
     *
     * @param  mixed $options
     * @return $this Provides a fluent interface
     */
    public function setCallbackOptions($options)
    {
        $this->options['callbackOptions'] = (array) $options;
        return $this;
    }

    /**
     * Returns true if and only if the set callback returns
     * for the provided $value
     *
     * @param  mixed $value
     * @param  mixed $context Additional context to provide to the callback
     * @return bool
     * @throws Exception\InvalidArgumentException
     */
    public function isValid($value, $context = null)
    {
        $this->setValue($value);

        $options  = $this->getCallbackOptions();
        $callback = $this->getCallback();
        if (empty($callback)) {
            throw new Exception\InvalidArgumentException('No callback given');
        }

        $args = [$value];
        if (empty($options) && ! empty($context)) {
            $args[] = $context;
        }
        if (! empty($options) && empty($context)) {
            $args = array_merge($args, $options);
        }
        if (! empty($options) && ! empty($context)) {
            $args[] = $context;
            $args   = array_merge($args, $options);
        }

        try {
            if (! call_user_func_array($callback, $args)) {
                $this->error(self::INVALID_VALUE);
                return false;
            }
        } catch (\Exception $e) {
            $this->error(self::INVALID_CALLBACK);
            return false;
        }

        return true;
    }
}
laminas-validator/src/Timezone.php000064400000011242147361032560013254 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-validator for the canonical source repository
 * @copyright https://github.com/laminas/laminas-validator/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-validator/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Validator;

use DateTimeZone;

class Timezone extends AbstractValidator
{
    const INVALID                       = 'invalidTimezone';
    const INVALID_TIMEZONE_LOCATION     = 'invalidTimezoneLocation';
    const INVALID_TIMEZONE_ABBREVIATION = 'invalidTimezoneAbbreviation';

    const LOCATION      = 0b01;
    const ABBREVIATION  = 0b10;
    const ALL           = 0b11;

    /**
     * @var array
     */
    protected $constants = [
        self::LOCATION       => 'location',
        self::ABBREVIATION   => 'abbreviation',
    ];

    /**
     * Default value for types; value = 3
     *
     * @var array
     */
    protected $defaultType = [
        self::LOCATION,
        self::ABBREVIATION,
    ];

    /**
     * @var array
     */
    protected $messageTemplates = [
        self::INVALID                       => 'Invalid timezone given.',
        self::INVALID_TIMEZONE_LOCATION     => 'Invalid timezone location given.',
        self::INVALID_TIMEZONE_ABBREVIATION => 'Invalid timezone abbreviation given.',
    ];

    /**
     * Options for this validator
     *
     * @var array
     */
    protected $options = [];

    /**
     * Constructor
     *
     * @param array|int $options OPTIONAL
     */
    public function __construct($options = [])
    {
        $opts['type'] = $this->defaultType;

        if (is_array($options)) {
            if (array_key_exists('type', $options)) {
                $opts['type'] = $options['type'];
            }
        } elseif (! empty($options)) {
            $opts['type'] = $options;
        }

        // setType called by parent constructor then setOptions method
        parent::__construct($opts);
    }

    /**
     * Set the types
     *
     * @param  int|array $type
     *
     * @throws Exception\InvalidArgumentException
     */
    public function setType($type = null)
    {
        $type = $this->calculateTypeValue($type);

        if (! is_int($type) || ($type < 1) || ($type > self::ALL)) {
            throw new Exception\InvalidArgumentException(sprintf(
                'Unknown type "%s" provided',
                is_string($type) || is_int($type)
                    ? $type
                    : (is_object($type) ? get_class($type) : gettype($type))
            ));
        }

        $this->options['type'] = $type;
    }

    /**
     * Returns true if timezone location or timezone abbreviations is correct.
     *
     * @param mixed $value
     * @return bool
     */
    public function isValid($value)
    {
        if ($value !== null && ! is_string($value)) {
            $this->error(self::INVALID);
            return false;
        }

        $type = $this->options['type'];
        $this->setValue($value);

        switch (true) {
            // Check in locations and abbreviations
            case (($type & self::LOCATION) && ($type & self::ABBREVIATION)):
                $abbrs = DateTimeZone::listAbbreviations();
                $locations = DateTimeZone::listIdentifiers();

                if (! array_key_exists($value, $abbrs) && ! in_array($value, $locations)) {
                    $this->error(self::INVALID);
                    return false;
                }
                break;

            // Check only in locations
            case ($type & self::LOCATION):
                $locations = DateTimeZone::listIdentifiers();

                if (! in_array($value, $locations)) {
                    $this->error(self::INVALID_TIMEZONE_LOCATION);
                    return false;
                }
                break;

            // Check only in abbreviations
            case ($type & self::ABBREVIATION):
                $abbrs = DateTimeZone::listAbbreviations();

                if (! array_key_exists($value, $abbrs)) {
                    $this->error(self::INVALID_TIMEZONE_ABBREVIATION);
                    return false;
                }
                break;
        }

        return true;
    }

    /**
     * @param array|int|string $type
     *
     * @return int
     */
    protected function calculateTypeValue($type)
    {
        $types    = (array) $type;
        $detected = 0;

        foreach ($types as $value) {
            if (is_int($value)) {
                $detected |= $value;
            } elseif (false !== ($position = array_search($value, $this->constants))) {
                $detected |= array_search($value, $this->constants);
            }
        }

        return $detected;
    }
}
laminas-validator/README.md000064400000001616147361032560011445 0ustar00# laminas-validator

[![Build Status](https://travis-ci.com/laminas/laminas-validator.svg?branch=master)](https://travis-ci.com/laminas/laminas-validator)
[![Coverage Status](https://coveralls.io/repos/github/laminas/laminas-validator/badge.svg?branch=master)](https://coveralls.io/github/laminas/laminas-validator?branch=master)

laminas-validator provides a set of commonly needed validators. It also provides a
simple validator chaining mechanism by which multiple validators may be applied
to a single datum in a user-defined order.

## Installation

Run the following to install this library:

```bash
$ composer require laminas/laminas-validator
```

## Documentation

Browse the documentation online at https://docs.laminas.dev/laminas-validator/

## Support

* [Issues](https://github.com/laminas/laminas-validator/issues/)
* [Chat](https://laminas.dev/chat/)
* [Forum](https://discourse.laminas.dev/)
laminas-validator/CHANGELOG.md000064400000055527147361032560012011 0ustar00# Changelog

All notable changes to this project will be documented in this file, in reverse chronological order by release.

## 2.13.4 - 2020-03-31

### Added

- Nothing.

### Changed

- Nothing.

### Deprecated

- Nothing.

### Removed

- Nothing.

### Fixed

- [#59](https://github.com/laminas/laminas-validator/pull/59) fixes `Uri` validator to accept any `Laminas\Uri\Uri` instance for the uri handler.

## 2.13.3 - 2020-03-29

### Added

- Nothing.

### Changed

- Nothing.

### Deprecated

- Nothing.

### Removed

- Nothing.

### Fixed

- Fixed `replace` version constraint in composer.json so repository can be used as replacement of `zendframework/zend-validator:^2.13.0`.

## 2.13.2 - 2020-03-16

### Added

- Nothing.

### Changed

- Nothing.

### Deprecated

- Nothing.

### Removed

- Nothing.

### Fixed

- [#57](https://github.com/laminas/laminas-validator/pull/57) removes redundant third argument in `UndisclosedPassword` validator constructor.

- [#53](https://github.com/laminas/laminas-validator/pull/53) fixes `UndisclosedPassword` validator to call parent constructor on instantiation. 

## 2.13.1 - 2020-01-15

### Added

- Nothing.

### Changed

- Nothing.

### Deprecated

- Nothing.

### Removed

- Nothing.

### Fixed

- [#32](https://github.com/laminas/laminas-validator/pull/32) fixes PHP 7.4 compatibility.

- [#34](https://github.com/laminas/laminas-validator/pull/34) fixes hostname validation for domain parts with 2+ dashes and with dash at the end.

- Updates the TLD list to the latest version from the IANA.

## 2.13.0 - 2019-12-27

### Added

- [zendframework/zend-validator#275](https://github.com/zendframework/zend-validator/pull/275) adds a new `strict` option to `Laminas\Validator\Date`; when `true`, the value being validated must both be a date AND in the same format as provided via the `format` option.

- [zendframework/zend-validator#264](https://github.com/zendframework/zend-validator/pull/264) adds `Laminas\Validator\UndisclosedPassword`, which can be used to determine if a password has been exposed in a known data breach as reported on the [Have I Been Pwned?](https://www.haveibeenpwned.com) website. [Documentation](https://docs.laminas.dev/laminas-validator/validators/undisclosed-password/)

- [zendframework/zend-validator#266](https://github.com/zendframework/zend-validator/pull/266) adds a new option to the `File\Extension` and `File\ExcludeExtension` validators, `allowNonExistentFile`. When set to `true`, the validators will continue validating the extension of the filename given even if the file does not exist. The default is `false`, to preserve backwards compatibility with previous versions.

### Changed

- [zendframework/zend-validator#264](https://github.com/zendframework/zend-validator/pull/264) bumps the minimum supported PHP version to 7.1.0.

- [zendframework/zend-validator#279](https://github.com/zendframework/zend-validator/pull/279) updates the `magic.mime` file used for file validations.

### Deprecated

- Nothing.

### Removed

- [zendframework/zend-validator#264](https://github.com/zendframework/zend-validator/pull/264) removes support for PHP versions prior to 7.1.0.

### Fixed

- Nothing.

## 2.12.2 - 2019-10-29

### Added

- Nothing.

### Changed

- Nothing.

### Deprecated

- Nothing.

### Removed

- Nothing.

### Fixed

- [zendframework/zend-validator#277](https://github.com/zendframework/zend-validator/pull/277) fixes `File\Hash` validator in case
  when the file hash contains only digits.

- [zendframework/zend-validator#277](https://github.com/zendframework/zend-validator/pull/277) fixes `File\Hash` validator to match 
  hash with the given hashing algorithm.

## 2.12.1 - 2019-10-12

### Added

- Nothing.

### Changed

- Nothing.

### Deprecated

- Nothing.

### Removed

- Nothing.

### Fixed

- [zendframework/zend-validator#272](https://github.com/zendframework/zend-validator/pull/272) changes
  curly braces in array and string offset access to square brackets
  in order to prevent issues under the upcoming PHP 7.4 release.

- [zendframework/zend-validator#231](https://github.com/zendframework/zend-validator/pull/231) fixes validation of input hashes in `Laminas\Validator\File\Hash` validator when provided as array.
  Only string hashes are allowed. If different type is provided `Laminas\Validator\Exception\InvalidArgumentException` is thrown.

## 2.12.0 - 2019-01-30

### Added

- [zendframework/zend-validator#250](https://github.com/zendframework/zend-validator/pull/250) adds support for PHP 7.3.

### Changed

- [zendframework/zend-validator#251](https://github.com/zendframework/zend-validator/pull/251) updates the logic of each of the various `Laminas\Validator\File` validators
  to allow validating against PSR-7 `UploadedFileInterface` instances, expanding
  the support originally provided in version 2.11.0.

### Deprecated

- Nothing.

### Removed

- [zendframework/zend-validator#250](https://github.com/zendframework/zend-validator/pull/250) removes support for laminas-stdlib v2 releases.

### Fixed

- Nothing.

## 2.11.1 - 2019-01-29

### Added

- [zendframework/zend-validator#249](https://github.com/zendframework/zend-validator/pull/249) adds support in the hostname validator for the `.rs` TLD.

### Changed

- [zendframework/zend-validator#253](https://github.com/zendframework/zend-validator/pull/253) updates the list of allowed characters for a `DE` domain name to match those published by IDN.

### Deprecated

- Nothing.

### Removed

- Nothing.

### Fixed

- [zendframework/zend-validator#256](https://github.com/zendframework/zend-validator/pull/256) fixes hostname validation when omitting the TLD from verification,
  ensuring validation of the domain segment considers all URI criteria.

## 2.11.0 - 2018-12-13

### Added

- [zendframework/zend-validator#237](https://github.com/zendframework/zend-validator/pull/237) adds support for the [PSR-7 UploadedFileInterface](https://www.php-fig.org/psr/psr-7/#uploadedfileinterface)
  to each of the `Upload` and `UploadFile` validators.

- [zendframework/zend-validator#220](https://github.com/zendframework/zend-validator/pull/220) adds image/webp to the list of known image types for the `IsImage` validator.

### Changed

- Nothing.

### Deprecated

- Nothing.

### Removed

- Nothing.

### Fixed

- Nothing.

## 2.10.3 - 2018-12-13

### Added

- Nothing.

### Changed

- Nothing.

### Deprecated

- Nothing.

### Removed

- Nothing.

### Fixed

- [zendframework/zend-validator#241](https://github.com/zendframework/zend-validator/pull/241) has the `Hostname` validator return an invalid result early when an empty
  domain segment is detected.

- [zendframework/zend-validator#232](https://github.com/zendframework/zend-validator/pull/232) updates the `Hostname` validator to allow underscores in subdomains.

- [zendframework/zend-validator#218](https://github.com/zendframework/zend-validator/pull/218) fixes a precision issue with the `Step` validator.

## 2.10.2 - 2018-02-01

### Added

- [zendframework/zend-validator#202](https://github.com/zendframework/zend-validator/pull/202) adds the
  ability to use custom constant types in extensions of
  `Laminas\Validator\CreditCard`, fixing an issue where users were unable to add
  new brands as they are created.

- [zendframework/zend-validator#203](https://github.com/zendframework/zend-validator/pull/203) adds support
  for the new Russian bank card "Mir".

- [zendframework/zend-validator#204](https://github.com/zendframework/zend-validator/pull/204) adds support
  to the IBAN validator for performing SEPA validation against Croatia and San
  Marino.

- [zendframework/zend-validator#209](https://github.com/zendframework/zend-validator/pull/209) adds
  documentation for the `Explode` validator.

### Changed

- Nothing.

### Deprecated

- Nothing.

### Removed

- Nothing.

### Fixed

- [zendframework/zend-validator#195](https://github.com/zendframework/zend-validator/pull/195) adds
  missing `GpsPoint` validator entries to the `ValidatorPluginManager`, ensuring
  they may be retrieved from it correctly.

- [zendframework/zend-validator#212](https://github.com/zendframework/zend-validator/pull/212) updates the
  `CSRF` validator to automatically mark any non-string values as invalid,
  preventing errors such as array to string conversion.

## 2.10.1 - 2017-08-22

### Added

- Nothing.

### Changed

- Nothing.

### Deprecated

- Nothing.

### Removed

- Nothing.

### Fixed

- [zendframework/zend-validator#194](https://github.com/zendframework/zend-validator/pull/194) modifies the
  `EmailAddress` validator to omit the `INTL_IDNA_VARIANT_UTS46` flag to
  `idn_to_utf8()` if the constant is not defined, fixing an issue on systems
  using pre-2012 releases of libicu.

## 2.10.0 - 2017-08-14

### Added

- [zendframework/zend-validator#175](https://github.com/zendframework/zend-validator/pull/175) adds support
  for PHP 7.2 (conditionally, as PHP 7.2 is currently in beta1).

- [zendframework/zend-validator#157](https://github.com/zendframework/zend-validator/pull/157) adds a new
  validator, `IsCountable`, which allows validating:
  - if a value is countable
  - if a countable value exactly matches a configured count
  - if a countable value is greater than a configured minimum count
  - if a countable value is less than a configured maximum count
  - if a countable value is between configured minimum and maximum counts

### Changed

- [zendframework/zend-validator#169](https://github.com/zendframework/zend-validator/pull/169) modifies how
  the various `File` validators check for readable files. Previously, they used
  `stream_resolve_include_path`, which led to false negative checks when the
  files did not exist within an `include_path` (which is often the case within a
  web application). These now use `is_readable()` instead.

- [zendframework/zend-validator#185](https://github.com/zendframework/zend-validator/pull/185) updates the
  laminas-session requirement (during development, and in the suggestions) to 2.8+,
  to ensure compatibility with the upcoming PHP 7.2 release.

- [zendframework/zend-validator#187](https://github.com/zendframework/zend-validator/pull/187) updates the
  `Between` validator to **require** that both a `min` and a `max` value are
  provided to the constructor, and that both are of the same type (both
  integer/float values and/or both string values). This fixes issues that could
  previously occur when one or the other was not set, but means an exception
  will now be raised during instantiation (versus runtime during `isValid()`).

- [zendframework/zend-validator#188](https://github.com/zendframework/zend-validator/pull/188) updates the
  `ConfigProvider` to alias the service name `ValidatorManager` to the class
  `Laminas\Validator\ValidatorPluginManager`, and now maps the the latter class to
  the `ValidatorPluginManagerFactory`. Previously, we mapped the service name
  directly to the factory. Usage should not change for anybody at this point.

### Deprecated

- Nothing.

### Removed

- [zendframework/zend-validator#175](https://github.com/zendframework/zend-validator/pull/175) removes
  support for HHVM.

### Fixed

- [zendframework/zend-validator#160](https://github.com/zendframework/zend-validator/pull/160) fixes how the
  `EmailAddress` validator handles the local part of an address, allowing it to
  support unicode.

## 2.9.2 - 2017-07-20

### Added

- Nothing.

### Deprecated

- Nothing.

### Removed

- Nothing.

### Fixed

- [zendframework/zend-validator#180](https://github.com/zendframework/zend-validator/pull/180) fixes how
  `Laminas\Validator\File\MimeType` "closes" the open FileInfo handle for the file
  being validated, using `unset()` instead of `finfo_close()`; this resolves a
  segfault that occurs on older PHP versions.
- [zendframework/zend-validator#174](https://github.com/zendframework/zend-validator/pull/174) fixes how
  `Laminas\Validator\Between` handles two situations: (1) when a non-numeric value
  is validated against numeric min/max values, and (2) when a numeric value is
  validated against non-numeric min/max values. Previously, these incorrectly
  validated as true; now they are marked invalid.

## 2.9.1 - 2017-05-17

### Added

- Nothing.

### Changes

- [zendframework/zend-validator#154](https://github.com/zendframework/zend-validator/pull/154) updates the
  `CreditCard` validator to allow 19 digit Discover card values, and 13 and 19
  digit Visa card values, which are now allowed (see
  https://en.wikipedia.org/wiki/Payment_card_number).
- [zendframework/zend-validator#162](https://github.com/zendframework/zend-validator/pull/162) updates the
  `Hostname` validator to support `.hr` (Croatia) IDN domains.
- [zendframework/zend-validator#163](https://github.com/zendframework/zend-validator/pull/163) updates the
  `Iban` validator to support Belarus.

### Deprecated

- Nothing.

### Removed

- Nothing.

### Fixed

- [zendframework/zend-validator#168](https://github.com/zendframework/zend-validator/pull/168) fixes how the
  `ValidatorPluginManagerFactory` factory initializes the plugin manager instance,
  ensuring it is injecting the relevant configuration from the `config` service
  and thus seeding it with configured validator services. This means
  that the `validators` configuration will now be honored in non-laminas-mvc contexts.

## 2.9.0 - 2017-03-17

### Added

- [zendframework/zend-validator#78](https://github.com/zendframework/zend-validator/pull/78) added
  `%length%` as an optional message variable in StringLength validator

### Deprecated

- Nothing.

### Removed

- [zendframework/zend-validator#151](https://github.com/zendframework/zend-validator/pull/151) dropped
  php 5.5 support

### Fixed

- [zendframework/zend-validator#147](https://github.com/zendframework/zend-validator/issues/147)
  [zendframework/zend-validator#148](https://github.com/zendframework/zend-validator/pull/148) adds further
  `"suggest"` clauses in `composer.json`, since some dependencies are not always
  required, and may lead to runtime failures.
- [zendframework/zend-validator#66](https://github.com/zendframework/zend-validator/pull/66) fixed
  EmailAddress validator applying IDNA conversion to local part 
- [zendframework/zend-validator#88](https://github.com/zendframework/zend-validator/pull/88) fixed NotEmpty
  validator incorrectly applying types bitmaps
- [zendframework/zend-validator#150](https://github.com/zendframework/zend-validator/pull/150) fixed Hostname
  validator not allowing some characters in .dk IDN

## 2.8.2 - 2017-01-29

### Added

- [zendframework/zend-validator#110](https://github.com/zendframework/zend-validator/pull/110) adds new
  Mastercard 2-series BINs

### Deprecated

- Nothing.

### Removed

- Nothing.

### Fixed

- [zendframework/zend-validator#81](https://github.com/zendframework/zend-validator/pull/81) registers the
  Uuid validator into ValidatorPluginManager.

## 2.8.1 - 2016-06-23

### Added

- Nothing.

### Deprecated

- Nothing.

### Removed

- Nothing.

### Fixed

- [zendframework/zend-validator#92](https://github.com/zendframework/zend-validator/pull/92) adds message
  templates to the `ExcludeMimeType` validator, to allow differentiating
  validation error messages from the `MimeType` validator.

## 2.8.0 - 2016-05-16

### Added

- [zendframework/zend-validator#58](https://github.com/zendframework/zend-validator/pull/58) adds a new
  `Uuid` validator, capable of validating if Versions 1-5 UUIDs are well-formed.
- [zendframework/zend-validator#64](https://github.com/zendframework/zend-validator/pull/64) ports
  `Laminas\ModuleManager\Feature\ValidatorProviderInterface` to
  `Laminas\Validator\ValidatorProviderInterface`, and updates the `Module::init()`
  to typehint against the new interface instead of the one from
  laminas-modulemanager. Applications targeting laminas-mvc v3 can start updating
  their code to implement the new interface, or simply duck-type against it.

### Deprecated

- Nothing.

### Removed

- Nothing.

### Fixed

- Nothing.

## 2.7.3 - 2016-05-16

### Added

- [zendframework/zend-validator#67](https://github.com/zendframework/zend-validator/pull/67) adds support
  for Punycoded top-level domains in the `Hostname` validator.
- [zendframework/zend-validator#79](https://github.com/zendframework/zend-validator/pull/79) adds and
  publishes the documentation to https://docs.laminas.dev/laminas-validator/

### Deprecated

- Nothing.

### Removed

- Nothing.

### Fixed

- Nothing.

## 2.7.2 - 2016-04-18

### Added

- Nothing.

### Deprecated

- Nothing.

### Removed

- Nothing.

### Fixed

- [zendframework/zend-validator#65](https://github.com/zendframework/zend-validator/pull/65) fixes the
  `Module::init()` method to properly receive a `ModuleManager` instance, and
  not expect a `ModuleEvent`.

## 2.7.1 - 2016-04-06

### Added

- Nothing.

### Deprecated

- Nothing.

### Removed

- Nothing.

### Fixed

- This release updates the TLD list to the latest version from the IANA.

## 2.7.0 - 2016-04-06

### Added

- [zendframework/zend-validator#63](https://github.com/zendframework/zend-validator/pull/63) exposes the
  package as a Laminas component and/or generic configuration provider, by adding the
  following:
  - `ValidatorPluginManagerFactory`, which can be consumed by container-interop /
    laminas-servicemanager to create and return a `ValidatorPluginManager` instance.
  - `ConfigProvider`, which maps the service `ValidatorManager` to the above
    factory.
  - `Module`, which does the same as `ConfigProvider`, but specifically for
    laminas-mvc applications. It also provices a specification to
    `Laminas\ModuleManager\Listener\ServiceListener` to allow modules to provide
    validator configuration.

### Deprecated

- Nothing.

### Removed

- Nothing.

### Fixed

- Nothing.

## 2.6.0 - 2016-02-17

### Added

- [zendframework/zend-validator#18](https://github.com/zendframework/zend-validator/pull/18) adds a `GpsPoint`
  validator for validating GPS coordinates.
- [zendframework/zend-validator#47](https://github.com/zendframework/zend-validator/pull/47) adds two new
  classes, `Laminas\Validator\Isbn\Isbn10` and `Isbn13`; these classes are the
  result of an extract class refactoring, and contain the logic specific to
  calcualting the checksum for each ISBN style. `Laminas\Validator\Isbn` now
  instantiates the appropriate one and invokes it.
- [zendframework/zend-validator#46](https://github.com/zendframework/zend-validator/pull/46) updates
  `Laminas\Validator\Db\AbstractDb` to implement `Laminas\Db\Adapter\AdapterAwareInterface`,
  by composing `Laminas\Db\Adapter\AdapterAwareTrait`.

### Deprecated

- Nothing.

### Removed

- [zendframework/zend-validator#55](https://github.com/zendframework/zend-validator/pull/55) removes some
  checks for `safe_mode` within the `MimeType` validator, as `safe_mode` became
  obsolete starting with PHP 5.4.

### Fixed

- [zendframework/zend-validator#45](https://github.com/zendframework/zend-validator/pull/45) fixes aliases
  mapping the deprecated `Float` and `Int` validators to their `Is*` counterparts.
- [zendframework/zend-validator#49](https://github.com/zendframework/zend-validator/pull/49)
  [zendframework/zend-validator#50](https://github.com/zendframework/zend-validator/pull/50), and
  [zendframework/zend-validator#51](https://github.com/zendframework/zend-validator/pull/51) update the
  code to be forwards-compatible with laminas-servicemanager and laminas-stdlib v3.
- [zendframework/zend-validator#56](https://github.com/zendframework/zend-validator/pull/56) fixes the regex
  in the `Ip` validator to escape `.` characters used as IP delimiters.

## 2.5.4 - 2016-02-17

### Added

- Nothing.

### Deprecated

- Nothing.

### Removed

- Nothing.

### Fixed

- [zendframework/zend-validator#44](https://github.com/zendframework/zend-validator/pull/44) corrects the
  grammar on the `NOT_GREATER_INCLUSIVE` validation error message.
- [zendframework/zend-validator#45](https://github.com/zendframework/zend-validator/pull/45) adds normalized
  aliases for the i18n isfloat/isint validators.
- Updates the hostname validator regexes per the canonical service on which they
  are based.
- [zendframework/zend-validator#52](https://github.com/zendframework/zend-validator/pull/52) updates the
  `Barcode` validator to cast empty options passed to the constructor to an
  empty array, fixing type mismatch errors.
- [zendframework/zend-validator#54](https://github.com/zendframework/zend-validator/pull/54) fixes the IP
  address detection in the `Hostname` validator to ensure that IPv6 is detected
  correctly.
- [zendframework/zend-validator#56](https://github.com/zendframework/zend-validator/pull/56) updates the
  regexes used by the `IP` validator when comparing ipv4 addresses to ensure a
  literal `.` is tested between network segments.

## 2.5.3 - 2015-09-03

### Added

- [zendframework/zend-validator#30](https://github.com/zendframework/zend-validator/pull/30) adds tooling to
  ensure that the Hostname TLD list stays up-to-date as changes are pushed for
  the repository.

### Deprecated

- Nothing.

### Removed

- Nothing.

### Fixed

- [zendframework/zend-validator#17](https://github.com/zendframework/zend-validator/pull/17) and
  [zendframework/zend-validator#29](https://github.com/zendframework/zend-validator/pull/29) provide more
  test coverage, and fix a number of edge cases, primarily in validator option
  verifications.
- [zendframework/zend-validator#26](https://github.com/zendframework/zend-validator/pull/26) fixes tests for
  `StaticValidator` such that they make correct assertions now. In doing so, we
  determined that it was possible to pass an indexed array of options, which
  could lead to unexpected results, often leading to false positives when
  validating. To correct this situation, `StaticValidator::execute()` now raises
  an `InvalidArgumentException` when an indexed array is detected for the
  `$options` argument.
- [zendframework/zend-validator#35](https://github.com/zendframework/zend-validator/pull/35) modifies the
  `NotEmpty` validator to no longer treat the float `0.0` as an empty value for
  purposes of validation.
- [zendframework/zend-validator#25](https://github.com/zendframework/zend-validator/pull/25) fixes the
  `Date` validator to check against `DateTimeImmutable` and not
  `DateTimeInterface` (as PHP has restrictions currently on how the latter can
  be used).

## 2.5.2 - 2015-07-16

### Added

- [zendframework/zend-validator#8](https://github.com/zendframework/zend-validator/pull/8) adds a "strict"
  configuration option; when enabled (the default), the length of the address is
  checked to ensure it follows the specification.

### Deprecated

- Nothing.

### Removed

- Nothing.

### Fixed

- [zendframework/zend-validator#8](https://github.com/zendframework/zend-validator/pull/8) fixes bad
  behavior on the part of the `idn_to_utf8()` function, returning the original
  address in the case that the function fails.
- [zendframework/zend-validator#11](https://github.com/zendframework/zend-validator/pull/11) fixes
  `ValidatorChain::prependValidator()` so that it works on HHVM.
- [zendframework/zend-validator#12](https://github.com/zendframework/zend-validator/pull/12) adds "6772" to
  the Maestro range of the `CreditCard` validator.
laminas-validator/LICENSE.md000064400000002732147361032560011572 0ustar00Copyright (c) 2019-2020, Laminas Foundation
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

- Redistributions of source code must retain the above copyright notice, this
  list of conditions and the following disclaimer.

- Redistributions in binary form must reproduce the above copyright notice,
  this list of conditions and the following disclaimer in the documentation
  and/or other materials provided with the distribution.

- Neither the name of Laminas Foundation nor the names of its contributors may
  be used to endorse or promote products derived from this software without
  specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
laminas-diactoros/COPYRIGHT.md000064400000000133147361032560012053 0ustar00Copyright (c) 2020 Laminas Project a Series of LF Projects, LLC. (https://getlaminas.org/)
laminas-diactoros/src/Response/XmlResponse.php000064400000004542147361032560015546 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-diactoros for the canonical source repository
 * @copyright https://github.com/laminas/laminas-diactoros/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-diactoros/blob/master/LICENSE.md New BSD License
 */

declare(strict_types=1);

namespace Laminas\Diactoros\Response;

use Laminas\Diactoros\Exception;
use Laminas\Diactoros\Response;
use Laminas\Diactoros\Stream;
use Psr\Http\Message\StreamInterface;

use function get_class;
use function gettype;
use function is_object;
use function is_string;
use function sprintf;

/**
 * XML response.
 *
 * Allows creating a response by passing an XML string to the constructor; by default,
 * sets a status code of 200 and sets the Content-Type header to application/xml.
 */
class XmlResponse extends Response
{
    use InjectContentTypeTrait;

    /**
     * Create an XML response.
     *
     * Produces an XML response with a Content-Type of application/xml and a default
     * status of 200.
     *
     * @param string|StreamInterface $xml String or stream for the message body.
     * @param int $status Integer status code for the response; 200 by default.
     * @param array $headers Array of headers to use at initialization.
     * @throws Exception\InvalidArgumentException if $text is neither a string or stream.
     */
    public function __construct(
        $xml,
        int $status = 200,
        array $headers = []
    ) {
        parent::__construct(
            $this->createBody($xml),
            $status,
            $this->injectContentType('application/xml; charset=utf-8', $headers)
        );
    }

    /**
     * Create the message body.
     *
     * @param string|StreamInterface $xml
     * @throws Exception\InvalidArgumentException if $xml is neither a string or stream.
     */
    private function createBody($xml) : StreamInterface
    {
        if ($xml instanceof StreamInterface) {
            return $xml;
        }

        if (! is_string($xml)) {
            throw new Exception\InvalidArgumentException(sprintf(
                'Invalid content (%s) provided to %s',
                (is_object($xml) ? get_class($xml) : gettype($xml)),
                __CLASS__
            ));
        }

        $body = new Stream('php://temp', 'wb+');
        $body->write($xml);
        $body->rewind();
        return $body;
    }
}
laminas-diactoros/src/Response/Serializer.php000064400000006446147361032560015405 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-diactoros for the canonical source repository
 * @copyright https://github.com/laminas/laminas-diactoros/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-diactoros/blob/master/LICENSE.md New BSD License
 */

declare(strict_types=1);

namespace Laminas\Diactoros\Response;

use Laminas\Diactoros\AbstractSerializer;
use Laminas\Diactoros\Exception;
use Laminas\Diactoros\Response;
use Laminas\Diactoros\Stream;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\StreamInterface;

use function preg_match;
use function sprintf;

final class Serializer extends AbstractSerializer
{
    /**
     * Deserialize a response string to a response instance.
     *
     * @throws Exception\SerializationException when errors occur parsing the message.
     */
    public static function fromString(string $message) : Response
    {
        $stream = new Stream('php://temp', 'wb+');
        $stream->write($message);
        return static::fromStream($stream);
    }

    /**
     * Parse a response from a stream.
     *
     * @throws Exception\InvalidArgumentException when the stream is not readable.
     * @throws Exception\SerializationException when errors occur parsing the message.
     */
    public static function fromStream(StreamInterface $stream) : Response
    {
        if (! $stream->isReadable() || ! $stream->isSeekable()) {
            throw new Exception\InvalidArgumentException('Message stream must be both readable and seekable');
        }

        $stream->rewind();

        [$version, $status, $reasonPhrase] = self::getStatusLine($stream);
        [$headers, $body]                  = self::splitStream($stream);

        return (new Response($body, $status, $headers))
            ->withProtocolVersion($version)
            ->withStatus((int) $status, $reasonPhrase);
    }

    /**
     * Create a string representation of a response.
     */
    public static function toString(ResponseInterface $response) : string
    {
        $reasonPhrase = $response->getReasonPhrase();
        $headers      = self::serializeHeaders($response->getHeaders());
        $body         = (string) $response->getBody();
        $format       = 'HTTP/%s %d%s%s%s';

        if (! empty($headers)) {
            $headers = "\r\n" . $headers;
        }

        $headers .= "\r\n\r\n";

        return sprintf(
            $format,
            $response->getProtocolVersion(),
            $response->getStatusCode(),
            ($reasonPhrase ? ' ' . $reasonPhrase : ''),
            $headers,
            $body
        );
    }

    /**
     * Retrieve the status line for the message.
     *
     * @return array Array with three elements: 0 => version, 1 => status, 2 => reason
     * @throws Exception\SerializationException if line is malformed
     */
    private static function getStatusLine(StreamInterface $stream) : array
    {
        $line = self::getLine($stream);

        if (! preg_match(
            '#^HTTP/(?P<version>[1-9]\d*\.\d) (?P<status>[1-5]\d{2})(\s+(?P<reason>.+))?$#',
            $line,
            $matches
        )) {
            throw Exception\SerializationException::forInvalidStatusLine();
        }

        return [$matches['version'], (int) $matches['status'], isset($matches['reason']) ? $matches['reason'] : ''];
    }
}
laminas-diactoros/src/Response/TextResponse.php000064400000004522147361032560015730 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-diactoros for the canonical source repository
 * @copyright https://github.com/laminas/laminas-diactoros/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-diactoros/blob/master/LICENSE.md New BSD License
 */

declare(strict_types=1);

namespace Laminas\Diactoros\Response;

use Laminas\Diactoros\Exception;
use Laminas\Diactoros\Response;
use Laminas\Diactoros\Stream;
use Psr\Http\Message\StreamInterface;

use function get_class;
use function gettype;
use function is_object;
use function is_string;
use function sprintf;

/**
 * Plain text response.
 *
 * Allows creating a response by passing a string to the constructor;
 * by default, sets a status code of 200 and sets the Content-Type header to
 * text/plain.
 */
class TextResponse extends Response
{
    use InjectContentTypeTrait;

    /**
     * Create a plain text response.
     *
     * Produces a text response with a Content-Type of text/plain and a default
     * status of 200.
     *
     * @param string|StreamInterface $text String or stream for the message body.
     * @param int $status Integer status code for the response; 200 by default.
     * @param array $headers Array of headers to use at initialization.
     * @throws Exception\InvalidArgumentException if $text is neither a string or stream.
     */
    public function __construct($text, int $status = 200, array $headers = [])
    {
        parent::__construct(
            $this->createBody($text),
            $status,
            $this->injectContentType('text/plain; charset=utf-8', $headers)
        );
    }

    /**
     * Create the message body.
     *
     * @param string|StreamInterface $text
     * @throws Exception\InvalidArgumentException if $text is neither a string or stream.
     */
    private function createBody($text) : StreamInterface
    {
        if ($text instanceof StreamInterface) {
            return $text;
        }

        if (! is_string($text)) {
            throw new Exception\InvalidArgumentException(sprintf(
                'Invalid content (%s) provided to %s',
                (is_object($text) ? get_class($text) : gettype($text)),
                __CLASS__
            ));
        }

        $body = new Stream('php://temp', 'wb+');
        $body->write($text);
        $body->rewind();
        return $body;
    }
}
laminas-diactoros/src/Response/ArraySerializer.php000064400000005604147361032560016377 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-diactoros for the canonical source repository
 * @copyright https://github.com/laminas/laminas-diactoros/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-diactoros/blob/master/LICENSE.md New BSD License
 */

declare(strict_types=1);

namespace Laminas\Diactoros\Response;

use Laminas\Diactoros\Exception;
use Laminas\Diactoros\Response;
use Laminas\Diactoros\Stream;
use Psr\Http\Message\ResponseInterface;
use Throwable;

use function sprintf;

/**
 * Serialize or deserialize response messages to/from arrays.
 *
 * This class provides functionality for serializing a ResponseInterface instance
 * to an array, as well as the reverse operation of creating a Response instance
 * from an array representing a message.
 */
final class ArraySerializer
{
    /**
     * Serialize a response message to an array.
     */
    public static function toArray(ResponseInterface $response) : array
    {
        return [
            'status_code'      => $response->getStatusCode(),
            'reason_phrase'    => $response->getReasonPhrase(),
            'protocol_version' => $response->getProtocolVersion(),
            'headers'          => $response->getHeaders(),
            'body'             => (string) $response->getBody(),
        ];
    }

    /**
     * Deserialize a response array to a response instance.
     *
     * @throws Exception\DeserializationException when cannot deserialize response
     */
    public static function fromArray(array $serializedResponse) : Response
    {
        try {
            $body = new Stream('php://memory', 'wb+');
            $body->write(self::getValueFromKey($serializedResponse, 'body'));

            $statusCode      = self::getValueFromKey($serializedResponse, 'status_code');
            $headers         = self::getValueFromKey($serializedResponse, 'headers');
            $protocolVersion = self::getValueFromKey($serializedResponse, 'protocol_version');
            $reasonPhrase    = self::getValueFromKey($serializedResponse, 'reason_phrase');

            return (new Response($body, $statusCode, $headers))
                ->withProtocolVersion($protocolVersion)
                ->withStatus($statusCode, $reasonPhrase);
        } catch (Throwable $exception) {
            throw Exception\DeserializationException::forResponseFromArray($exception);
        }
    }

    /**
     * @param array $data
     * @param string $key
     * @param string $message
     * @return mixed
     * @throws UnexpectedValueException
     */
    private static function getValueFromKey(array $data, string $key, string $message = null)
    {
        if (isset($data[$key])) {
            return $data[$key];
        }
        if ($message === null) {
            $message = sprintf('Missing "%s" key in serialized response', $key);
        }
        throw new Exception\DeserializationException($message);
    }
}
laminas-diactoros/src/Response/EmptyResponse.php000064400000002261147361032560016100 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-diactoros for the canonical source repository
 * @copyright https://github.com/laminas/laminas-diactoros/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-diactoros/blob/master/LICENSE.md New BSD License
 */

declare(strict_types=1);

namespace Laminas\Diactoros\Response;

use Laminas\Diactoros\Response;
use Laminas\Diactoros\Stream;

/**
 * A class representing empty HTTP responses.
 */
class EmptyResponse extends Response
{
    /**
     * Create an empty response with the given status code.
     *
     * @param int $status Status code for the response, if any.
     * @param array $headers Headers for the response, if any.
     */
    public function __construct(int $status = 204, array $headers = [])
    {
        $body = new Stream('php://temp', 'r');
        parent::__construct($body, $status, $headers);
    }

    /**
     * Create an empty response with the given headers.
     *
     * @param array $headers Headers for the response.
     * @return EmptyResponse
     */
    public static function withHeaders(array $headers) : EmptyResponse
    {
        return new static(204, $headers);
    }
}
laminas-diactoros/src/Response/HtmlResponse.php000064400000004511147361032560015706 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-diactoros for the canonical source repository
 * @copyright https://github.com/laminas/laminas-diactoros/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-diactoros/blob/master/LICENSE.md New BSD License
 */

declare(strict_types=1);

namespace Laminas\Diactoros\Response;

use Laminas\Diactoros\Exception;
use Laminas\Diactoros\Response;
use Laminas\Diactoros\Stream;
use Psr\Http\Message\StreamInterface;

use function get_class;
use function gettype;
use function is_object;
use function is_string;
use function sprintf;

/**
 * HTML response.
 *
 * Allows creating a response by passing an HTML string to the constructor;
 * by default, sets a status code of 200 and sets the Content-Type header to
 * text/html.
 */
class HtmlResponse extends Response
{
    use InjectContentTypeTrait;

    /**
     * Create an HTML response.
     *
     * Produces an HTML response with a Content-Type of text/html and a default
     * status of 200.
     *
     * @param string|StreamInterface $html HTML or stream for the message body.
     * @param int $status Integer status code for the response; 200 by default.
     * @param array $headers Array of headers to use at initialization.
     * @throws Exception\InvalidArgumentException if $html is neither a string or stream.
     */
    public function __construct($html, int $status = 200, array $headers = [])
    {
        parent::__construct(
            $this->createBody($html),
            $status,
            $this->injectContentType('text/html; charset=utf-8', $headers)
        );
    }

    /**
     * Create the message body.
     *
     * @param string|StreamInterface $html
     * @throws Exception\InvalidArgumentException if $html is neither a string or stream.
     */
    private function createBody($html) : StreamInterface
    {
        if ($html instanceof StreamInterface) {
            return $html;
        }

        if (! is_string($html)) {
            throw new Exception\InvalidArgumentException(sprintf(
                'Invalid content (%s) provided to %s',
                (is_object($html) ? get_class($html) : gettype($html)),
                __CLASS__
            ));
        }

        $body = new Stream('php://temp', 'wb+');
        $body->write($html);
        $body->rewind();
        return $body;
    }
}
laminas-diactoros/src/Response/RedirectResponse.php000064400000003233147361032560016543 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-diactoros for the canonical source repository
 * @copyright https://github.com/laminas/laminas-diactoros/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-diactoros/blob/master/LICENSE.md New BSD License
 */

declare(strict_types=1);

namespace Laminas\Diactoros\Response;

use Laminas\Diactoros\Exception;
use Laminas\Diactoros\Response;
use Psr\Http\Message\UriInterface;

use function get_class;
use function gettype;
use function is_object;
use function is_string;
use function sprintf;

/**
 * Produce a redirect response.
 */
class RedirectResponse extends Response
{
    /**
     * Create a redirect response.
     *
     * Produces a redirect response with a Location header and the given status
     * (302 by default).
     *
     * Note: this method overwrites the `location` $headers value.
     *
     * @param string|UriInterface $uri URI for the Location header.
     * @param int $status Integer status code for the redirect; 302 by default.
     * @param array $headers Array of headers to use at initialization.
     */
    public function __construct($uri, int $status = 302, array $headers = [])
    {
        if (! is_string($uri) && ! $uri instanceof UriInterface) {
            throw new Exception\InvalidArgumentException(sprintf(
                'Uri provided to %s MUST be a string or Psr\Http\Message\UriInterface instance; received "%s"',
                __CLASS__,
                (is_object($uri) ? get_class($uri) : gettype($uri))
            ));
        }

        $headers['location'] = [(string) $uri];
        parent::__construct('php://temp', $status, $headers);
    }
}
laminas-diactoros/src/Response/InjectContentTypeTrait.php000064400000001766147361032560017711 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-diactoros for the canonical source repository
 * @copyright https://github.com/laminas/laminas-diactoros/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-diactoros/blob/master/LICENSE.md New BSD License
 */

declare(strict_types=1);

namespace Laminas\Diactoros\Response;

use function array_keys;
use function array_reduce;
use function strtolower;

trait InjectContentTypeTrait
{
    /**
     * Inject the provided Content-Type, if none is already present.
     *
     * @return array Headers with injected Content-Type
     */
    private function injectContentType(string $contentType, array $headers) : array
    {
        $hasContentType = array_reduce(array_keys($headers), function ($carry, $item) {
            return $carry ?: (strtolower($item) === 'content-type');
        }, false);

        if (! $hasContentType) {
            $headers['content-type'] = [$contentType];
        }

        return $headers;
    }
}
laminas-diactoros/src/Response/JsonResponse.php000064400000011367147361032560015722 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-diactoros for the canonical source repository
 * @copyright https://github.com/laminas/laminas-diactoros/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-diactoros/blob/master/LICENSE.md New BSD License
 */

declare(strict_types=1);

namespace Laminas\Diactoros\Response;

use Laminas\Diactoros\Exception;
use Laminas\Diactoros\Response;
use Laminas\Diactoros\Stream;

use function is_object;
use function is_resource;
use function json_encode;
use function json_last_error;
use function json_last_error_msg;
use function sprintf;

use const JSON_ERROR_NONE;

/**
 * JSON response.
 *
 * Allows creating a response by passing data to the constructor; by default,
 * serializes the data to JSON, sets a status code of 200 and sets the
 * Content-Type header to application/json.
 */
class JsonResponse extends Response
{
    use InjectContentTypeTrait;

    /**
     * Default flags for json_encode; value of:
     *
     * <code>
     * JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_AMP | JSON_HEX_QUOT | JSON_UNESCAPED_SLASHES
     * </code>
     *
     * @const int
     */
    const DEFAULT_JSON_FLAGS = 79;

    /**
     * @var mixed
     */
    private $payload;

    /**
     * @var int
     */
    private $encodingOptions;

    /**
     * Create a JSON response with the given data.
     *
     * Default JSON encoding is performed with the following options, which
     * produces RFC4627-compliant JSON, capable of embedding into HTML.
     *
     * - JSON_HEX_TAG
     * - JSON_HEX_APOS
     * - JSON_HEX_AMP
     * - JSON_HEX_QUOT
     * - JSON_UNESCAPED_SLASHES
     *
     * @param mixed $data Data to convert to JSON.
     * @param int $status Integer status code for the response; 200 by default.
     * @param array $headers Array of headers to use at initialization.
     * @param int $encodingOptions JSON encoding options to use.
     * @throws Exception\InvalidArgumentException if unable to encode the $data to JSON.
     */
    public function __construct(
        $data,
        int $status = 200,
        array $headers = [],
        int $encodingOptions = self::DEFAULT_JSON_FLAGS
    ) {
        $this->setPayload($data);
        $this->encodingOptions = $encodingOptions;

        $json = $this->jsonEncode($data, $this->encodingOptions);
        $body = $this->createBodyFromJson($json);

        $headers = $this->injectContentType('application/json', $headers);

        parent::__construct($body, $status, $headers);
    }

    /**
     * @return mixed
     */
    public function getPayload()
    {
        return $this->payload;
    }

    /**
     * @param mixed $data
     */
    public function withPayload($data) : JsonResponse
    {
        $new = clone $this;
        $new->setPayload($data);
        return $this->updateBodyFor($new);
    }

    public function getEncodingOptions() : int
    {
        return $this->encodingOptions;
    }

    public function withEncodingOptions(int $encodingOptions) : JsonResponse
    {
        $new = clone $this;
        $new->encodingOptions = $encodingOptions;
        return $this->updateBodyFor($new);
    }

    private function createBodyFromJson(string $json) : Stream
    {
        $body = new Stream('php://temp', 'wb+');
        $body->write($json);
        $body->rewind();

        return $body;
    }

    /**
     * Encode the provided data to JSON.
     *
     * @param mixed $data
     * @throws Exception\InvalidArgumentException if unable to encode the $data to JSON.
     */
    private function jsonEncode($data, int $encodingOptions) : string
    {
        if (is_resource($data)) {
            throw new Exception\InvalidArgumentException('Cannot JSON encode resources');
        }

        // Clear json_last_error()
        json_encode(null);

        $json = json_encode($data, $encodingOptions);

        if (JSON_ERROR_NONE !== json_last_error()) {
            throw new Exception\InvalidArgumentException(sprintf(
                'Unable to encode data to JSON in %s: %s',
                __CLASS__,
                json_last_error_msg()
            ));
        }

        return $json;
    }

    /**
     * @param mixed $data
     */
    private function setPayload($data) : void
    {
        if (is_object($data)) {
            $data = clone $data;
        }

        $this->payload = $data;
    }

    /**
     * Update the response body for the given instance.
     *
     * @param self $toUpdate Instance to update.
     * @return JsonResponse Returns a new instance with an updated body.
     */
    private function updateBodyFor(JsonResponse $toUpdate) : JsonResponse
    {
        $json = $this->jsonEncode($toUpdate->payload, $toUpdate->encodingOptions);
        $body = $this->createBodyFromJson($json);
        return $toUpdate->withBody($body);
    }
}
laminas-diactoros/src/AbstractSerializer.php000064400000010752147361032560015266 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-diactoros for the canonical source repository
 * @copyright https://github.com/laminas/laminas-diactoros/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-diactoros/blob/master/LICENSE.md New BSD License
 */

declare(strict_types=1);

namespace Laminas\Diactoros;

use Psr\Http\Message\StreamInterface;

use function array_pop;
use function implode;
use function ltrim;
use function preg_match;
use function sprintf;
use function str_replace;
use function ucwords;

/**
 * Provides base functionality for request and response de/serialization
 * strategies, including functionality for retrieving a line at a time from
 * the message, splitting headers from the body, and serializing headers.
 */
abstract class AbstractSerializer
{
    const CR  = "\r";
    const EOL = "\r\n";
    const LF  = "\n";

    /**
     * Retrieve a single line from the stream.
     *
     * Retrieves a line from the stream; a line is defined as a sequence of
     * characters ending in a CRLF sequence.
     *
     * @throws Exception\DeserializationException if the sequence contains a CR
     *     or LF in isolation, or ends in a CR.
     */
    protected static function getLine(StreamInterface $stream) : string
    {
        $line    = '';
        $crFound = false;
        while (! $stream->eof()) {
            $char = $stream->read(1);

            if ($crFound && $char === self::LF) {
                $crFound = false;
                break;
            }

            // CR NOT followed by LF
            if ($crFound && $char !== self::LF) {
                throw Exception\DeserializationException::forUnexpectedCarriageReturn();
            }

            // LF in isolation
            if (! $crFound && $char === self::LF) {
                throw Exception\DeserializationException::forUnexpectedLineFeed();
            }

            // CR found; do not append
            if ($char === self::CR) {
                $crFound = true;
                continue;
            }

            // Any other character: append
            $line .= $char;
        }

        // CR found at end of stream
        if ($crFound) {
            throw Exception\DeserializationException::forUnexpectedEndOfHeaders();
        }

        return $line;
    }

    /**
     * Split the stream into headers and body content.
     *
     * Returns an array containing two elements
     *
     * - The first is an array of headers
     * - The second is a StreamInterface containing the body content
     *
     * @throws Exception\DeserializationException For invalid headers.
     */
    protected static function splitStream(StreamInterface $stream) : array
    {
        $headers       = [];
        $currentHeader = false;

        while ($line = self::getLine($stream)) {
            if (preg_match(';^(?P<name>[!#$%&\'*+.^_`\|~0-9a-zA-Z-]+):(?P<value>.*)$;', $line, $matches)) {
                $currentHeader = $matches['name'];
                if (! isset($headers[$currentHeader])) {
                    $headers[$currentHeader] = [];
                }
                $headers[$currentHeader][] = ltrim($matches['value']);
                continue;
            }

            if (! $currentHeader) {
                throw Exception\DeserializationException::forInvalidHeader();
            }

            if (! preg_match('#^[ \t]#', $line)) {
                throw Exception\DeserializationException::forInvalidHeaderContinuation();
            }

            // Append continuation to last header value found
            $value = array_pop($headers[$currentHeader]);
            $headers[$currentHeader][] = $value . ltrim($line);
        }

        // use RelativeStream to avoid copying initial stream into memory
        return [$headers, new RelativeStream($stream, $stream->tell())];
    }

    /**
     * Serialize headers to string values.
     */
    protected static function serializeHeaders(array $headers) : string
    {
        $lines = [];
        foreach ($headers as $header => $values) {
            $normalized = self::filterHeader($header);
            foreach ($values as $value) {
                $lines[] = sprintf('%s: %s', $normalized, $value);
            }
        }

        return implode("\r\n", $lines);
    }

    /**
     * Filter a header name to wordcase
     */
    protected static function filterHeader($header) : string
    {
        $filtered = str_replace('-', ' ', $header);
        $filtered = ucwords($filtered);
        return str_replace(' ', '-', $filtered);
    }
}
laminas-diactoros/src/HeaderSecurity.php000064400000012476147361032560014416 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-diactoros for the canonical source repository
 * @copyright https://github.com/laminas/laminas-diactoros/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-diactoros/blob/master/LICENSE.md New BSD License
 */

declare(strict_types=1);

namespace Laminas\Diactoros;

use function get_class;
use function gettype;
use function in_array;
use function is_numeric;
use function is_object;
use function is_string;
use function ord;
use function preg_match;
use function sprintf;
use function strlen;

/**
 * Provide security tools around HTTP headers to prevent common injection vectors.
 *
 * Code is largely lifted from the Laminas\Http\Header\HeaderValue implementation in
 * Laminas, released with the copyright and license below.
 *
 * @copyright Copyright (c) 2005-2015 Laminas (https://www.zend.com)
 * @license   https://getlaminas.org/license/new-bsd New BSD License
 */
final class HeaderSecurity
{
    /**
     * Private constructor; non-instantiable.
     * @codeCoverageIgnore
     */
    private function __construct()
    {
    }

    /**
     * Filter a header value
     *
     * Ensures CRLF header injection vectors are filtered.
     *
     * Per RFC 7230, only VISIBLE ASCII characters, spaces, and horizontal
     * tabs are allowed in values; header continuations MUST consist of
     * a single CRLF sequence followed by a space or horizontal tab.
     *
     * This method filters any values not allowed from the string, and is
     * lossy.
     *
     * @see http://en.wikipedia.org/wiki/HTTP_response_splitting
     */
    public static function filter(string $value) : string
    {
        $value  = (string) $value;
        $length = strlen($value);
        $string = '';
        for ($i = 0; $i < $length; $i += 1) {
            $ascii = ord($value[$i]);

            // Detect continuation sequences
            if ($ascii === 13) {
                $lf = ord($value[$i + 1]);
                $ws = ord($value[$i + 2]);
                if ($lf === 10 && in_array($ws, [9, 32], true)) {
                    $string .= $value[$i] . $value[$i + 1];
                    $i += 1;
                }

                continue;
            }

            // Non-visible, non-whitespace characters
            // 9 === horizontal tab
            // 32-126, 128-254 === visible
            // 127 === DEL
            // 255 === null byte
            if (($ascii < 32 && $ascii !== 9)
                || $ascii === 127
                || $ascii > 254
            ) {
                continue;
            }

            $string .= $value[$i];
        }

        return $string;
    }

    /**
     * Validate a header value.
     *
     * Per RFC 7230, only VISIBLE ASCII characters, spaces, and horizontal
     * tabs are allowed in values; header continuations MUST consist of
     * a single CRLF sequence followed by a space or horizontal tab.
     *
     * @param string|int|float $value
     * @see http://en.wikipedia.org/wiki/HTTP_response_splitting
     */
    public static function isValid($value) : bool
    {
        $value  = (string) $value;

        // Look for:
        // \n not preceded by \r, OR
        // \r not followed by \n, OR
        // \r\n not followed by space or horizontal tab; these are all CRLF attacks
        if (preg_match("#(?:(?:(?<!\r)\n)|(?:\r(?!\n))|(?:\r\n(?![ \t])))#", $value)) {
            return false;
        }

        // Non-visible, non-whitespace characters
        // 9 === horizontal tab
        // 10 === line feed
        // 13 === carriage return
        // 32-126, 128-254 === visible
        // 127 === DEL (disallowed)
        // 255 === null byte (disallowed)
        if (preg_match('/[^\x09\x0a\x0d\x20-\x7E\x80-\xFE]/', $value)) {
            return false;
        }

        return true;
    }

    /**
     * Assert a header value is valid.
     *
     * @param mixed $value Value to be tested. This method asserts it is a string or number.
     * @throws Exception\InvalidArgumentException for invalid values
     */
    public static function assertValid($value)
    {
        if (! is_string($value) && ! is_numeric($value)) {
            throw new Exception\InvalidArgumentException(sprintf(
                'Invalid header value type; must be a string or numeric; received %s',
                (is_object($value) ? get_class($value) : gettype($value))
            ));
        }
        if (! self::isValid($value)) {
            throw new Exception\InvalidArgumentException(sprintf(
                '"%s" is not valid header value',
                $value
            ));
        }
    }

    /**
     * Assert whether or not a header name is valid.
     *
     * @see http://tools.ietf.org/html/rfc7230#section-3.2
     * @param mixed $name
     * @throws Exception\InvalidArgumentException
     */
    public static function assertValidName($name)
    {
        if (! is_string($name)) {
            throw new Exception\InvalidArgumentException(sprintf(
                'Invalid header name type; expected string; received %s',
                (is_object($name) ? get_class($name) : gettype($name))
            ));
        }
        if (! preg_match('/^[a-zA-Z0-9\'`#$%&*+.^_|~!-]+$/', $name)) {
            throw new Exception\InvalidArgumentException(sprintf(
                '"%s" is not valid header name',
                $name
            ));
        }
    }
}
laminas-diactoros/src/RequestFactory.php000064400000001226147361032560014445 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-diactoros for the canonical source repository
 * @copyright https://github.com/laminas/laminas-diactoros/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-diactoros/blob/master/LICENSE.md New BSD License
 */

declare(strict_types=1);

namespace Laminas\Diactoros;

use Psr\Http\Message\RequestFactoryInterface;
use Psr\Http\Message\RequestInterface;

class RequestFactory implements RequestFactoryInterface
{
    /**
     * {@inheritDoc}
     */
    public function createRequest(string $method, $uri) : RequestInterface
    {
        return new Request($uri, $method);
    }
}
laminas-diactoros/src/RequestTrait.php000064400000023724147361032560014130 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-diactoros for the canonical source repository
 * @copyright https://github.com/laminas/laminas-diactoros/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-diactoros/blob/master/LICENSE.md New BSD License
 */

declare(strict_types=1);

namespace Laminas\Diactoros;

use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\StreamInterface;
use Psr\Http\Message\UriInterface;

use function array_keys;
use function get_class;
use function gettype;
use function is_object;
use function is_string;
use function preg_match;
use function sprintf;
use function strtolower;

/**
 * Trait with common request behaviors.
 *
 * Server and client-side requests differ slightly in how the Host header is
 * handled; on client-side, it should be calculated on-the-fly from the
 * composed URI (if present), while on server-side, it will be calculated from
 * the environment. As such, this trait exists to provide the common code
 * between both client-side and server-side requests, and each can then
 * use the headers functionality required by their implementations.
 */
trait RequestTrait
{
    use MessageTrait;

    /**
     * @var string
     */
    private $method = 'GET';

    /**
     * The request-target, if it has been provided or calculated.
     *
     * @var null|string
     */
    private $requestTarget;

    /**
     * @var UriInterface
     */
    private $uri;

    /**
     * Initialize request state.
     *
     * Used by constructors.
     *
     * @param null|string|UriInterface $uri URI for the request, if any.
     * @param null|string $method HTTP method for the request, if any.
     * @param string|resource|StreamInterface $body Message body, if any.
     * @param array $headers Headers for the message, if any.
     * @throws Exception\InvalidArgumentException for any invalid value.
     */
    private function initialize(
        $uri = null,
        string $method = null,
        $body = 'php://memory',
        array $headers = []
    ) : void {
        if ($method !== null) {
            $this->setMethod($method);
        }

        $this->uri    = $this->createUri($uri);
        $this->stream = $this->getStream($body, 'wb+');

        $this->setHeaders($headers);

        // per PSR-7: attempt to set the Host header from a provided URI if no
        // Host header is provided
        if (! $this->hasHeader('Host') && $this->uri->getHost()) {
            $this->headerNames['host'] = 'Host';
            $this->headers['Host'] = [$this->getHostFromUri()];
        }
    }

    /**
     * Create and return a URI instance.
     *
     * If `$uri` is a already a `UriInterface` instance, returns it.
     *
     * If `$uri` is a string, passes it to the `Uri` constructor to return an
     * instance.
     *
     * If `$uri is null, creates and returns an empty `Uri` instance.
     *
     * Otherwise, it raises an exception.
     *
     * @param null|string|UriInterface $uri
     * @throws Exception\InvalidArgumentException
     */
    private function createUri($uri) : UriInterface
    {
        if ($uri instanceof UriInterface) {
            return $uri;
        }
        if (is_string($uri)) {
            return new Uri($uri);
        }
        if ($uri === null) {
            return new Uri();
        }
        throw new Exception\InvalidArgumentException(
            'Invalid URI provided; must be null, a string, or a Psr\Http\Message\UriInterface instance'
        );
    }

    /**
     * Retrieves the message's request target.
     *
     * Retrieves the message's request-target either as it will appear (for
     * clients), as it appeared at request (for servers), or as it was
     * specified for the instance (see withRequestTarget()).
     *
     * In most cases, this will be the origin-form of the composed URI,
     * unless a value was provided to the concrete implementation (see
     * withRequestTarget() below).
     *
     * If no URI is available, and no request-target has been specifically
     * provided, this method MUST return the string "/".
     */
    public function getRequestTarget() : string
    {
        if (null !== $this->requestTarget) {
            return $this->requestTarget;
        }

        $target = $this->uri->getPath();
        if ($this->uri->getQuery()) {
            $target .= '?' . $this->uri->getQuery();
        }

        if (empty($target)) {
            $target = '/';
        }

        return $target;
    }

    /**
     * Create a new instance with a specific request-target.
     *
     * If the request needs a non-origin-form request-target — e.g., for
     * specifying an absolute-form, authority-form, or asterisk-form —
     * this method may be used to create an instance with the specified
     * request-target, verbatim.
     *
     * This method MUST be implemented in such a way as to retain the
     * immutability of the message, and MUST return a new instance that has the
     * changed request target.
     *
     * @link http://tools.ietf.org/html/rfc7230#section-2.7 (for the various
     *     request-target forms allowed in request messages)
     * @param string $requestTarget
     * @throws Exception\InvalidArgumentException if the request target is invalid.
     */
    public function withRequestTarget($requestTarget) : RequestInterface
    {
        if (preg_match('#\s#', $requestTarget)) {
            throw new Exception\InvalidArgumentException(
                'Invalid request target provided; cannot contain whitespace'
            );
        }

        $new = clone $this;
        $new->requestTarget = $requestTarget;
        return $new;
    }

    /**
     * Retrieves the HTTP method of the request.
     *
     * @return string Returns the request method.
     */
    public function getMethod() : string
    {
        return $this->method;
    }

    /**
     * Return an instance with the provided HTTP method.
     *
     * While HTTP method names are typically all uppercase characters, HTTP
     * method names are case-sensitive and thus implementations SHOULD NOT
     * modify the given string.
     *
     * This method MUST be implemented in such a way as to retain the
     * immutability of the message, and MUST return an instance that has the
     * changed request method.
     *
     * @param string $method Case-insensitive method.
     * @throws Exception\InvalidArgumentException for invalid HTTP methods.
     */
    public function withMethod($method) : RequestInterface
    {
        $new = clone $this;
        $new->setMethod($method);
        return $new;
    }

    /**
     * Retrieves the URI instance.
     *
     * This method MUST return a UriInterface instance.
     *
     * @link http://tools.ietf.org/html/rfc3986#section-4.3
     * @return UriInterface Returns a UriInterface instance
     *     representing the URI of the request, if any.
     */
    public function getUri() : UriInterface
    {
        return $this->uri;
    }

    /**
     * Returns an instance with the provided URI.
     *
     * This method will update the Host header of the returned request by
     * default if the URI contains a host component. If the URI does not
     * contain a host component, any pre-existing Host header will be carried
     * over to the returned request.
     *
     * You can opt-in to preserving the original state of the Host header by
     * setting `$preserveHost` to `true`. When `$preserveHost` is set to
     * `true`, the returned request will not update the Host header of the
     * returned message -- even if the message contains no Host header. This
     * means that a call to `getHeader('Host')` on the original request MUST
     * equal the return value of a call to `getHeader('Host')` on the returned
     * request.
     *
     * This method MUST be implemented in such a way as to retain the
     * immutability of the message, and MUST return an instance that has the
     * new UriInterface instance.
     *
     * @link http://tools.ietf.org/html/rfc3986#section-4.3
     * @param UriInterface $uri New request URI to use.
     * @param bool $preserveHost Preserve the original state of the Host header.
     */
    public function withUri(UriInterface $uri, $preserveHost = false) : RequestInterface
    {
        $new = clone $this;
        $new->uri = $uri;

        if ($preserveHost && $this->hasHeader('Host')) {
            return $new;
        }

        if (! $uri->getHost()) {
            return $new;
        }

        $host = $uri->getHost();
        if ($uri->getPort()) {
            $host .= ':' . $uri->getPort();
        }

        $new->headerNames['host'] = 'Host';

        // Remove an existing host header if present, regardless of current
        // de-normalization of the header name.
        // @see https://github.com/zendframework/zend-diactoros/issues/91
        foreach (array_keys($new->headers) as $header) {
            if (strtolower($header) === 'host') {
                unset($new->headers[$header]);
            }
        }

        $new->headers['Host'] = [$host];

        return $new;
    }

    /**
     * Set and validate the HTTP method
     *
     * @param string $method
     * @throws Exception\InvalidArgumentException on invalid HTTP method.
     */
    private function setMethod($method) : void
    {
        if (! is_string($method)) {
            throw new Exception\InvalidArgumentException(sprintf(
                'Unsupported HTTP method; must be a string, received %s',
                is_object($method) ? get_class($method) : gettype($method)
            ));
        }

        if (! preg_match('/^[!#$%&\'*+.^_`\|~0-9a-z-]+$/i', $method)) {
            throw new Exception\InvalidArgumentException(sprintf(
                'Unsupported HTTP method "%s" provided',
                $method
            ));
        }
        $this->method = $method;
    }

    /**
     * Retrieve the host from the URI instance
     */
    private function getHostFromUri() : string
    {
        $host  = $this->uri->getHost();
        $host .= $this->uri->getPort() ? ':' . $this->uri->getPort() : '';
        return $host;
    }
}
laminas-diactoros/src/Module.php000064400000001011147361032560012702 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-diactoros for the canonical source repository
 * @copyright https://github.com/laminas/laminas-diactoros/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-diactoros/blob/master/LICENSE.md New BSD License
 */

declare(strict_types=1);

namespace Laminas\Diactoros;

class Module
{
    public function getConfig(): array
    {
        return [
            'service_manager' => (new ConfigProvider())->getDependencies(),
        ];
    }
}
laminas-diactoros/src/UploadedFile.php000064400000016763147361032560014036 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-diactoros for the canonical source repository
 * @copyright https://github.com/laminas/laminas-diactoros/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-diactoros/blob/master/LICENSE.md New BSD License
 */

declare(strict_types=1);

namespace Laminas\Diactoros;

use Psr\Http\Message\StreamInterface;
use Psr\Http\Message\UploadedFileInterface;

use function dirname;
use function fclose;
use function fopen;
use function fwrite;
use function is_dir;
use function is_int;
use function is_resource;
use function is_string;
use function is_writable;
use function move_uploaded_file;
use function sprintf;
use function strpos;

use const PHP_SAPI;
use const UPLOAD_ERR_CANT_WRITE;
use const UPLOAD_ERR_EXTENSION;
use const UPLOAD_ERR_FORM_SIZE;
use const UPLOAD_ERR_INI_SIZE;
use const UPLOAD_ERR_NO_FILE;
use const UPLOAD_ERR_NO_TMP_DIR;
use const UPLOAD_ERR_OK;
use const UPLOAD_ERR_PARTIAL;

class UploadedFile implements UploadedFileInterface
{
    const ERROR_MESSAGES = [
        UPLOAD_ERR_OK         => 'There is no error, the file uploaded with success',
        UPLOAD_ERR_INI_SIZE   => 'The uploaded file exceeds the upload_max_filesize directive in php.ini',
        UPLOAD_ERR_FORM_SIZE  => 'The uploaded file exceeds the MAX_FILE_SIZE directive that was '
            . 'specified in the HTML form',
        UPLOAD_ERR_PARTIAL    => 'The uploaded file was only partially uploaded',
        UPLOAD_ERR_NO_FILE    => 'No file was uploaded',
        UPLOAD_ERR_NO_TMP_DIR => 'Missing a temporary folder',
        UPLOAD_ERR_CANT_WRITE => 'Failed to write file to disk',
        UPLOAD_ERR_EXTENSION  => 'A PHP extension stopped the file upload.',
    ];

    /**
     * @var string|null
     */
    private $clientFilename;

    /**
     * @var string|null
     */
    private $clientMediaType;

    /**
     * @var int
     */
    private $error;

    /**
     * @var null|string
     */
    private $file;

    /**
     * @var bool
     */
    private $moved = false;

    /**
     * @var int
     */
    private $size;

    /**
     * @var null|StreamInterface
     */
    private $stream;

    /**
     * @param string|resource $streamOrFile
     * @param int $size
     * @param int $errorStatus
     * @param string|null $clientFilename
     * @param string|null $clientMediaType
     * @throws Exception\InvalidArgumentException
     */
    public function __construct(
        $streamOrFile,
        int $size,
        int $errorStatus,
        string $clientFilename = null,
        string $clientMediaType = null
    ) {
        if ($errorStatus === UPLOAD_ERR_OK) {
            if (is_string($streamOrFile)) {
                $this->file = $streamOrFile;
            }
            if (is_resource($streamOrFile)) {
                $this->stream = new Stream($streamOrFile);
            }

            if (! $this->file && ! $this->stream) {
                if (! $streamOrFile instanceof StreamInterface) {
                    throw new Exception\InvalidArgumentException('Invalid stream or file provided for UploadedFile');
                }
                $this->stream = $streamOrFile;
            }
        }

        $this->size = $size;

        if (0 > $errorStatus || 8 < $errorStatus) {
            throw new Exception\InvalidArgumentException(
                'Invalid error status for UploadedFile; must be an UPLOAD_ERR_* constant'
            );
        }
        $this->error = $errorStatus;

        $this->clientFilename = $clientFilename;
        $this->clientMediaType = $clientMediaType;
    }

    /**
     * {@inheritdoc}
     * @throws Exception\UploadedFileAlreadyMovedException if the upload was
     *     not successful.
     */
    public function getStream() : StreamInterface
    {
        if ($this->error !== UPLOAD_ERR_OK) {
            throw Exception\UploadedFileErrorException::dueToStreamUploadError(
                self::ERROR_MESSAGES[$this->error]
            );
        }

        if ($this->moved) {
            throw new Exception\UploadedFileAlreadyMovedException();
        }

        if ($this->stream instanceof StreamInterface) {
            return $this->stream;
        }

        $this->stream = new Stream($this->file);
        return $this->stream;
    }

    /**
     * {@inheritdoc}
     *
     * @see http://php.net/is_uploaded_file
     * @see http://php.net/move_uploaded_file
     * @param string $targetPath Path to which to move the uploaded file.
     * @throws Exception\UploadedFileErrorException if the upload was not successful.
     * @throws Exception\InvalidArgumentException if the $path specified is invalid.
     * @throws Exception\UploadedFileErrorException on any error during the
     *     move operation, or on the second or subsequent call to the method.
     */
    public function moveTo($targetPath) : void
    {
        if ($this->moved) {
            throw new Exception\UploadedFileAlreadyMovedException('Cannot move file; already moved!');
        }

        if ($this->error !== UPLOAD_ERR_OK) {
            throw Exception\UploadedFileErrorException::dueToStreamUploadError(
                self::ERROR_MESSAGES[$this->error]
            );
        }

        if (! is_string($targetPath) || empty($targetPath)) {
            throw new Exception\InvalidArgumentException(
                'Invalid path provided for move operation; must be a non-empty string'
            );
        }

        $targetDirectory = dirname($targetPath);
        if (! is_dir($targetDirectory) || ! is_writable($targetDirectory)) {
            throw Exception\UploadedFileErrorException::dueToUnwritableTarget($targetDirectory);
        }

        $sapi = PHP_SAPI;
        switch (true) {
            case (empty($sapi) || 0 === strpos($sapi, 'cli') || 0 === strpos($sapi, 'phpdbg') || ! $this->file):
                // Non-SAPI environment, or no filename present
                $this->writeFile($targetPath);
                break;
            default:
                // SAPI environment, with file present
                if (false === move_uploaded_file($this->file, $targetPath)) {
                    throw Exception\UploadedFileErrorException::forUnmovableFile();
                }
                break;
        }

        $this->moved = true;
    }

    /**
     * {@inheritdoc}
     *
     * @return int|null The file size in bytes or null if unknown.
     */
    public function getSize() : ?int
    {
        return $this->size;
    }

    /**
     * {@inheritdoc}
     *
     * @see http://php.net/manual/en/features.file-upload.errors.php
     * @return int One of PHP's UPLOAD_ERR_XXX constants.
     */
    public function getError() : int
    {
        return $this->error;
    }

    /**
     * {@inheritdoc}
     *
     * @return string|null The filename sent by the client or null if none
     *     was provided.
     */
    public function getClientFilename() : ?string
    {
        return $this->clientFilename;
    }

    /**
     * {@inheritdoc}
     */
    public function getClientMediaType() : ?string
    {
        return $this->clientMediaType;
    }

    /**
     * Write internal stream to given path
     *
     * @param string $path
     */
    private function writeFile(string $path) : void
    {
        $handle = fopen($path, 'wb+');
        if (false === $handle) {
            throw Exception\UploadedFileErrorException::dueToUnwritablePath();
        }

        $stream = $this->getStream();
        $stream->rewind();
        while (! $stream->eof()) {
            fwrite($handle, $stream->read(4096));
        }

        fclose($handle);
    }
}
laminas-diactoros/src/ConfigProvider.php000064400000003051147361032560014403 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-diactoros for the canonical source repository
 * @copyright https://github.com/laminas/laminas-diactoros/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-diactoros/blob/master/LICENSE.md New BSD License
 */

declare(strict_types=1);

namespace Laminas\Diactoros;

use Psr\Http\Message\ServerRequestFactoryInterface;
use Psr\Http\Message\RequestFactoryInterface;
use Psr\Http\Message\ResponseFactoryInterface;
use Psr\Http\Message\StreamFactoryInterface;
use Psr\Http\Message\UploadedFileFactoryInterface;
use Psr\Http\Message\UriFactoryInterface;

class ConfigProvider
{
    /**
     * Retrieve configuration for laminas-diactoros.
     *
     * @return array
     */
    public function __invoke() : array
    {
        return [
            'dependencies' => $this->getDependencies(),
        ];
    }

    /**
     * Returns the container dependencies.
     * Maps factory interfaces to factories.
     */
    public function getDependencies() : array
    {
        return [
            'invokables' => [
                RequestFactoryInterface::class => RequestFactory::class,
                ResponseFactoryInterface::class => ResponseFactory::class,
                StreamFactoryInterface::class => StreamFactory::class,
                ServerRequestFactoryInterface::class => ServerRequestFactory::class,
                UploadedFileFactoryInterface::class => UploadedFileFactory::class,
                UriFactoryInterface::class => UriFactory::class
            ],
        ];
    }
}
laminas-diactoros/src/Response.php000064400000013612147361032560013265 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-diactoros for the canonical source repository
 * @copyright https://github.com/laminas/laminas-diactoros/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-diactoros/blob/master/LICENSE.md New BSD License
 */

declare(strict_types=1);

namespace Laminas\Diactoros;

use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\StreamInterface;

use function gettype;
use function is_float;
use function is_numeric;
use function is_scalar;
use function sprintf;

/**
 * HTTP response encapsulation.
 *
 * Responses are considered immutable; all methods that might change state are
 * implemented such that they retain the internal state of the current
 * message and return a new instance that contains the changed state.
 */
class Response implements ResponseInterface
{
    use MessageTrait;

    const MIN_STATUS_CODE_VALUE = 100;
    const MAX_STATUS_CODE_VALUE = 599;

    /**
     * Map of standard HTTP status code/reason phrases
     *
     * @var array
     */
    private $phrases = [
        // INFORMATIONAL CODES
        100 => 'Continue',
        101 => 'Switching Protocols',
        102 => 'Processing',
        103 => 'Early Hints',
        // SUCCESS CODES
        200 => 'OK',
        201 => 'Created',
        202 => 'Accepted',
        203 => 'Non-Authoritative Information',
        204 => 'No Content',
        205 => 'Reset Content',
        206 => 'Partial Content',
        207 => 'Multi-Status',
        208 => 'Already Reported',
        226 => 'IM Used',
        // REDIRECTION CODES
        300 => 'Multiple Choices',
        301 => 'Moved Permanently',
        302 => 'Found',
        303 => 'See Other',
        304 => 'Not Modified',
        305 => 'Use Proxy',
        306 => 'Switch Proxy', // Deprecated to 306 => '(Unused)'
        307 => 'Temporary Redirect',
        308 => 'Permanent Redirect',
        // CLIENT ERROR
        400 => 'Bad Request',
        401 => 'Unauthorized',
        402 => 'Payment Required',
        403 => 'Forbidden',
        404 => 'Not Found',
        405 => 'Method Not Allowed',
        406 => 'Not Acceptable',
        407 => 'Proxy Authentication Required',
        408 => 'Request Timeout',
        409 => 'Conflict',
        410 => 'Gone',
        411 => 'Length Required',
        412 => 'Precondition Failed',
        413 => 'Payload Too Large',
        414 => 'URI Too Long',
        415 => 'Unsupported Media Type',
        416 => 'Range Not Satisfiable',
        417 => 'Expectation Failed',
        418 => 'I\'m a teapot',
        421 => 'Misdirected Request',
        422 => 'Unprocessable Entity',
        423 => 'Locked',
        424 => 'Failed Dependency',
        425 => 'Too Early',
        426 => 'Upgrade Required',
        428 => 'Precondition Required',
        429 => 'Too Many Requests',
        431 => 'Request Header Fields Too Large',
        444 => 'Connection Closed Without Response',
        451 => 'Unavailable For Legal Reasons',
        // SERVER ERROR
        499 => 'Client Closed Request',
        500 => 'Internal Server Error',
        501 => 'Not Implemented',
        502 => 'Bad Gateway',
        503 => 'Service Unavailable',
        504 => 'Gateway Timeout',
        505 => 'HTTP Version Not Supported',
        506 => 'Variant Also Negotiates',
        507 => 'Insufficient Storage',
        508 => 'Loop Detected',
        510 => 'Not Extended',
        511 => 'Network Authentication Required',
        599 => 'Network Connect Timeout Error',
    ];

    /**
     * @var string
     */
    private $reasonPhrase;

    /**
     * @var int
     */
    private $statusCode;

    /**
     * @param string|resource|StreamInterface $body Stream identifier and/or actual stream resource
     * @param int $status Status code for the response, if any.
     * @param array $headers Headers for the response, if any.
     * @throws Exception\InvalidArgumentException on any invalid element.
     */
    public function __construct($body = 'php://memory', int $status = 200, array $headers = [])
    {
        $this->setStatusCode($status);
        $this->stream = $this->getStream($body, 'wb+');
        $this->setHeaders($headers);
    }

    /**
     * {@inheritdoc}
     */
    public function getStatusCode() : int
    {
        return $this->statusCode;
    }

    /**
     * {@inheritdoc}
     */
    public function getReasonPhrase() : string
    {
        return $this->reasonPhrase;
    }

    /**
     * {@inheritdoc}
     */
    public function withStatus($code, $reasonPhrase = '') : Response
    {
        $new = clone $this;
        $new->setStatusCode($code, $reasonPhrase);
        return $new;
    }

    /**
     * Set a valid status code.
     *
     * @param int $code
     * @param string $reasonPhrase
     * @throws Exception\InvalidArgumentException on an invalid status code.
     */
    private function setStatusCode($code, $reasonPhrase = '') : void
    {
        if (! is_numeric($code)
            || is_float($code)
            || $code < static::MIN_STATUS_CODE_VALUE
            || $code > static::MAX_STATUS_CODE_VALUE
        ) {
            throw new Exception\InvalidArgumentException(sprintf(
                'Invalid status code "%s"; must be an integer between %d and %d, inclusive',
                is_scalar($code) ? $code : gettype($code),
                static::MIN_STATUS_CODE_VALUE,
                static::MAX_STATUS_CODE_VALUE
            ));
        }

        if (! is_string($reasonPhrase)) {
            throw new Exception\InvalidArgumentException(sprintf(
                'Unsupported response reason phrase; must be a string, received %s',
                is_object($reasonPhrase) ? get_class($reasonPhrase) : gettype($reasonPhrase)
            ));
        }

        if ($reasonPhrase === '' && isset($this->phrases[$code])) {
            $reasonPhrase = $this->phrases[$code];
        }

        $this->reasonPhrase = $reasonPhrase;
        $this->statusCode = (int) $code;
    }
}
laminas-diactoros/src/Stream.php000064400000020102147361032560012712 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-diactoros for the canonical source repository
 * @copyright https://github.com/laminas/laminas-diactoros/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-diactoros/blob/master/LICENSE.md New BSD License
 */

declare(strict_types=1);

namespace Laminas\Diactoros;

use Psr\Http\Message\StreamInterface;
use RuntimeException;

use function array_key_exists;
use function fclose;
use function feof;
use function fopen;
use function fread;
use function fseek;
use function fstat;
use function ftell;
use function fwrite;
use function get_resource_type;
use function is_int;
use function is_resource;
use function is_string;
use function restore_error_handler;
use function set_error_handler;
use function stream_get_contents;
use function stream_get_meta_data;
use function strstr;

use const E_WARNING;
use const SEEK_SET;

/**
 * Implementation of PSR HTTP streams
 */
class Stream implements StreamInterface
{
    /**
     * @var resource|null
     */
    protected $resource;

    /**
     * @var string|resource
     */
    protected $stream;

    /**
     * @param string|resource $stream
     * @param string $mode Mode with which to open stream
     * @throws Exception\InvalidArgumentException
     */
    public function __construct($stream, string $mode = 'r')
    {
        $this->setStream($stream, $mode);
    }

    /**
     * {@inheritdoc}
     */
    public function __toString() : string
    {
        if (! $this->isReadable()) {
            return '';
        }

        try {
            if ($this->isSeekable()) {
                $this->rewind();
            }

            return $this->getContents();
        } catch (RuntimeException $e) {
            return '';
        }
    }

    /**
     * {@inheritdoc}
     */
    public function close() : void
    {
        if (! $this->resource) {
            return;
        }

        $resource = $this->detach();
        fclose($resource);
    }

    /**
     * {@inheritdoc}
     */
    public function detach()
    {
        $resource = $this->resource;
        $this->resource = null;
        return $resource;
    }

    /**
     * Attach a new stream/resource to the instance.
     *
     * @param string|resource $resource
     * @param string $mode
     * @throws Exception\InvalidArgumentException for stream identifier that cannot be
     *     cast to a resource
     * @throws Exception\InvalidArgumentException for non-resource stream
     */
    public function attach($resource, string $mode = 'r') : void
    {
        $this->setStream($resource, $mode);
    }

    /**
     * {@inheritdoc}
     */
    public function getSize() : ?int
    {
        if (null === $this->resource) {
            return null;
        }

        $stats = fstat($this->resource);
        if ($stats !== false) {
            return $stats['size'];
        }

        return null;
    }

    /**
     * {@inheritdoc}
     */
    public function tell() : int
    {
        if (! $this->resource) {
            throw Exception\UntellableStreamException::dueToMissingResource();
        }

        $result = ftell($this->resource);
        if (! is_int($result)) {
            throw Exception\UntellableStreamException::dueToPhpError();
        }

        return $result;
    }

    /**
     * {@inheritdoc}
     */
    public function eof() : bool
    {
        if (! $this->resource) {
            return true;
        }

        return feof($this->resource);
    }

    /**
     * {@inheritdoc}
     */
    public function isSeekable() : bool
    {
        if (! $this->resource) {
            return false;
        }

        $meta = stream_get_meta_data($this->resource);
        return $meta['seekable'];
    }

    /**
     * {@inheritdoc}
     */
    public function seek($offset, $whence = SEEK_SET) : void
    {
        if (! $this->resource) {
            throw Exception\UnseekableStreamException::dueToMissingResource();
        }

        if (! $this->isSeekable()) {
            throw Exception\UnseekableStreamException::dueToConfiguration();
        }

        $result = fseek($this->resource, $offset, $whence);

        if (0 !== $result) {
            throw Exception\UnseekableStreamException::dueToPhpError();
        }
    }

    /**
     * {@inheritdoc}
     */
    public function rewind() : void
    {
        $this->seek(0);
    }

    /**
     * {@inheritdoc}
     */
    public function isWritable() : bool
    {
        if (! $this->resource) {
            return false;
        }

        $meta = stream_get_meta_data($this->resource);
        $mode = $meta['mode'];

        return (
            strstr($mode, 'x')
            || strstr($mode, 'w')
            || strstr($mode, 'c')
            || strstr($mode, 'a')
            || strstr($mode, '+')
        );
    }

    /**
     * {@inheritdoc}
     */
    public function write($string) : int
    {
        if (! $this->resource) {
            throw Exception\UnwritableStreamException::dueToMissingResource();
        }

        if (! $this->isWritable()) {
            throw Exception\UnwritableStreamException::dueToConfiguration();
        }

        $result = fwrite($this->resource, $string);

        if (false === $result) {
            throw Exception\UnwritableStreamException::dueToPhpError();
        }

        return $result;
    }

    /**
     * {@inheritdoc}
     */
    public function isReadable() : bool
    {
        if (! $this->resource) {
            return false;
        }

        $meta = stream_get_meta_data($this->resource);
        $mode = $meta['mode'];

        return (strstr($mode, 'r') || strstr($mode, '+'));
    }

    /**
     * {@inheritdoc}
     */
    public function read($length) : string
    {
        if (! $this->resource) {
            throw Exception\UnreadableStreamException::dueToMissingResource();
        }

        if (! $this->isReadable()) {
            throw Exception\UnreadableStreamException::dueToConfiguration();
        }

        $result = fread($this->resource, $length);

        if (false === $result) {
            throw Exception\UnreadableStreamException::dueToPhpError();
        }

        return $result;
    }

    /**
     * {@inheritdoc}
     */
    public function getContents() : string
    {
        if (! $this->isReadable()) {
            throw Exception\UnreadableStreamException::dueToConfiguration();
        }

        $result = stream_get_contents($this->resource);
        if (false === $result) {
            throw Exception\UnreadableStreamException::dueToPhpError();
        }
        return $result;
    }

    /**
     * {@inheritdoc}
     */
    public function getMetadata($key = null)
    {
        if (null === $key) {
            return stream_get_meta_data($this->resource);
        }

        $metadata = stream_get_meta_data($this->resource);
        if (! array_key_exists($key, $metadata)) {
            return null;
        }

        return $metadata[$key];
    }

    /**
     * Set the internal stream resource.
     *
     * @param string|resource $stream String stream target or stream resource.
     * @param string $mode Resource mode for stream target.
     * @throws Exception\InvalidArgumentException for invalid streams or resources.
     */
    private function setStream($stream, string $mode = 'r') : void
    {
        $error    = null;
        $resource = $stream;

        if (is_string($stream)) {
            set_error_handler(function ($e) use (&$error) {
                if ($e !== E_WARNING) {
                    return;
                }

                $error = $e;
            });
            $resource = fopen($stream, $mode);
            restore_error_handler();
        }

        if ($error) {
            throw new Exception\InvalidArgumentException('Invalid stream reference provided');
        }

        if (! is_resource($resource) || 'stream' !== get_resource_type($resource)) {
            throw new Exception\InvalidArgumentException(
                'Invalid stream provided; must be a string stream identifier or stream resource'
            );
        }

        if ($stream !== $resource) {
            $this->stream = $stream;
        }

        $this->resource = $resource;
    }
}
laminas-diactoros/src/UriFactory.php000064400000001155147361032560013555 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-diactoros for the canonical source repository
 * @copyright https://github.com/laminas/laminas-diactoros/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-diactoros/blob/master/LICENSE.md New BSD License
 */

declare(strict_types=1);

namespace Laminas\Diactoros;

use Psr\Http\Message\UriFactoryInterface;
use Psr\Http\Message\UriInterface;

class UriFactory implements UriFactoryInterface
{
    /**
     * {@inheritDoc}
     */
    public function createUri(string $uri = '') : UriInterface
    {
        return new Uri($uri);
    }
}
laminas-diactoros/src/RelativeStream.php000064400000007406147361032560014422 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-diactoros for the canonical source repository
 * @copyright https://github.com/laminas/laminas-diactoros/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-diactoros/blob/master/LICENSE.md New BSD License
 */

declare(strict_types=1);

namespace Laminas\Diactoros;

use Psr\Http\Message\StreamInterface;

use const SEEK_SET;

/**
 * Class RelativeStream
 *
 * Wrapper for default Stream class, representing subpart (starting from given offset) of initial stream.
 * It can be used to avoid copying full stream, conserving memory.
 * @example see Laminas\Diactoros\AbstractSerializer::splitStream()
 */
final class RelativeStream implements StreamInterface
{
    /**
     * @var StreamInterface
     */
    private $decoratedStream;

    /**
     * @var int
     */
    private $offset;

    /**
     * Class constructor
     *
     * @param StreamInterface $decoratedStream
     * @param int $offset
     */
    public function __construct(StreamInterface $decoratedStream, ?int $offset)
    {
        $this->decoratedStream = $decoratedStream;
        $this->offset = (int) $offset;
    }

    /**
     * {@inheritdoc}
     */
    public function __toString() : string
    {
        if ($this->isSeekable()) {
            $this->seek(0);
        }
        return $this->getContents();
    }

    /**
     * {@inheritdoc}
     */
    public function close() : void
    {
        $this->decoratedStream->close();
    }

    /**
     * {@inheritdoc}
     */
    public function detach()
    {
        return $this->decoratedStream->detach();
    }

    /**
     * {@inheritdoc}
     */
    public function getSize() : int
    {
        return $this->decoratedStream->getSize() - $this->offset;
    }

    /**
     * {@inheritdoc}
     */
    public function tell() : int
    {
        return $this->decoratedStream->tell() - $this->offset;
    }

    /**
     * {@inheritdoc}
     */
    public function eof() : bool
    {
        return $this->decoratedStream->eof();
    }

    /**
     * {@inheritdoc}
     */
    public function isSeekable() : bool
    {
        return $this->decoratedStream->isSeekable();
    }

    /**
     * {@inheritdoc}
     */
    public function seek($offset, $whence = SEEK_SET) : void
    {
        if ($whence == SEEK_SET) {
            $this->decoratedStream->seek($offset + $this->offset, $whence);
            return;
        }
        $this->decoratedStream->seek($offset, $whence);
    }

    /**
     * {@inheritdoc}
     */
    public function rewind() : void
    {
        $this->seek(0);
    }

    /**
     * {@inheritdoc}
     */
    public function isWritable() : bool
    {
        return $this->decoratedStream->isWritable();
    }

    /**
     * {@inheritdoc}
     */
    public function write($string) : int
    {
        if ($this->tell() < 0) {
            throw new Exception\InvalidStreamPointerPositionException();
        }
        return $this->decoratedStream->write($string);
    }

    /**
     * {@inheritdoc}
     */
    public function isReadable() : bool
    {
        return $this->decoratedStream->isReadable();
    }

    /**
     * {@inheritdoc}
     */
    public function read($length) : string
    {
        if ($this->tell() < 0) {
            throw new Exception\InvalidStreamPointerPositionException();
        }
        return $this->decoratedStream->read($length);
    }

    /**
     * {@inheritdoc}
     */
    public function getContents() : string
    {
        if ($this->tell() < 0) {
            throw new Exception\InvalidStreamPointerPositionException();
        }
        return $this->decoratedStream->getContents();
    }

    /**
     * {@inheritdoc}
     */
    public function getMetadata($key = null)
    {
        return $this->decoratedStream->getMetadata($key);
    }
}
laminas-diactoros/src/Request.php000064400000004107147361032560013116 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-diactoros for the canonical source repository
 * @copyright https://github.com/laminas/laminas-diactoros/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-diactoros/blob/master/LICENSE.md New BSD License
 */

declare(strict_types=1);

namespace Laminas\Diactoros;

use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\StreamInterface;
use Psr\Http\Message\UriInterface;

use function strtolower;

/**
 * HTTP Request encapsulation
 *
 * Requests are considered immutable; all methods that might change state are
 * implemented such that they retain the internal state of the current
 * message and return a new instance that contains the changed state.
 */
class Request implements RequestInterface
{
    use RequestTrait;

    /**
     * @param null|string|UriInterface $uri URI for the request, if any.
     * @param null|string $method HTTP method for the request, if any.
     * @param string|resource|StreamInterface $body Message body, if any.
     * @param array $headers Headers for the message, if any.
     * @throws Exception\InvalidArgumentException for any invalid value.
     */
    public function __construct($uri = null, string $method = null, $body = 'php://temp', array $headers = [])
    {
        $this->initialize($uri, $method, $body, $headers);
    }

    /**
     * {@inheritdoc}
     */
    public function getHeaders() : array
    {
        $headers = $this->headers;
        if (! $this->hasHeader('host')
            && $this->uri->getHost()
        ) {
            $headers['Host'] = [$this->getHostFromUri()];
        }

        return $headers;
    }

    /**
     * {@inheritdoc}
     */
    public function getHeader($header) : array
    {
        if (! $this->hasHeader($header)) {
            if (strtolower($header) === 'host'
                && $this->uri->getHost()
            ) {
                return [$this->getHostFromUri()];
            }

            return [];
        }

        $header = $this->headerNames[strtolower($header)];

        return $this->headers[$header];
    }
}
laminas-diactoros/src/MessageTrait.php000064400000031200147361032560014050 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-diactoros for the canonical source repository
 * @copyright https://github.com/laminas/laminas-diactoros/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-diactoros/blob/master/LICENSE.md New BSD License
 */

declare(strict_types=1);

namespace Laminas\Diactoros;

use Psr\Http\Message\MessageInterface;
use Psr\Http\Message\StreamInterface;

use function array_map;
use function array_merge;
use function get_class;
use function gettype;
use function implode;
use function is_array;
use function is_object;
use function is_resource;
use function is_string;
use function preg_match;
use function sprintf;
use function strtolower;

/**
 * Trait implementing the various methods defined in MessageInterface.
 *
 * @see https://github.com/php-fig/http-message/tree/master/src/MessageInterface.php
 */
trait MessageTrait
{
    /**
     * List of all registered headers, as key => array of values.
     *
     * @var array
     */
    protected $headers = [];

    /**
     * Map of normalized header name to original name used to register header.
     *
     * @var array
     */
    protected $headerNames = [];

    /**
     * @var string
     */
    private $protocol = '1.1';

    /**
     * @var StreamInterface
     */
    private $stream;

    /**
     * Retrieves the HTTP protocol version as a string.
     *
     * The string MUST contain only the HTTP version number (e.g., "1.1", "1.0").
     *
     * @return string HTTP protocol version.
     */
    public function getProtocolVersion() : string
    {
        return $this->protocol;
    }

    /**
     * Return an instance with the specified HTTP protocol version.
     *
     * The version string MUST contain only the HTTP version number (e.g.,
     * "1.1", "1.0").
     *
     * This method MUST be implemented in such a way as to retain the
     * immutability of the message, and MUST return an instance that has the
     * new protocol version.
     *
     * @param string $version HTTP protocol version
     * @return static
     */
    public function withProtocolVersion($version) : MessageInterface
    {
        $this->validateProtocolVersion($version);
        $new = clone $this;
        $new->protocol = $version;
        return $new;
    }

    /**
     * Retrieves all message headers.
     *
     * The keys represent the header name as it will be sent over the wire, and
     * each value is an array of strings associated with the header.
     *
     *     // Represent the headers as a string
     *     foreach ($message->getHeaders() as $name => $values) {
     *         echo $name . ": " . implode(", ", $values);
     *     }
     *
     *     // Emit headers iteratively:
     *     foreach ($message->getHeaders() as $name => $values) {
     *         foreach ($values as $value) {
     *             header(sprintf('%s: %s', $name, $value), false);
     *         }
     *     }
     *
     * @return array Returns an associative array of the message's headers. Each
     *     key MUST be a header name, and each value MUST be an array of strings.
     */
    public function getHeaders() : array
    {
        return $this->headers;
    }

    /**
     * Checks if a header exists by the given case-insensitive name.
     *
     * @param string $header Case-insensitive header name.
     * @return bool Returns true if any header names match the given header
     *     name using a case-insensitive string comparison. Returns false if
     *     no matching header name is found in the message.
     */
    public function hasHeader($header) : bool
    {
        return isset($this->headerNames[strtolower($header)]);
    }

    /**
     * Retrieves a message header value by the given case-insensitive name.
     *
     * This method returns an array of all the header values of the given
     * case-insensitive header name.
     *
     * If the header does not appear in the message, this method MUST return an
     * empty array.
     *
     * @param string $header Case-insensitive header field name.
     * @return string[] An array of string values as provided for the given
     *    header. If the header does not appear in the message, this method MUST
     *    return an empty array.
     */
    public function getHeader($header) : array
    {
        if (! $this->hasHeader($header)) {
            return [];
        }

        $header = $this->headerNames[strtolower($header)];

        return $this->headers[$header];
    }

    /**
     * Retrieves a comma-separated string of the values for a single header.
     *
     * This method returns all of the header values of the given
     * case-insensitive header name as a string concatenated together using
     * a comma.
     *
     * NOTE: Not all header values may be appropriately represented using
     * comma concatenation. For such headers, use getHeader() instead
     * and supply your own delimiter when concatenating.
     *
     * If the header does not appear in the message, this method MUST return
     * an empty string.
     *
     * @param string $name Case-insensitive header field name.
     * @return string A string of values as provided for the given header
     *    concatenated together using a comma. If the header does not appear in
     *    the message, this method MUST return an empty string.
     */
    public function getHeaderLine($name) : string
    {
        $value = $this->getHeader($name);
        if (empty($value)) {
            return '';
        }

        return implode(',', $value);
    }

    /**
     * Return an instance with the provided header, replacing any existing
     * values of any headers with the same case-insensitive name.
     *
     * While header names are case-insensitive, the casing of the header will
     * be preserved by this function, and returned from getHeaders().
     *
     * This method MUST be implemented in such a way as to retain the
     * immutability of the message, and MUST return an instance that has the
     * new and/or updated header and value.
     *
     * @param string $header Case-insensitive header field name.
     * @param string|string[] $value Header value(s).
     * @return static
     * @throws Exception\InvalidArgumentException for invalid header names or values.
     */
    public function withHeader($header, $value) : MessageInterface
    {
        $this->assertHeader($header);

        $normalized = strtolower($header);

        $new = clone $this;
        if ($new->hasHeader($header)) {
            unset($new->headers[$new->headerNames[$normalized]]);
        }

        $value = $this->filterHeaderValue($value);

        $new->headerNames[$normalized] = $header;
        $new->headers[$header]         = $value;

        return $new;
    }

    /**
     * Return an instance with the specified header appended with the
     * given value.
     *
     * Existing values for the specified header will be maintained. The new
     * value(s) will be appended to the existing list. If the header did not
     * exist previously, it will be added.
     *
     * This method MUST be implemented in such a way as to retain the
     * immutability of the message, and MUST return an instance that has the
     * new header and/or value.
     *
     * @param string $header Case-insensitive header field name to add.
     * @param string|string[] $value Header value(s).
     * @return static
     * @throws Exception\InvalidArgumentException for invalid header names or values.
     */
    public function withAddedHeader($header, $value) : MessageInterface
    {
        $this->assertHeader($header);

        if (! $this->hasHeader($header)) {
            return $this->withHeader($header, $value);
        }

        $header = $this->headerNames[strtolower($header)];

        $new = clone $this;
        $value = $this->filterHeaderValue($value);
        $new->headers[$header] = array_merge($this->headers[$header], $value);
        return $new;
    }

    /**
     * Return an instance without the specified header.
     *
     * Header resolution MUST be done without case-sensitivity.
     *
     * This method MUST be implemented in such a way as to retain the
     * immutability of the message, and MUST return an instance that removes
     * the named header.
     *
     * @param string $header Case-insensitive header field name to remove.
     * @return static
     */
    public function withoutHeader($header) : MessageInterface
    {
        if (! $this->hasHeader($header)) {
            return clone $this;
        }

        $normalized = strtolower($header);
        $original   = $this->headerNames[$normalized];

        $new = clone $this;
        unset($new->headers[$original], $new->headerNames[$normalized]);
        return $new;
    }

    /**
     * Gets the body of the message.
     *
     * @return StreamInterface Returns the body as a stream.
     */
    public function getBody() : StreamInterface
    {
        return $this->stream;
    }

    /**
     * Return an instance with the specified message body.
     *
     * The body MUST be a StreamInterface object.
     *
     * This method MUST be implemented in such a way as to retain the
     * immutability of the message, and MUST return a new instance that has the
     * new body stream.
     *
     * @param StreamInterface $body Body.
     * @return static
     * @throws Exception\InvalidArgumentException When the body is not valid.
     */
    public function withBody(StreamInterface $body) : MessageInterface
    {
        $new = clone $this;
        $new->stream = $body;
        return $new;
    }

    private function getStream($stream, string $modeIfNotInstance) : StreamInterface
    {
        if ($stream instanceof StreamInterface) {
            return $stream;
        }

        if (! is_string($stream) && ! is_resource($stream)) {
            throw new Exception\InvalidArgumentException(
                'Stream must be a string stream resource identifier, '
                . 'an actual stream resource, '
                . 'or a Psr\Http\Message\StreamInterface implementation'
            );
        }

        return new Stream($stream, $modeIfNotInstance);
    }

    /**
     * Filter a set of headers to ensure they are in the correct internal format.
     *
     * Used by message constructors to allow setting all initial headers at once.
     *
     * @param array $originalHeaders Headers to filter.
     */
    private function setHeaders(array $originalHeaders) : void
    {
        $headerNames = $headers = [];

        foreach ($originalHeaders as $header => $value) {
            $value = $this->filterHeaderValue($value);

            $this->assertHeader($header);

            $headerNames[strtolower($header)] = $header;
            $headers[$header] = $value;
        }

        $this->headerNames = $headerNames;
        $this->headers = $headers;
    }

    /**
     * Validate the HTTP protocol version
     *
     * @param string $version
     * @throws Exception\InvalidArgumentException on invalid HTTP protocol version
     */
    private function validateProtocolVersion($version) : void
    {
        if (empty($version)) {
            throw new Exception\InvalidArgumentException(
                'HTTP protocol version can not be empty'
            );
        }
        if (! is_string($version)) {
            throw new Exception\InvalidArgumentException(sprintf(
                'Unsupported HTTP protocol version; must be a string, received %s',
                (is_object($version) ? get_class($version) : gettype($version))
            ));
        }

        // HTTP/1 uses a "<major>.<minor>" numbering scheme to indicate
        // versions of the protocol, while HTTP/2 does not.
        if (! preg_match('#^(1\.[01]|2)$#', $version)) {
            throw new Exception\InvalidArgumentException(sprintf(
                'Unsupported HTTP protocol version "%s" provided',
                $version
            ));
        }
    }

    /**
     * @param mixed $values
     * @return string[]
     */
    private function filterHeaderValue($values) : array
    {
        if (! is_array($values)) {
            $values = [$values];
        }

        if ([] === $values) {
            throw new Exception\InvalidArgumentException(
                'Invalid header value: must be a string or array of strings; '
                . 'cannot be an empty array'
            );
        }

        return array_map(function ($value) {
            HeaderSecurity::assertValid($value);

            return (string) $value;
        }, array_values($values));
    }

    /**
     * Ensure header name and values are valid.
     *
     * @param string $name
     *
     * @throws Exception\InvalidArgumentException
     */
    private function assertHeader($name) : void
    {
        HeaderSecurity::assertValidName($name);
    }
}
laminas-diactoros/src/Exception/UnseekableStreamException.php000064400000001731147361032560020535 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-diactoros for the canonical source repository
 * @copyright https://github.com/laminas/laminas-diactoros/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-diactoros/blob/master/LICENSE.md New BSD License
 */

declare(strict_types=1);

namespace Laminas\Diactoros\Exception;

use RuntimeException;

class UnseekableStreamException extends RuntimeException implements ExceptionInterface
{
    public static function dueToConfiguration() : self
    {
        return new self('Stream is not seekable');
    }

    public static function dueToMissingResource() : self
    {
        return new self('No resource available; cannot seek position');
    }

    public static function dueToPhpError() : self
    {
        return new self('Error seeking within stream');
    }

    public static function forCallbackStream() : self
    {
        return new self('Callback streams cannot seek position');
    }
}
laminas-diactoros/src/Exception/UnrecognizedProtocolVersionException.php000064400000001247147361032560023031 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-diactoros for the canonical source repository
 * @copyright https://github.com/laminas/laminas-diactoros/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-diactoros/blob/master/LICENSE.md New BSD License
 */

declare(strict_types=1);

namespace Laminas\Diactoros\Exception;

use UnexpectedValueException;

use function sprintf;

class UnrecognizedProtocolVersionException extends UnexpectedValueException implements ExceptionInterface
{
    public static function forVersion(string $version) : self
    {
        return new self(sprintf('Unrecognized protocol version (%s)', $version));
    }
}
laminas-diactoros/src/Exception/UnrewindableStreamException.php000064400000001141147361032560021071 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-diactoros for the canonical source repository
 * @copyright https://github.com/laminas/laminas-diactoros/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-diactoros/blob/master/LICENSE.md New BSD License
 */

declare(strict_types=1);

namespace Laminas\Diactoros\Exception;

use RuntimeException;

class UnrewindableStreamException extends RuntimeException implements ExceptionInterface
{
    public static function forCallbackStream() : self
    {
        return new self('Callback streams cannot rewind position');
    }
}
laminas-diactoros/src/Exception/SerializationException.php000064400000001340147361032560020114 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-diactoros for the canonical source repository
 * @copyright https://github.com/laminas/laminas-diactoros/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-diactoros/blob/master/LICENSE.md New BSD License
 */

declare(strict_types=1);

namespace Laminas\Diactoros\Exception;

use UnexpectedValueException;

class SerializationException extends UnexpectedValueException implements ExceptionInterface
{
    public static function forInvalidRequestLine() : self
    {
        return new self('Invalid request line detected');
    }

    public static function forInvalidStatusLine() : self
    {
        return new self('No status line detected');
    }
}
laminas-diactoros/src/Exception/ExceptionInterface.php000064400000000747147361032560017211 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-diactoros for the canonical source repository
 * @copyright https://github.com/laminas/laminas-diactoros/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-diactoros/blob/master/LICENSE.md New BSD License
 */

declare(strict_types=1);

namespace Laminas\Diactoros\Exception;

use Throwable;

/**
 * Marker interface for package-specific exceptions.
 */
interface ExceptionInterface extends Throwable
{
}
laminas-diactoros/src/Exception/InvalidArgumentException.php000064400000000712147361032560020372 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-diactoros for the canonical source repository
 * @copyright https://github.com/laminas/laminas-diactoros/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-diactoros/blob/master/LICENSE.md New BSD License
 */

declare(strict_types=1);

namespace Laminas\Diactoros\Exception;

class InvalidArgumentException extends \InvalidArgumentException implements ExceptionInterface
{
}
laminas-diactoros/src/Exception/UntellableStreamException.php000064400000001553147361032560020550 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-diactoros for the canonical source repository
 * @copyright https://github.com/laminas/laminas-diactoros/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-diactoros/blob/master/LICENSE.md New BSD License
 */

declare(strict_types=1);

namespace Laminas\Diactoros\Exception;

use RuntimeException;

class UntellableStreamException extends RuntimeException implements ExceptionInterface
{
    public static function dueToMissingResource() : self
    {
        return new self('No resource available; cannot tell position');
    }

    public static function dueToPhpError() : self
    {
        return new self('Error occurred during tell operation');
    }

    public static function forCallbackStream() : self
    {
        return new self('Callback streams cannot tell position');
    }
}
laminas-diactoros/src/Exception/InvalidStreamPointerPositionException.php000064400000001310147361032560023124 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-diactoros for the canonical source repository
 * @copyright https://github.com/laminas/laminas-diactoros/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-diactoros/blob/master/LICENSE.md New BSD License
 */

declare(strict_types=1);

namespace Laminas\Diactoros\Exception;

use RuntimeException;
use Throwable;

class InvalidStreamPointerPositionException extends RuntimeException implements ExceptionInterface
{
    public function __construct(
        string $message = 'Invalid pointer position',
        $code = 0,
        Throwable $previous = null
    ) {
        parent::__construct($message, $code, $previous);
    }
}
laminas-diactoros/src/Exception/UnreadableStreamException.php000064400000001700147361032560020515 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-diactoros for the canonical source repository
 * @copyright https://github.com/laminas/laminas-diactoros/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-diactoros/blob/master/LICENSE.md New BSD License
 */

declare(strict_types=1);

namespace Laminas\Diactoros\Exception;

use RuntimeException;

class UnreadableStreamException extends RuntimeException implements ExceptionInterface
{
    public static function dueToConfiguration() : self
    {
        return new self('Stream is not readable');
    }

    public static function dueToMissingResource() : self
    {
        return new self('No resource available; cannot read');
    }

    public static function dueToPhpError() : self
    {
        return new self('Error reading stream');
    }

    public static function forCallbackStream() : self
    {
        return new self('Callback streams cannot read');
    }
}
laminas-diactoros/src/Exception/DeserializationException.php000064400000002736147361032560020437 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-diactoros for the canonical source repository
 * @copyright https://github.com/laminas/laminas-diactoros/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-diactoros/blob/master/LICENSE.md New BSD License
 */

declare(strict_types=1);

namespace Laminas\Diactoros\Exception;

use Throwable;
use UnexpectedValueException;

class DeserializationException extends UnexpectedValueException implements ExceptionInterface
{
    public static function forInvalidHeader() : self
    {
        throw new self('Invalid header detected');
    }

    public static function forInvalidHeaderContinuation() : self
    {
        throw new self('Invalid header continuation');
    }

    public static function forRequestFromArray(Throwable $previous) : self
    {
        return new self('Cannot deserialize request', $previous->getCode(), $previous);
    }

    public static function forResponseFromArray(Throwable $previous) : self
    {
        return new self('Cannot deserialize response', $previous->getCode(), $previous);
    }

    public static function forUnexpectedCarriageReturn() : self
    {
        throw new self('Unexpected carriage return detected');
    }

    public static function forUnexpectedEndOfHeaders() : self
    {
        throw new self('Unexpected end of headers');
    }

    public static function forUnexpectedLineFeed() : self
    {
        throw new self('Unexpected line feed detected');
    }
}
laminas-diactoros/src/Exception/UploadedFileAlreadyMovedException.php000064400000001335147361032560022135 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-diactoros for the canonical source repository
 * @copyright https://github.com/laminas/laminas-diactoros/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-diactoros/blob/master/LICENSE.md New BSD License
 */

declare(strict_types=1);

namespace Laminas\Diactoros\Exception;

use RuntimeException;
use Throwable;

class UploadedFileAlreadyMovedException extends RuntimeException implements ExceptionInterface
{
    public function __construct(
        string $message = 'Cannot retrieve stream after it has already moved',
        $code = 0,
        Throwable $previous = null
    ) {
        parent::__construct($message, $code, $previous);
    }
}
laminas-diactoros/src/Exception/UnwritableStreamException.php000064400000001705147361032560020574 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-diactoros for the canonical source repository
 * @copyright https://github.com/laminas/laminas-diactoros/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-diactoros/blob/master/LICENSE.md New BSD License
 */

declare(strict_types=1);

namespace Laminas\Diactoros\Exception;

use RuntimeException;

class UnwritableStreamException extends RuntimeException implements ExceptionInterface
{
    public static function dueToConfiguration() : self
    {
        return new self('Stream is not writable');
    }

    public static function dueToMissingResource() : self
    {
        return new self('No resource available; cannot write');
    }

    public static function dueToPhpError() : self
    {
        return new self('Error writing to stream');
    }

    public static function forCallbackStream() : self
    {
        return new self('Callback streams cannot write');
    }
}
laminas-diactoros/src/Exception/UploadedFileErrorException.php000064400000002303147361032560020646 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-diactoros for the canonical source repository
 * @copyright https://github.com/laminas/laminas-diactoros/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-diactoros/blob/master/LICENSE.md New BSD License
 */

declare(strict_types=1);

namespace Laminas\Diactoros\Exception;

use RuntimeException;

use function sprintf;

class UploadedFileErrorException extends RuntimeException implements ExceptionInterface
{
    public static function forUnmovableFile() : self
    {
        return new self('Error occurred while moving uploaded file');
    }

    public static function dueToStreamUploadError(string $error) : self
    {
        return new self(sprintf(
            'Cannot retrieve stream due to upload error: %s',
            $error
        ));
    }

    public static function dueToUnwritablePath() : self
    {
        return new self('Unable to write to designated path');
    }

    public static function dueToUnwritableTarget(string $targetDirectory) : self
    {
        return new self(sprintf(
            'The target directory `%s` does not exists or is not writable',
            $targetDirectory
        ));
    }
}
laminas-diactoros/src/CallbackStream.php000064400000006545147361032560014346 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-diactoros for the canonical source repository
 * @copyright https://github.com/laminas/laminas-diactoros/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-diactoros/blob/master/LICENSE.md New BSD License
 */

declare(strict_types=1);

namespace Laminas\Diactoros;

use Psr\Http\Message\StreamInterface;

use function array_key_exists;

use const SEEK_SET;

/**
 * Implementation of PSR HTTP streams
 */
class CallbackStream implements StreamInterface
{
    /**
     * @var callable|null
     */
    protected $callback;

    /**
     * @param callable $callback
     * @throws Exception\InvalidArgumentException
     */
    public function __construct(callable $callback)
    {
        $this->attach($callback);
    }

    /**
     * {@inheritdoc}
     */
    public function __toString() : string
    {
        return $this->getContents();
    }

    /**
     * {@inheritdoc}
     */
    public function close() : void
    {
        $this->callback = null;
    }

    /**
     * {@inheritdoc}
     */
    public function detach() : ?callable
    {
        $callback = $this->callback;
        $this->callback = null;
        return $callback;
    }

    /**
     * Attach a new callback to the instance.
     */
    public function attach(callable $callback) : void
    {
        $this->callback = $callback;
    }

    /**
     * {@inheritdoc}
     */
    public function getSize() : ?int
    {
        return null;
    }

    /**
     * {@inheritdoc}
     */
    public function tell() : int
    {
        throw Exception\UntellableStreamException::forCallbackStream();
    }

    /**
     * {@inheritdoc}
     */
    public function eof() : bool
    {
        return empty($this->callback);
    }

    /**
     * {@inheritdoc}
     */
    public function isSeekable() : bool
    {
        return false;
    }

    /**
     * {@inheritdoc}
     */
    public function seek($offset, $whence = SEEK_SET)
    {
        throw Exception\UnseekableStreamException::forCallbackStream();
    }

    /**
     * {@inheritdoc}
     */
    public function rewind() : void
    {
        throw Exception\UnrewindableStreamException::forCallbackStream();
    }

    /**
     * {@inheritdoc}
     */
    public function isWritable() : bool
    {
        return false;
    }

    /**
     * {@inheritdoc}
     */
    public function write($string) : void
    {
        throw Exception\UnwritableStreamException::forCallbackStream();
    }

    /**
     * {@inheritdoc}
     */
    public function isReadable() : bool
    {
        return false;
    }

    /**
     * {@inheritdoc}
     */
    public function read($length) : string
    {
        throw Exception\UnreadableStreamException::forCallbackStream();
    }

    /**
     * {@inheritdoc}
     */
    public function getContents() : string
    {
        $callback = $this->detach();
        $contents = $callback ? $callback() : '';
        return (string) $contents;
    }

    /**
     * {@inheritdoc}
     */
    public function getMetadata($key = null)
    {
        $metadata = [
            'eof' => $this->eof(),
            'stream_type' => 'callback',
            'seekable' => false
        ];

        if (null === $key) {
            return $metadata;
        }

        if (! array_key_exists($key, $metadata)) {
            return null;
        }

        return $metadata[$key];
    }
}
laminas-diactoros/src/functions/normalize_uploaded_files.legacy.php000064400000001246147361032560022001 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-diactoros for the canonical source repository
 * @copyright https://github.com/laminas/laminas-diactoros/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-diactoros/blob/master/LICENSE.md New BSD License
 */

declare(strict_types=1);

namespace Zend\Diactoros;

use Psr\Http\Message\UploadedFileInterface;

use function Laminas\Diactoros\normalizeUploadedFiles as laminas_normalizeUploadedFiles;

/**
 * @deprecated Use Laminas\Diactoros\normalizeUploadedFiles instead
 */
function normalizeUploadedFiles(array $files) : array
{
    return laminas_normalizeUploadedFiles(...func_get_args());
}
laminas-diactoros/src/functions/normalize_server.legacy.php000064400000001205147361032560020323 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-diactoros for the canonical source repository
 * @copyright https://github.com/laminas/laminas-diactoros/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-diactoros/blob/master/LICENSE.md New BSD License
 */

declare(strict_types=1);

namespace Zend\Diactoros;

use function Laminas\Diactoros\normalizeServer as laminas_normalizeServer;

/**
 * @deprecated Use Laminas\Diactoros\normalizeServer instead
 */
function normalizeServer(array $server, callable $apacheRequestHeaderCallback = null) : array
{
    return laminas_normalizeServer(...func_get_args());
}
laminas-diactoros/src/functions/normalize_server.php000064400000003455147361032560017071 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-diactoros for the canonical source repository
 * @copyright https://github.com/laminas/laminas-diactoros/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-diactoros/blob/master/LICENSE.md New BSD License
 */

declare(strict_types=1);

namespace Laminas\Diactoros;

use function is_callable;

/**
 * Marshal the $_SERVER array
 *
 * Pre-processes and returns the $_SERVER superglobal. In particularly, it
 * attempts to detect the Authorization header, which is often not aggregated
 * correctly under various SAPI/httpd combinations.
 *
 * @param null|callable $apacheRequestHeaderCallback Callback that can be used to
 *     retrieve Apache request headers. This defaults to
 *     `apache_request_headers` under the Apache mod_php.
 * @return array Either $server verbatim, or with an added HTTP_AUTHORIZATION header.
 */
function normalizeServer(array $server, callable $apacheRequestHeaderCallback = null) : array
{
    if (null === $apacheRequestHeaderCallback && is_callable('apache_request_headers')) {
        $apacheRequestHeaderCallback = 'apache_request_headers';
    }

    // If the HTTP_AUTHORIZATION value is already set, or the callback is not
    // callable, we return verbatim
    if (isset($server['HTTP_AUTHORIZATION'])
        || ! is_callable($apacheRequestHeaderCallback)
    ) {
        return $server;
    }

    $apacheRequestHeaders = $apacheRequestHeaderCallback();
    if (isset($apacheRequestHeaders['Authorization'])) {
        $server['HTTP_AUTHORIZATION'] = $apacheRequestHeaders['Authorization'];
        return $server;
    }

    if (isset($apacheRequestHeaders['authorization'])) {
        $server['HTTP_AUTHORIZATION'] = $apacheRequestHeaders['authorization'];
        return $server;
    }

    return $server;
}
laminas-diactoros/src/functions/parse_cookie_header.php000064400000002376147361032560017457 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-diactoros for the canonical source repository
 * @copyright https://github.com/laminas/laminas-diactoros/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-diactoros/blob/master/LICENSE.md New BSD License
 */

declare(strict_types=1);

namespace Laminas\Diactoros;

use function preg_match_all;
use function urldecode;

/**
 * Parse a cookie header according to RFC 6265.
 *
 * PHP will replace special characters in cookie names, which results in other cookies not being available due to
 * overwriting. Thus, the server request should take the cookies from the request header instead.
 *
 * @param string $cookieHeader A string cookie header value.
 * @return array key/value cookie pairs.
 */
function parseCookieHeader($cookieHeader) : array
{
    preg_match_all('(
        (?:^\\n?[ \t]*|;[ ])
        (?P<name>[!#$%&\'*+-.0-9A-Z^_`a-z|~]+)
        =
        (?P<DQUOTE>"?)
            (?P<value>[\x21\x23-\x2b\x2d-\x3a\x3c-\x5b\x5d-\x7e]*)
        (?P=DQUOTE)
        (?=\\n?[ \t]*$|;[ ])
    )x', $cookieHeader, $matches, PREG_SET_ORDER);

    $cookies = [];

    foreach ($matches as $match) {
        $cookies[$match['name']] = urldecode($match['value']);
    }

    return $cookies;
}
laminas-diactoros/src/functions/marshal_protocol_version_from_sapi.legacy.php000064400000001243147361032560024113 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-diactoros for the canonical source repository
 * @copyright https://github.com/laminas/laminas-diactoros/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-diactoros/blob/master/LICENSE.md New BSD License
 */

declare(strict_types=1);

namespace Zend\Diactoros;

use function Laminas\Diactoros\marshalProtocolVersionFromSapi as laminas_marshalProtocolVersionFromSapi;

/**
 * @deprecated Use Laminas\Diactoros\marshalProtocolVersionFromSapi instead
 */
function marshalProtocolVersionFromSapi(array $server) : string
{
    return laminas_marshalProtocolVersionFromSapi(...func_get_args());
}
laminas-diactoros/src/functions/parse_cookie_header.legacy.php000064400000001141147361032560020707 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-diactoros for the canonical source repository
 * @copyright https://github.com/laminas/laminas-diactoros/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-diactoros/blob/master/LICENSE.md New BSD License
 */

declare(strict_types=1);

namespace Zend\Diactoros;

use function Laminas\Diactoros\parseCookieHeader as laminas_parseCookieHeader;

/**
 * @deprecated Use Laminas\Diactoros\parseCookieHeader instead
 */
function parseCookieHeader($cookieHeader) : array
{
    return laminas_parseCookieHeader(...func_get_args());
}
laminas-diactoros/src/functions/marshal_protocol_version_from_sapi.php000064400000001760147361032560022654 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-diactoros for the canonical source repository
 * @copyright https://github.com/laminas/laminas-diactoros/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-diactoros/blob/master/LICENSE.md New BSD License
 */

declare(strict_types=1);

namespace Laminas\Diactoros;

use function preg_match;

/**
 * Return HTTP protocol version (X.Y) as discovered within a `$_SERVER` array.
 *
 * @throws Exception\UnrecognizedProtocolVersionException if the
 *     $server['SERVER_PROTOCOL'] value is malformed.
 */
function marshalProtocolVersionFromSapi(array $server) : string
{
    if (! isset($server['SERVER_PROTOCOL'])) {
        return '1.1';
    }

    if (! preg_match('#^(HTTP/)?(?P<version>[1-9]\d*(?:\.\d)?)$#', $server['SERVER_PROTOCOL'], $matches)) {
        throw Exception\UnrecognizedProtocolVersionException::forVersion(
            (string) $server['SERVER_PROTOCOL']
        );
    }

    return $matches['version'];
}
laminas-diactoros/src/functions/create_uploaded_file.legacy.php000064400000001153147361032560021056 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-diactoros for the canonical source repository
 * @copyright https://github.com/laminas/laminas-diactoros/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-diactoros/blob/master/LICENSE.md New BSD License
 */

declare(strict_types=1);

namespace Zend\Diactoros;

use function Laminas\Diactoros\createUploadedFile as laminas_createUploadedFile;

/**
 * @deprecated Use Laminas\Diactoros\createUploadedFile instead
 */
function createUploadedFile(array $spec) : UploadedFile
{
    return laminas_createUploadedFile(...func_get_args());
}
laminas-diactoros/src/functions/normalize_uploaded_files.php000064400000010331147361032560020531 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-diactoros for the canonical source repository
 * @copyright https://github.com/laminas/laminas-diactoros/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-diactoros/blob/master/LICENSE.md New BSD License
 */

declare(strict_types=1);

namespace Laminas\Diactoros;

use Psr\Http\Message\UploadedFileInterface;

use function is_array;

/**
 * Normalize uploaded files
 *
 * Transforms each value into an UploadedFile instance, and ensures that nested
 * arrays are normalized.
 *
 * @return UploadedFileInterface[]
 * @throws Exception\InvalidArgumentException for unrecognized values
 */
function normalizeUploadedFiles(array $files) : array
{
    /**
     * Traverse a nested tree of uploaded file specifications.
     *
     * @param string[]|array[] $tmpNameTree
     * @param int[]|array[] $sizeTree
     * @param int[]|array[] $errorTree
     * @param string[]|array[]|null $nameTree
     * @param string[]|array[]|null $typeTree
     * @return UploadedFile[]|array[]
     */
    $recursiveNormalize = function (
        array $tmpNameTree,
        array $sizeTree,
        array $errorTree,
        array $nameTree = null,
        array $typeTree = null
    ) use (&$recursiveNormalize) : array {
        $normalized = [];
        foreach ($tmpNameTree as $key => $value) {
            if (is_array($value)) {
                // Traverse
                $normalized[$key] = $recursiveNormalize(
                    $tmpNameTree[$key],
                    $sizeTree[$key],
                    $errorTree[$key],
                    $nameTree[$key] ?? null,
                    $typeTree[$key] ?? null
                );
                continue;
            }
            $normalized[$key] = createUploadedFile([
                'tmp_name' => $tmpNameTree[$key],
                'size' => $sizeTree[$key],
                'error' => $errorTree[$key],
                'name' => $nameTree[$key] ?? null,
                'type' => $typeTree[$key] ?? null,
            ]);
        }
        return $normalized;
    };

    /**
     * Normalize an array of file specifications.
     *
     * Loops through all nested files (as determined by receiving an array to the
     * `tmp_name` key of a `$_FILES` specification) and returns a normalized array
     * of UploadedFile instances.
     *
     * This function normalizes a `$_FILES` array representing a nested set of
     * uploaded files as produced by the php-fpm SAPI, CGI SAPI, or mod_php
     * SAPI.
     *
     * @param array $files
     * @return UploadedFile[]
     */
    $normalizeUploadedFileSpecification = function (array $files = []) use (&$recursiveNormalize) : array {
        if (! isset($files['tmp_name']) || ! is_array($files['tmp_name'])
            || ! isset($files['size']) || ! is_array($files['size'])
            || ! isset($files['error']) || ! is_array($files['error'])
        ) {
            throw new Exception\InvalidArgumentException(sprintf(
                '$files provided to %s MUST contain each of the keys "tmp_name",'
                . ' "size", and "error", with each represented as an array;'
                . ' one or more were missing or non-array values',
                __FUNCTION__
            ));
        }

        return $recursiveNormalize(
            $files['tmp_name'],
            $files['size'],
            $files['error'],
            $files['name'] ?? null,
            $files['type'] ?? null
        );
    };

    $normalized = [];
    foreach ($files as $key => $value) {
        if ($value instanceof UploadedFileInterface) {
            $normalized[$key] = $value;
            continue;
        }

        if (is_array($value) && isset($value['tmp_name']) && is_array($value['tmp_name'])) {
            $normalized[$key] = $normalizeUploadedFileSpecification($value);
            continue;
        }

        if (is_array($value) && isset($value['tmp_name'])) {
            $normalized[$key] = createUploadedFile($value);
            continue;
        }

        if (is_array($value)) {
            $normalized[$key] = normalizeUploadedFiles($value);
            continue;
        }

        throw new Exception\InvalidArgumentException('Invalid value in files specification');
    }
    return $normalized;
}
laminas-diactoros/src/functions/marshal_uri_from_sapi.legacy.php000064400000001164147361032560021306 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-diactoros for the canonical source repository
 * @copyright https://github.com/laminas/laminas-diactoros/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-diactoros/blob/master/LICENSE.md New BSD License
 */

declare(strict_types=1);

namespace Zend\Diactoros;

use function Laminas\Diactoros\marshalUriFromSapi as laminas_marshalUriFromSapi;

/**
 * @deprecated Use Laminas\Diactoros\marshalUriFromSapi instead
 */
function marshalUriFromSapi(array $server, array $headers) : Uri
{
    return laminas_marshalUriFromSapi(...func_get_args());
}
laminas-diactoros/src/functions/marshal_headers_from_sapi.php000064400000003153147361032560020657 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-diactoros for the canonical source repository
 * @copyright https://github.com/laminas/laminas-diactoros/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-diactoros/blob/master/LICENSE.md New BSD License
 */

declare(strict_types=1);

namespace Laminas\Diactoros;

use function array_key_exists;
use function is_string;
use function strpos;
use function strtolower;
use function strtr;
use function substr;

/**
 * @param array $server Values obtained from the SAPI (generally `$_SERVER`).
 * @return array Header/value pairs
 */
function marshalHeadersFromSapi(array $server) : array
{
    $headers = [];
    foreach ($server as $key => $value) {
        if (! is_string($key)) {
            continue;
        }

        if ($value === '') {
            continue;
        }

        // Apache prefixes environment variables with REDIRECT_
        // if they are added by rewrite rules
        if (strpos($key, 'REDIRECT_') === 0) {
            $key = substr($key, 9);

            // We will not overwrite existing variables with the
            // prefixed versions, though
            if (array_key_exists($key, $server)) {
                continue;
            }
        }

        if (strpos($key, 'HTTP_') === 0) {
            $name = strtr(strtolower(substr($key, 5)), '_', '-');
            $headers[$name] = $value;
            continue;
        }

        if (strpos($key, 'CONTENT_') === 0) {
            $name = strtr(strtolower($key), '_', '-');
            $headers[$name] = $value;
            continue;
        }
    }

    return $headers;
}
laminas-diactoros/src/functions/marshal_method_from_sapi.legacy.php000064400000001166147361032560021771 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-diactoros for the canonical source repository
 * @copyright https://github.com/laminas/laminas-diactoros/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-diactoros/blob/master/LICENSE.md New BSD License
 */

declare(strict_types=1);

namespace Zend\Diactoros;

use function Laminas\Diactoros\marshalMethodFromSapi as laminas_marshalMethodFromSapi;

/**
 * @deprecated Use Laminas\Diactoros\marshalMethodFromSapi instead
 */
function marshalMethodFromSapi(array $server) : string
{
    return laminas_marshalMethodFromSapi(...func_get_args());
}
laminas-diactoros/src/functions/marshal_uri_from_sapi.php000064400000015243147361032560020046 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-diactoros for the canonical source repository
 * @copyright https://github.com/laminas/laminas-diactoros/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-diactoros/blob/master/LICENSE.md New BSD License
 */

declare(strict_types=1);

namespace Laminas\Diactoros;

use function array_change_key_case;
use function array_key_exists;
use function explode;
use function implode;
use function is_array;
use function ltrim;
use function preg_match;
use function preg_replace;
use function strlen;
use function strpos;
use function strtolower;
use function substr;

/**
 * Marshal a Uri instance based on the values presnt in the $_SERVER array and headers.
 *
 * @param array $server SAPI parameters
 * @param array $headers HTTP request headers
 */
function marshalUriFromSapi(array $server, array $headers) : Uri
{
    /**
     * Retrieve a header value from an array of headers using a case-insensitive lookup.
     *
     * @param array $headers Key/value header pairs
     * @param mixed $default Default value to return if header not found
     * @return mixed
     */
    $getHeaderFromArray = function (string $name, array $headers, $default = null) {
        $header  = strtolower($name);
        $headers = array_change_key_case($headers, CASE_LOWER);
        if (array_key_exists($header, $headers)) {
            $value = is_array($headers[$header]) ? implode(', ', $headers[$header]) : $headers[$header];
            return $value;
        }

        return $default;
    };

    /**
     * Marshal the host and port from HTTP headers and/or the PHP environment.
     *
     * @return array Array of two items, host and port, in that order (can be
     *     passed to a list() operation).
     */
    $marshalHostAndPort = function (array $headers, array $server) use ($getHeaderFromArray) : array {
        /**
        * @param string|array $host
        * @return array Array of two items, host and port, in that order (can be
        *     passed to a list() operation).
        */
        $marshalHostAndPortFromHeader = function ($host) {
            if (is_array($host)) {
                $host = implode(', ', $host);
            }

            $port = null;

            // works for regname, IPv4 & IPv6
            if (preg_match('|\:(\d+)$|', $host, $matches)) {
                $host = substr($host, 0, -1 * (strlen($matches[1]) + 1));
                $port = (int) $matches[1];
            }

            return [$host, $port];
        };

        /**
        * @return array Array of two items, host and port, in that order (can be
        *     passed to a list() operation).
        */
        $marshalIpv6HostAndPort = function (array $server, ?int $port) : array {
            $host = '[' . $server['SERVER_ADDR'] . ']';
            $port = $port ?: 80;
            if ($port . ']' === substr($host, strrpos($host, ':') + 1)) {
                // The last digit of the IPv6-Address has been taken as port
                // Unset the port so the default port can be used
                $port = null;
            }
            return [$host, $port];
        };

        static $defaults = ['', null];

        $forwardedHost = $getHeaderFromArray('x-forwarded-host', $headers, false);
        if ($forwardedHost !== false) {
            return $marshalHostAndPortFromHeader($forwardedHost);
        }

        $host = $getHeaderFromArray('host', $headers, false);
        if ($host !== false) {
            return $marshalHostAndPortFromHeader($host);
        }

        if (! isset($server['SERVER_NAME'])) {
            return $defaults;
        }

        $host = $server['SERVER_NAME'];
        $port = isset($server['SERVER_PORT']) ? (int) $server['SERVER_PORT'] : null;

        if (! isset($server['SERVER_ADDR'])
            || ! preg_match('/^\[[0-9a-fA-F\:]+\]$/', $host)
        ) {
            return [$host, $port];
        }

        // Misinterpreted IPv6-Address
        // Reported for Safari on Windows
        return $marshalIpv6HostAndPort($server, $port);
    };

    /**
     * Detect the path for the request
     *
     * Looks at a variety of criteria in order to attempt to autodetect the base
     * request path, including:
     *
     * - IIS7 UrlRewrite environment
     * - REQUEST_URI
     * - ORIG_PATH_INFO
     *
     * From Laminas\Http\PhpEnvironment\Request class
     */
    $marshalRequestPath = function (array $server) : string {
        // IIS7 with URL Rewrite: make sure we get the unencoded url
        // (double slash problem).
        $iisUrlRewritten = $server['IIS_WasUrlRewritten'] ?? null;
        $unencodedUrl    = $server['UNENCODED_URL'] ?? '';
        if ('1' === $iisUrlRewritten && ! empty($unencodedUrl)) {
            return $unencodedUrl;
        }

        $requestUri = $server['REQUEST_URI'] ?? null;

        if ($requestUri !== null) {
            return preg_replace('#^[^/:]+://[^/]+#', '', $requestUri);
        }

        $origPathInfo = $server['ORIG_PATH_INFO'] ?? null;
        if (empty($origPathInfo)) {
            return '/';
        }

        return $origPathInfo;
    };

    $uri = new Uri('');

    // URI scheme
    $scheme = 'http';
    $marshalHttpsValue = function ($https) : bool {
        if (is_bool($https)) {
            return $https;
        }

        if (! is_string($https)) {
            throw new Exception\InvalidArgumentException(sprintf(
                'SAPI HTTPS value MUST be a string or boolean; received %s',
                gettype($https)
            ));
        }

        return 'on' === strtolower($https);
    };
    if (array_key_exists('HTTPS', $server)) {
        $https = $marshalHttpsValue($server['HTTPS']);
    } elseif (array_key_exists('https', $server)) {
        $https = $marshalHttpsValue($server['https']);
    } else {
        $https = false;
    }

    if ($https
        || strtolower($getHeaderFromArray('x-forwarded-proto', $headers, '')) === 'https'
    ) {
        $scheme = 'https';
    }
    $uri = $uri->withScheme($scheme);

    // Set the host
    [$host, $port] = $marshalHostAndPort($headers, $server);
    if (! empty($host)) {
        $uri = $uri->withHost($host);
        if (! empty($port)) {
            $uri = $uri->withPort($port);
        }
    }

    // URI path
    $path = $marshalRequestPath($server);

    // Strip query string
    $path = explode('?', $path, 2)[0];

    // URI query
    $query = '';
    if (isset($server['QUERY_STRING'])) {
        $query = ltrim($server['QUERY_STRING'], '?');
    }

    // URI fragment
    $fragment = '';
    if (strpos($path, '#') !== false) {
        [$path, $fragment] = explode('#', $path, 2);
    }

    return $uri
        ->withPath($path)
        ->withFragment($fragment)
        ->withQuery($query);
}
laminas-diactoros/src/functions/marshal_headers_from_sapi.legacy.php000064400000001172147361032560022121 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-diactoros for the canonical source repository
 * @copyright https://github.com/laminas/laminas-diactoros/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-diactoros/blob/master/LICENSE.md New BSD License
 */

declare(strict_types=1);

namespace Zend\Diactoros;

use function Laminas\Diactoros\marshalHeadersFromSapi as laminas_marshalHeadersFromSapi;

/**
 * @deprecated Use Laminas\Diactoros\marshalHeadersFromSapi instead
 */
function marshalHeadersFromSapi(array $server) : array
{
    return laminas_marshalHeadersFromSapi(...func_get_args());
}
laminas-diactoros/src/functions/create_uploaded_file.php000064400000002250147361032560017612 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-diactoros for the canonical source repository
 * @copyright https://github.com/laminas/laminas-diactoros/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-diactoros/blob/master/LICENSE.md New BSD License
 */

declare(strict_types=1);

namespace Laminas\Diactoros;

/**
 * Create an uploaded file instance from an array of values.
 *
 * @param array $spec A single $_FILES entry.
 * @throws Exception\InvalidArgumentException if one or more of the tmp_name,
 *     size, or error keys are missing from $spec.
 */
function createUploadedFile(array $spec) : UploadedFile
{
    if (! isset($spec['tmp_name'])
        || ! isset($spec['size'])
        || ! isset($spec['error'])
    ) {
        throw new Exception\InvalidArgumentException(sprintf(
            '$spec provided to %s MUST contain each of the keys "tmp_name",'
            . ' "size", and "error"; one or more were missing',
            __FUNCTION__
        ));
    }

    return new UploadedFile(
        $spec['tmp_name'],
        (int) $spec['size'],
        $spec['error'],
        $spec['name'] ?? null,
        $spec['type'] ?? null
    );
}
laminas-diactoros/src/functions/marshal_method_from_sapi.php000064400000001010147361032560020512 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-diactoros for the canonical source repository
 * @copyright https://github.com/laminas/laminas-diactoros/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-diactoros/blob/master/LICENSE.md New BSD License
 */

declare(strict_types=1);

namespace Laminas\Diactoros;

/**
 * Retrieve the request method from the SAPI parameters.
 */
function marshalMethodFromSapi(array $server) : string
{
    return $server['REQUEST_METHOD'] ?? 'GET';
}
laminas-diactoros/src/Request/Serializer.php000064400000010754147361032560015234 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-diactoros for the canonical source repository
 * @copyright https://github.com/laminas/laminas-diactoros/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-diactoros/blob/master/LICENSE.md New BSD License
 */

declare(strict_types=1);

namespace Laminas\Diactoros\Request;

use Laminas\Diactoros\AbstractSerializer;
use Laminas\Diactoros\Exception;
use Laminas\Diactoros\Request;
use Laminas\Diactoros\Stream;
use Laminas\Diactoros\Uri;
use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\StreamInterface;

use function preg_match;
use function sprintf;

/**
 * Serialize (cast to string) or deserialize (cast string to Request) messages.
 *
 * This class provides functionality for serializing a RequestInterface instance
 * to a string, as well as the reverse operation of creating a Request instance
 * from a string/stream representing a message.
 */
final class Serializer extends AbstractSerializer
{
    /**
     * Deserialize a request string to a request instance.
     *
     * Internally, casts the message to a stream and invokes fromStream().
     *
     * @throws Exception\SerializationException when errors occur parsing the message.
     */
    public static function fromString(string $message) : Request
    {
        $stream = new Stream('php://temp', 'wb+');
        $stream->write($message);
        return self::fromStream($stream);
    }

    /**
     * Deserialize a request stream to a request instance.
     *
     * @throws Exception\InvalidArgumentException if the message stream is not
     *     readable or seekable.
     * @throws Exception\SerializationException if an invalid request line is detected.
     */
    public static function fromStream(StreamInterface $stream) : Request
    {
        if (! $stream->isReadable() || ! $stream->isSeekable()) {
            throw new Exception\InvalidArgumentException('Message stream must be both readable and seekable');
        }

        $stream->rewind();

        [$method, $requestTarget, $version] = self::getRequestLine($stream);
        $uri = self::createUriFromRequestTarget($requestTarget);

        [$headers, $body] = self::splitStream($stream);

        return (new Request($uri, $method, $body, $headers))
            ->withProtocolVersion($version)
            ->withRequestTarget($requestTarget);
    }

    /**
     * Serialize a request message to a string.
     */
    public static function toString(RequestInterface $request) : string
    {
        $httpMethod = $request->getMethod();
        $headers = self::serializeHeaders($request->getHeaders());
        $body    = (string) $request->getBody();
        $format  = '%s %s HTTP/%s%s%s';

        if (! empty($headers)) {
            $headers = "\r\n" . $headers;
        }
        if (! empty($body)) {
            $headers .= "\r\n\r\n";
        }

        return sprintf(
            $format,
            $httpMethod,
            $request->getRequestTarget(),
            $request->getProtocolVersion(),
            $headers,
            $body
        );
    }

    /**
     * Retrieve the components of the request line.
     *
     * Retrieves the first line of the stream and parses it, raising an
     * exception if it does not follow specifications; if valid, returns a list
     * with the method, target, and version, in that order.
     *
     * @throws Exception\SerializationException
     */
    private static function getRequestLine(StreamInterface $stream) : array
    {
        $requestLine = self::getLine($stream);

        if (! preg_match(
            '#^(?P<method>[!\#$%&\'*+.^_`|~a-zA-Z0-9-]+) (?P<target>[^\s]+) HTTP/(?P<version>[1-9]\d*\.\d+)$#',
            $requestLine,
            $matches
        )) {
            throw Exception\SerializationException::forInvalidRequestLine();
        }

        return [$matches['method'], $matches['target'], $matches['version']];
    }

    /**
     * Create and return a Uri instance based on the provided request target.
     *
     * If the request target is of authority or asterisk form, an empty Uri
     * instance is returned; otherwise, the value is used to create and return
     * a new Uri instance.
     */
    private static function createUriFromRequestTarget(string $requestTarget) : Uri
    {
        if (preg_match('#^https?://#', $requestTarget)) {
            return new Uri($requestTarget);
        }

        if (preg_match('#^(\*|[^/])#', $requestTarget)) {
            return new Uri();
        }

        return new Uri($requestTarget);
    }
}
laminas-diactoros/src/Request/ArraySerializer.php000064400000005662147361032560016235 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-diactoros for the canonical source repository
 * @copyright https://github.com/laminas/laminas-diactoros/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-diactoros/blob/master/LICENSE.md New BSD License
 */

declare(strict_types=1);

namespace Laminas\Diactoros\Request;

use Laminas\Diactoros\Exception;
use Laminas\Diactoros\Request;
use Laminas\Diactoros\Stream;
use Psr\Http\Message\RequestInterface;
use Throwable;

use function sprintf;

/**
 * Serialize or deserialize request messages to/from arrays.
 *
 * This class provides functionality for serializing a RequestInterface instance
 * to an array, as well as the reverse operation of creating a Request instance
 * from an array representing a message.
 */
final class ArraySerializer
{
    /**
     * Serialize a request message to an array.
     */
    public static function toArray(RequestInterface $request) : array
    {
        return [
            'method'           => $request->getMethod(),
            'request_target'   => $request->getRequestTarget(),
            'uri'              => (string) $request->getUri(),
            'protocol_version' => $request->getProtocolVersion(),
            'headers'          => $request->getHeaders(),
            'body'             => (string) $request->getBody(),
        ];
    }

    /**
     * Deserialize a request array to a request instance.
     *
     * @throws Exception\DeserializationException when cannot deserialize response
     */
    public static function fromArray(array $serializedRequest) : Request
    {
        try {
            $uri             = self::getValueFromKey($serializedRequest, 'uri');
            $method          = self::getValueFromKey($serializedRequest, 'method');
            $body            = new Stream('php://memory', 'wb+');
            $body->write(self::getValueFromKey($serializedRequest, 'body'));
            $headers         = self::getValueFromKey($serializedRequest, 'headers');
            $requestTarget   = self::getValueFromKey($serializedRequest, 'request_target');
            $protocolVersion = self::getValueFromKey($serializedRequest, 'protocol_version');

            return (new Request($uri, $method, $body, $headers))
                ->withRequestTarget($requestTarget)
                ->withProtocolVersion($protocolVersion);
        } catch (Throwable $exception) {
            throw Exception\DeserializationException::forRequestFromArray($exception);
        }
    }

    /**
     * @return mixed
     * @throws Exception\DeserializationException
     */
    private static function getValueFromKey(array $data, string $key, string $message = null)
    {
        if (isset($data[$key])) {
            return $data[$key];
        }
        if ($message === null) {
            $message = sprintf('Missing "%s" key in serialized request', $key);
        }
        throw new Exception\DeserializationException($message);
    }
}
laminas-diactoros/src/PhpInputStream.php000064400000003461147361032560014413 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-diactoros for the canonical source repository
 * @copyright https://github.com/laminas/laminas-diactoros/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-diactoros/blob/master/LICENSE.md New BSD License
 */

declare(strict_types=1);

namespace Laminas\Diactoros;

use function stream_get_contents;

/**
 * Caching version of php://input
 */
class PhpInputStream extends Stream
{
    /**
     * @var string
     */
    private $cache = '';

    /**
     * @var bool
     */
    private $reachedEof = false;

    /**
     * @param  string|resource $stream
     */
    public function __construct($stream = 'php://input')
    {
        parent::__construct($stream, 'r');
    }

    /**
     * {@inheritdoc}
     */
    public function __toString() : string
    {
        if ($this->reachedEof) {
            return $this->cache;
        }

        $this->getContents();
        return $this->cache;
    }

    /**
     * {@inheritdoc}
     */
    public function isWritable() : bool
    {
        return false;
    }

    /**
     * {@inheritdoc}
     */
    public function read($length) : string
    {
        $content = parent::read($length);
        if (! $this->reachedEof) {
            $this->cache .= $content;
        }

        if ($this->eof()) {
            $this->reachedEof = true;
        }

        return $content;
    }

    /**
     * {@inheritdoc}
     */
    public function getContents($maxLength = -1) : string
    {
        if ($this->reachedEof) {
            return $this->cache;
        }

        $contents     = stream_get_contents($this->resource, $maxLength);
        $this->cache .= $contents;

        if ($maxLength === -1 || $this->eof()) {
            $this->reachedEof = true;
        }

        return $contents;
    }
}
laminas-diactoros/src/ServerRequest.php000064400000014677147361032560014322 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-diactoros for the canonical source repository
 * @copyright https://github.com/laminas/laminas-diactoros/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-diactoros/blob/master/LICENSE.md New BSD License
 */

declare(strict_types=1);

namespace Laminas\Diactoros;

use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Message\StreamInterface;
use Psr\Http\Message\UploadedFileInterface;
use Psr\Http\Message\UriInterface;

use function array_key_exists;
use function is_array;

/**
 * Server-side HTTP request
 *
 * Extends the Request definition to add methods for accessing incoming data,
 * specifically server parameters, cookies, matched path parameters, query
 * string arguments, body parameters, and upload file information.
 *
 * "Attributes" are discovered via decomposing the request (and usually
 * specifically the URI path), and typically will be injected by the application.
 *
 * Requests are considered immutable; all methods that might change state are
 * implemented such that they retain the internal state of the current
 * message and return a new instance that contains the changed state.
 */
class ServerRequest implements ServerRequestInterface
{
    use RequestTrait;

    /**
     * @var array
     */
    private $attributes = [];

    /**
     * @var array
     */
    private $cookieParams = [];

    /**
     * @var null|array|object
     */
    private $parsedBody;

    /**
     * @var array
     */
    private $queryParams = [];

    /**
     * @var array
     */
    private $serverParams;

    /**
     * @var array
     */
    private $uploadedFiles;

    /**
     * @param array $serverParams Server parameters, typically from $_SERVER
     * @param array $uploadedFiles Upload file information, a tree of UploadedFiles
     * @param null|string|UriInterface $uri URI for the request, if any.
     * @param null|string $method HTTP method for the request, if any.
     * @param string|resource|StreamInterface $body Message body, if any.
     * @param array $headers Headers for the message, if any.
     * @param array $cookies Cookies for the message, if any.
     * @param array $queryParams Query params for the message, if any.
     * @param null|array|object $parsedBody The deserialized body parameters, if any.
     * @param string $protocol HTTP protocol version.
     * @throws Exception\InvalidArgumentException for any invalid value.
     */
    public function __construct(
        array $serverParams = [],
        array $uploadedFiles = [],
        $uri = null,
        string $method = null,
        $body = 'php://input',
        array $headers = [],
        array $cookies = [],
        array $queryParams = [],
        $parsedBody = null,
        string $protocol = '1.1'
    ) {
        $this->validateUploadedFiles($uploadedFiles);

        if ($body === 'php://input') {
            $body = new PhpInputStream();
        }

        $this->initialize($uri, $method, $body, $headers);
        $this->serverParams  = $serverParams;
        $this->uploadedFiles = $uploadedFiles;
        $this->cookieParams  = $cookies;
        $this->queryParams   = $queryParams;
        $this->parsedBody    = $parsedBody;
        $this->protocol      = $protocol;
    }

    /**
     * {@inheritdoc}
     */
    public function getServerParams() : array
    {
        return $this->serverParams;
    }

    /**
     * {@inheritdoc}
     */
    public function getUploadedFiles() : array
    {
        return $this->uploadedFiles;
    }

    /**
     * {@inheritdoc}
     */
    public function withUploadedFiles(array $uploadedFiles) : ServerRequest
    {
        $this->validateUploadedFiles($uploadedFiles);
        $new = clone $this;
        $new->uploadedFiles = $uploadedFiles;
        return $new;
    }

    /**
     * {@inheritdoc}
     */
    public function getCookieParams() : array
    {
        return $this->cookieParams;
    }

    /**
     * {@inheritdoc}
     */
    public function withCookieParams(array $cookies) : ServerRequest
    {
        $new = clone $this;
        $new->cookieParams = $cookies;
        return $new;
    }

    /**
     * {@inheritdoc}
     */
    public function getQueryParams() : array
    {
        return $this->queryParams;
    }

    /**
     * {@inheritdoc}
     */
    public function withQueryParams(array $query) : ServerRequest
    {
        $new = clone $this;
        $new->queryParams = $query;
        return $new;
    }

    /**
     * {@inheritdoc}
     */
    public function getParsedBody()
    {
        return $this->parsedBody;
    }

    /**
     * {@inheritdoc}
     */
    public function withParsedBody($data) : ServerRequest
    {
        if (! is_array($data) && ! is_object($data) && null !== $data) {
            throw new Exception\InvalidArgumentException(sprintf(
                '%s expects a null, array, or object argument; received %s',
                __METHOD__,
                gettype($data)
            ));
        }

        $new = clone $this;
        $new->parsedBody = $data;
        return $new;
    }

    /**
     * {@inheritdoc}
     */
    public function getAttributes() : array
    {
        return $this->attributes;
    }

    /**
     * {@inheritdoc}
     */
    public function getAttribute($attribute, $default = null)
    {
        if (! array_key_exists($attribute, $this->attributes)) {
            return $default;
        }

        return $this->attributes[$attribute];
    }

    /**
     * {@inheritdoc}
     */
    public function withAttribute($attribute, $value) : ServerRequest
    {
        $new = clone $this;
        $new->attributes[$attribute] = $value;
        return $new;
    }

    /**
     * {@inheritdoc}
     */
    public function withoutAttribute($attribute) : ServerRequest
    {
        $new = clone $this;
        unset($new->attributes[$attribute]);
        return $new;
    }

    /**
     * Recursively validate the structure in an uploaded files array.
     *
     * @throws Exception\InvalidArgumentException if any leaf is not an UploadedFileInterface instance.
     */
    private function validateUploadedFiles(array $uploadedFiles) : void
    {
        foreach ($uploadedFiles as $file) {
            if (is_array($file)) {
                $this->validateUploadedFiles($file);
                continue;
            }

            if (! $file instanceof UploadedFileInterface) {
                throw new Exception\InvalidArgumentException('Invalid leaf in uploaded files structure');
            }
        }
    }
}
laminas-diactoros/src/ServerRequestFactory.php000064400000006020147361032560015631 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-diactoros for the canonical source repository
 * @copyright https://github.com/laminas/laminas-diactoros/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-diactoros/blob/master/LICENSE.md New BSD License
 */

declare(strict_types=1);

namespace Laminas\Diactoros;

use Psr\Http\Message\ServerRequestFactoryInterface;
use Psr\Http\Message\ServerRequestInterface;

use function array_key_exists;
use function is_callable;

/**
 * Class for marshaling a request object from the current PHP environment.
 *
 * Logic largely refactored from the Laminas Laminas\Http\PhpEnvironment\Request class.
 *
 * @copyright Copyright (c) 2005-2015 Laminas (https://www.zend.com)
 * @license   https://getlaminas.org/license/new-bsd New BSD License
 */
class ServerRequestFactory implements ServerRequestFactoryInterface
{
    /**
     * Function to use to get apache request headers; present only to simplify mocking.
     *
     * @var callable
     */
    private static $apacheRequestHeaders = 'apache_request_headers';

    /**
     * Create a request from the supplied superglobal values.
     *
     * If any argument is not supplied, the corresponding superglobal value will
     * be used.
     *
     * The ServerRequest created is then passed to the fromServer() method in
     * order to marshal the request URI and headers.
     *
     * @see fromServer()
     * @param array $server $_SERVER superglobal
     * @param array $query $_GET superglobal
     * @param array $body $_POST superglobal
     * @param array $cookies $_COOKIE superglobal
     * @param array $files $_FILES superglobal
     * @return ServerRequest
     */
    public static function fromGlobals(
        array $server = null,
        array $query = null,
        array $body = null,
        array $cookies = null,
        array $files = null
    ) : ServerRequest {
        $server = normalizeServer(
            $server ?: $_SERVER,
            is_callable(self::$apacheRequestHeaders) ? self::$apacheRequestHeaders : null
        );
        $files   = normalizeUploadedFiles($files ?: $_FILES);
        $headers = marshalHeadersFromSapi($server);

        if (null === $cookies && array_key_exists('cookie', $headers)) {
            $cookies = parseCookieHeader($headers['cookie']);
        }

        return new ServerRequest(
            $server,
            $files,
            marshalUriFromSapi($server, $headers),
            marshalMethodFromSapi($server),
            'php://input',
            $headers,
            $cookies ?: $_COOKIE,
            $query ?: $_GET,
            $body ?: $_POST,
            marshalProtocolVersionFromSapi($server)
        );
    }

    /**
     * {@inheritDoc}
     */
    public function createServerRequest(string $method, $uri, array $serverParams = []) : ServerRequestInterface
    {
        $uploadedFiles = [];

        return new ServerRequest(
            $serverParams,
            $uploadedFiles,
            $uri,
            $method,
            'php://temp'
        );
    }
}
laminas-diactoros/src/StreamFactory.php000064400000002720147361032560014250 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-diactoros for the canonical source repository
 * @copyright https://github.com/laminas/laminas-diactoros/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-diactoros/blob/master/LICENSE.md New BSD License
 */

declare(strict_types=1);

namespace Laminas\Diactoros;

use Psr\Http\Message\StreamFactoryInterface;
use Psr\Http\Message\StreamInterface;

use function fopen;
use function fwrite;
use function get_resource_type;
use function is_resource;
use function rewind;

class StreamFactory implements StreamFactoryInterface
{
    /**
     * {@inheritDoc}
     */
    public function createStream(string $content = '') : StreamInterface
    {
        $resource = fopen('php://temp', 'r+');
        fwrite($resource, $content);
        rewind($resource);

        return $this->createStreamFromResource($resource);
    }

    /**
     * {@inheritDoc}
     */
    public function createStreamFromFile(string $file, string $mode = 'r') : StreamInterface
    {
        return new Stream($file, $mode);
    }

    /**
     * {@inheritDoc}
     */
    public function createStreamFromResource($resource) : StreamInterface
    {
        if (! is_resource($resource) || 'stream' !== get_resource_type($resource)) {
            throw new Exception\InvalidArgumentException(
                'Invalid stream provided; must be a stream resource'
            );
        }
        return new Stream($resource);
    }
}
laminas-diactoros/src/Uri.php000064400000042531147361032560012230 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-diactoros for the canonical source repository
 * @copyright https://github.com/laminas/laminas-diactoros/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-diactoros/blob/master/LICENSE.md New BSD License
 */

declare(strict_types=1);

namespace Laminas\Diactoros;

use Psr\Http\Message\UriInterface;

use function array_keys;
use function explode;
use function get_class;
use function gettype;
use function implode;
use function is_numeric;
use function is_object;
use function is_string;
use function ltrim;
use function parse_url;
use function preg_match;
use function preg_replace;
use function preg_replace_callback;
use function rawurlencode;
use function sprintf;
use function str_split;
use function strpos;
use function strtolower;
use function substr;

/**
 * Implementation of Psr\Http\UriInterface.
 *
 * Provides a value object representing a URI for HTTP requests.
 *
 * Instances of this class  are considered immutable; all methods that
 * might change state are implemented such that they retain the internal
 * state of the current instance and return a new instance that contains the
 * changed state.
 */
class Uri implements UriInterface
{
    /**
     * Sub-delimiters used in user info, query strings and fragments.
     *
     * @const string
     */
    const CHAR_SUB_DELIMS = '!\$&\'\(\)\*\+,;=';

    /**
     * Unreserved characters used in user info, paths, query strings, and fragments.
     *
     * @const string
     */
    const CHAR_UNRESERVED = 'a-zA-Z0-9_\-\.~\pL';

    /**
     * @var int[] Array indexed by valid scheme names to their corresponding ports.
     */
    protected $allowedSchemes = [
        'http'  => 80,
        'https' => 443,
    ];

    /**
     * @var string
     */
    private $scheme = '';

    /**
     * @var string
     */
    private $userInfo = '';

    /**
     * @var string
     */
    private $host = '';

    /**
     * @var int
     */
    private $port;

    /**
     * @var string
     */
    private $path = '';

    /**
     * @var string
     */
    private $query = '';

    /**
     * @var string
     */
    private $fragment = '';

    /**
     * generated uri string cache
     * @var string|null
     */
    private $uriString;

    public function __construct(string $uri = '')
    {
        if ('' === $uri) {
            return;
        }

        $this->parseUri($uri);
    }

    /**
     * Operations to perform on clone.
     *
     * Since cloning usually is for purposes of mutation, we reset the
     * $uriString property so it will be re-calculated.
     */
    public function __clone()
    {
        $this->uriString = null;
    }

    /**
     * {@inheritdoc}
     */
    public function __toString() : string
    {
        if (null !== $this->uriString) {
            return $this->uriString;
        }

        $this->uriString = static::createUriString(
            $this->scheme,
            $this->getAuthority(),
            $this->getPath(), // Absolute URIs should use a "/" for an empty path
            $this->query,
            $this->fragment
        );

        return $this->uriString;
    }

    /**
     * {@inheritdoc}
     */
    public function getScheme() : string
    {
        return $this->scheme;
    }

    /**
     * {@inheritdoc}
     */
    public function getAuthority() : string
    {
        if ('' === $this->host) {
            return '';
        }

        $authority = $this->host;
        if ('' !== $this->userInfo) {
            $authority = $this->userInfo . '@' . $authority;
        }

        if ($this->isNonStandardPort($this->scheme, $this->host, $this->port)) {
            $authority .= ':' . $this->port;
        }

        return $authority;
    }

    /**
     * Retrieve the user-info part of the URI.
     *
     * This value is percent-encoded, per RFC 3986 Section 3.2.1.
     *
     * {@inheritdoc}
     */
    public function getUserInfo() : string
    {
        return $this->userInfo;
    }

    /**
     * {@inheritdoc}
     */
    public function getHost() : string
    {
        return $this->host;
    }

    /**
     * {@inheritdoc}
     */
    public function getPort() : ?int
    {
        return $this->isNonStandardPort($this->scheme, $this->host, $this->port)
            ? $this->port
            : null;
    }

    /**
     * {@inheritdoc}
     */
    public function getPath() : string
    {
        return $this->path;
    }

    /**
     * {@inheritdoc}
     */
    public function getQuery() : string
    {
        return $this->query;
    }

    /**
     * {@inheritdoc}
     */
    public function getFragment() : string
    {
        return $this->fragment;
    }

    /**
     * {@inheritdoc}
     */
    public function withScheme($scheme) : UriInterface
    {
        if (! is_string($scheme)) {
            throw new Exception\InvalidArgumentException(sprintf(
                '%s expects a string argument; received %s',
                __METHOD__,
                is_object($scheme) ? get_class($scheme) : gettype($scheme)
            ));
        }

        $scheme = $this->filterScheme($scheme);

        if ($scheme === $this->scheme) {
            // Do nothing if no change was made.
            return $this;
        }

        $new = clone $this;
        $new->scheme = $scheme;

        return $new;
    }

    /**
     * Create and return a new instance containing the provided user credentials.
     *
     * The value will be percent-encoded in the new instance, but with measures
     * taken to prevent double-encoding.
     *
     * {@inheritdoc}
     */
    public function withUserInfo($user, $password = null) : UriInterface
    {
        if (! is_string($user)) {
            throw new Exception\InvalidArgumentException(sprintf(
                '%s expects a string user argument; received %s',
                __METHOD__,
                is_object($user) ? get_class($user) : gettype($user)
            ));
        }
        if (null !== $password && ! is_string($password)) {
            throw new Exception\InvalidArgumentException(sprintf(
                '%s expects a string or null password argument; received %s',
                __METHOD__,
                is_object($password) ? get_class($password) : gettype($password)
            ));
        }

        $info = $this->filterUserInfoPart($user);
        if (null !== $password) {
            $info .= ':' . $this->filterUserInfoPart($password);
        }

        if ($info === $this->userInfo) {
            // Do nothing if no change was made.
            return $this;
        }

        $new = clone $this;
        $new->userInfo = $info;

        return $new;
    }

    /**
     * {@inheritdoc}
     */
    public function withHost($host) : UriInterface
    {
        if (! is_string($host)) {
            throw new Exception\InvalidArgumentException(sprintf(
                '%s expects a string argument; received %s',
                __METHOD__,
                is_object($host) ? get_class($host) : gettype($host)
            ));
        }

        if ($host === $this->host) {
            // Do nothing if no change was made.
            return $this;
        }

        $new = clone $this;
        $new->host = strtolower($host);

        return $new;
    }

    /**
     * {@inheritdoc}
     */
    public function withPort($port) : UriInterface
    {
        if ($port !== null) {
            if (! is_numeric($port) || is_float($port)) {
                throw new Exception\InvalidArgumentException(sprintf(
                    'Invalid port "%s" specified; must be an integer, an integer string, or null',
                    is_object($port) ? get_class($port) : gettype($port)
                ));
            }

            $port = (int) $port;
        }

        if ($port === $this->port) {
            // Do nothing if no change was made.
            return $this;
        }

        if ($port !== null && ($port < 1 || $port > 65535)) {
            throw new Exception\InvalidArgumentException(sprintf(
                'Invalid port "%d" specified; must be a valid TCP/UDP port',
                $port
            ));
        }

        $new = clone $this;
        $new->port = $port;

        return $new;
    }

    /**
     * {@inheritdoc}
     */
    public function withPath($path) : UriInterface
    {
        if (! is_string($path)) {
            throw new Exception\InvalidArgumentException(
                'Invalid path provided; must be a string'
            );
        }

        if (strpos($path, '?') !== false) {
            throw new Exception\InvalidArgumentException(
                'Invalid path provided; must not contain a query string'
            );
        }

        if (strpos($path, '#') !== false) {
            throw new Exception\InvalidArgumentException(
                'Invalid path provided; must not contain a URI fragment'
            );
        }

        $path = $this->filterPath($path);

        if ($path === $this->path) {
            // Do nothing if no change was made.
            return $this;
        }

        $new = clone $this;
        $new->path = $path;

        return $new;
    }

    /**
     * {@inheritdoc}
     */
    public function withQuery($query) : UriInterface
    {
        if (! is_string($query)) {
            throw new Exception\InvalidArgumentException(
                'Query string must be a string'
            );
        }

        if (strpos($query, '#') !== false) {
            throw new Exception\InvalidArgumentException(
                'Query string must not include a URI fragment'
            );
        }

        $query = $this->filterQuery($query);

        if ($query === $this->query) {
            // Do nothing if no change was made.
            return $this;
        }

        $new = clone $this;
        $new->query = $query;

        return $new;
    }

    /**
     * {@inheritdoc}
     */
    public function withFragment($fragment) : UriInterface
    {
        if (! is_string($fragment)) {
            throw new Exception\InvalidArgumentException(sprintf(
                '%s expects a string argument; received %s',
                __METHOD__,
                is_object($fragment) ? get_class($fragment) : gettype($fragment)
            ));
        }

        $fragment = $this->filterFragment($fragment);

        if ($fragment === $this->fragment) {
            // Do nothing if no change was made.
            return $this;
        }

        $new = clone $this;
        $new->fragment = $fragment;

        return $new;
    }

    /**
     * Parse a URI into its parts, and set the properties
     */
    private function parseUri(string $uri) : void
    {
        $parts = parse_url($uri);

        if (false === $parts) {
            throw new Exception\InvalidArgumentException(
                'The source URI string appears to be malformed'
            );
        }

        $this->scheme    = isset($parts['scheme']) ? $this->filterScheme($parts['scheme']) : '';
        $this->userInfo  = isset($parts['user']) ? $this->filterUserInfoPart($parts['user']) : '';
        $this->host      = isset($parts['host']) ? strtolower($parts['host']) : '';
        $this->port      = isset($parts['port']) ? $parts['port'] : null;
        $this->path      = isset($parts['path']) ? $this->filterPath($parts['path']) : '';
        $this->query     = isset($parts['query']) ? $this->filterQuery($parts['query']) : '';
        $this->fragment  = isset($parts['fragment']) ? $this->filterFragment($parts['fragment']) : '';

        if (isset($parts['pass'])) {
            $this->userInfo .= ':' . $parts['pass'];
        }
    }

    /**
     * Create a URI string from its various parts
     */
    private static function createUriString(
        string $scheme,
        string $authority,
        string $path,
        string $query,
        string $fragment
    ) : string {
        $uri = '';

        if ('' !== $scheme) {
            $uri .= sprintf('%s:', $scheme);
        }

        if ('' !== $authority) {
            $uri .= '//' . $authority;
        }

        if ('' !== $path && '/' !== substr($path, 0, 1)) {
            $path = '/' . $path;
        }

        $uri .= $path;


        if ('' !== $query) {
            $uri .= sprintf('?%s', $query);
        }

        if ('' !== $fragment) {
            $uri .= sprintf('#%s', $fragment);
        }

        return $uri;
    }

    /**
     * Is a given port non-standard for the current scheme?
     */
    private function isNonStandardPort(string $scheme, string $host, ?int $port) : bool
    {
        if ('' === $scheme) {
            return '' === $host || null !== $port;
        }

        if ('' === $host || null === $port) {
            return false;
        }

        return ! isset($this->allowedSchemes[$scheme]) || $port !== $this->allowedSchemes[$scheme];
    }

    /**
     * Filters the scheme to ensure it is a valid scheme.
     *
     * @param string $scheme Scheme name.
     * @return string Filtered scheme.
     */
    private function filterScheme(string $scheme) : string
    {
        $scheme = strtolower($scheme);
        $scheme = preg_replace('#:(//)?$#', '', $scheme);

        if ('' === $scheme) {
            return '';
        }

        if (! isset($this->allowedSchemes[$scheme])) {
            throw new Exception\InvalidArgumentException(sprintf(
                'Unsupported scheme "%s"; must be any empty string or in the set (%s)',
                $scheme,
                implode(', ', array_keys($this->allowedSchemes))
            ));
        }

        return $scheme;
    }

    /**
     * Filters a part of user info in a URI to ensure it is properly encoded.
     *
     * @param string $part
     * @return string
     */
    private function filterUserInfoPart(string $part) : string
    {
        $part = $this->filterInvalidUtf8($part);

        // Note the addition of `%` to initial charset; this allows `|` portion
        // to match and thus prevent double-encoding.
        return preg_replace_callback(
            '/(?:[^%' . self::CHAR_UNRESERVED . self::CHAR_SUB_DELIMS . ']+|%(?![A-Fa-f0-9]{2}))/u',
            [$this, 'urlEncodeChar'],
            $part
        );
    }

    /**
     * Filters the path of a URI to ensure it is properly encoded.
     */
    private function filterPath(string $path) : string
    {
        $path = $this->filterInvalidUtf8($path);

        $path = preg_replace_callback(
            '/(?:[^' . self::CHAR_UNRESERVED . ')(:@&=\+\$,\/;%]+|%(?![A-Fa-f0-9]{2}))/u',
            [$this, 'urlEncodeChar'],
            $path
        );

        if ('' === $path) {
            // No path
            return $path;
        }

        if ($path[0] !== '/') {
            // Relative path
            return $path;
        }

        // Ensure only one leading slash, to prevent XSS attempts.
        return '/' . ltrim($path, '/');
    }

    /**
     * Encode invalid UTF-8 characters in given string. All other characters are unchanged.
     */
    private function filterInvalidUtf8(string $string) : string
    {
        // check if given string contains only valid UTF-8 characters
        if (preg_match('//u', $string)) {
            return $string;
        }

        $letters = str_split($string);
        foreach ($letters as $i => $letter) {
            if (! preg_match('//u', $letter)) {
                $letters[$i] = $this->urlEncodeChar([$letter]);
            }
        }

        return implode('', $letters);
    }

    /**
     * Filter a query string to ensure it is propertly encoded.
     *
     * Ensures that the values in the query string are properly urlencoded.
     */
    private function filterQuery(string $query) : string
    {
        if ('' !== $query && strpos($query, '?') === 0) {
            $query = substr($query, 1);
        }

        $parts = explode('&', $query);
        foreach ($parts as $index => $part) {
            [$key, $value] = $this->splitQueryValue($part);
            if ($value === null) {
                $parts[$index] = $this->filterQueryOrFragment($key);
                continue;
            }
            $parts[$index] = sprintf(
                '%s=%s',
                $this->filterQueryOrFragment($key),
                $this->filterQueryOrFragment($value)
            );
        }

        return implode('&', $parts);
    }

    /**
     * Split a query value into a key/value tuple.
     *
     * @param string $value
     * @return array A value with exactly two elements, key and value
     */
    private function splitQueryValue(string $value) : array
    {
        $data = explode('=', $value, 2);
        if (! isset($data[1])) {
            $data[] = null;
        }
        return $data;
    }

    /**
     * Filter a fragment value to ensure it is properly encoded.
     */
    private function filterFragment(string $fragment) : string
    {
        if ('' !== $fragment && strpos($fragment, '#') === 0) {
            $fragment = '%23' . substr($fragment, 1);
        }

        return $this->filterQueryOrFragment($fragment);
    }

    /**
     * Filter a query string key or value, or a fragment.
     */
    private function filterQueryOrFragment(string $value) : string
    {
        $value = $this->filterInvalidUtf8($value);

        return preg_replace_callback(
            '/(?:[^' . self::CHAR_UNRESERVED . self::CHAR_SUB_DELIMS . '%:@\/\?]+|%(?![A-Fa-f0-9]{2}))/u',
            [$this, 'urlEncodeChar'],
            $value
        );
    }

    /**
     * URL encode a character returned by a regex.
     */
    private function urlEncodeChar(array $matches) : string
    {
        return rawurlencode($matches[0]);
    }
}
laminas-diactoros/src/UploadedFileFactory.php000064400000002020147361032560015343 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-diactoros for the canonical source repository
 * @copyright https://github.com/laminas/laminas-diactoros/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-diactoros/blob/master/LICENSE.md New BSD License
 */

declare(strict_types=1);

namespace Laminas\Diactoros;

use Psr\Http\Message\StreamInterface;
use Psr\Http\Message\UploadedFileFactoryInterface;
use Psr\Http\Message\UploadedFileInterface;

use const UPLOAD_ERR_OK;

class UploadedFileFactory implements UploadedFileFactoryInterface
{
    /**
     * {@inheritDoc}
     */
    public function createUploadedFile(
        StreamInterface $stream,
        int $size = null,
        int $error = UPLOAD_ERR_OK,
        string $clientFilename = null,
        string $clientMediaType = null
    ) : UploadedFileInterface {
        if ($size === null) {
            $size = $stream->getSize();
        }

        return new UploadedFile($stream, $size, $error, $clientFilename, $clientMediaType);
    }
}
laminas-diactoros/src/ResponseFactory.php000064400000001327147361032560014615 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-diactoros for the canonical source repository
 * @copyright https://github.com/laminas/laminas-diactoros/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-diactoros/blob/master/LICENSE.md New BSD License
 */

declare(strict_types=1);

namespace Laminas\Diactoros;

use Psr\Http\Message\ResponseFactoryInterface;
use Psr\Http\Message\ResponseInterface;

class ResponseFactory implements ResponseFactoryInterface
{
    /**
     * {@inheritDoc}
     */
    public function createResponse(int $code = 200, string $reasonPhrase = '') : ResponseInterface
    {
        return (new Response())
            ->withStatus($code, $reasonPhrase);
    }
}
laminas-diactoros/README.md000064400000003221147361032560011441 0ustar00# laminas-diactoros

Master:
[![Build status][Master image]][Master]
[![Coverage Status][Master coverage image]][Master coverage]
Develop:
[![Build status][Develop image]][Develop]
[![Coverage Status][Develop coverage image]][Develop coverage]

> Diactoros (pronunciation: `/dɪʌktɒrɒs/`): an epithet for Hermes, meaning literally, "the messenger."

This package supercedes and replaces [phly/http](https://github.com/phly/http).

`laminas-diactoros` is a PHP package containing implementations of the
[PSR-7 HTTP message interfaces](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-7-http-message.md)
and [PSR-17 HTTP message factory interfaces](https://www.php-fig.org/psr/psr-17).

* File issues at https://github.com/laminas/laminas-diactoros/issues
* Issue patches to https://github.com/laminas/laminas-diactoros/pulls

## Documentation

Documentation is available at:

- https://docs.laminas.dev/laminas-diactoros/

Source files for documentation are [in the docs/ tree](docs/).

  [Master]: https://travis-ci.com/laminas/laminas-diactoros
  [Master image]: https://travis-ci.com/laminas/laminas-diactoros.svg?branch=master
  [Master coverage image]: https://img.shields.io/coveralls/laminas/laminas-diactoros/master.svg
  [Master coverage]: https://coveralls.io/r/laminas/laminas-diactoros?branch=master
  [Develop]: https://github.com/laminas/laminas-diactoros/tree/develop
  [Develop image]:  https://travis-ci.com/laminas/laminas-diactoros.svg?branch=develop
  [Develop coverage image]: https://coveralls.io/repos/laminas/laminas-diactoros/badge.svg?branch=develop
  [Develop coverage]: https://coveralls.io/r/laminas/laminas-diactoros?branch=develop
laminas-diactoros/CHANGELOG.md000064400000154121147361032560012001 0ustar00# Changelog

All notable changes to this project will be documented in this file, in reverse chronological order by release.

## 2.3.1 - 2020-07-07

### Added

- Nothing.

### Changed

- Nothing.

### Deprecated

- Nothing.

### Removed

- Nothing.

### Fixed

- [#44](https://github.com/laminas/laminas-diactoros/pull/44) fixes an issue whereby the uploaded file size was being provided as an integer string, and causing type errors. The value is now cast to integer before creating an `UploadedFile` instance.

## 2.3.0 - 2020-04-27

### Added

- [#37](https://github.com/laminas/laminas-diactoros/pull/37) adds a ConfigProvider and Module, allowing the package to be autoregistered within Mezzio and MVC applications. Each provides configuration mapping PSR-17 HTTP message factory interfaces to the Diactoros implementations of them.

### Changed

- Nothing.

### Deprecated

- Nothing.

### Removed

- Nothing.

### Fixed

- Nothing.

## 2.2.3 - 2020-03-29

### Added

- Nothing.

### Changed

- Nothing.

### Deprecated

- Nothing.

### Removed

- Nothing.

### Fixed

- Fixed `replace` version constraint in composer.json so repository can be used as replacement of `zendframework/zend-diactoros:^2.2.1`.

## 2.2.2 - 2020-01-07

### Added

- Nothing.

### Changed

- Nothing.

### Deprecated

- Nothing.

### Removed

- Nothing.

### Fixed

- [#30](https://github.com/laminas/laminas-diactoros/pull/30) adds missing `return` statements to the various `src/functions/*.legacy.php` function files to ensure they work correctly when used.

## 2.2.1 - 2019-11-13

### Added

- Nothing.

### Changed

- [zendframework/zend-diactoros#379](https://github.com/zendframework/zend-diactoros/pull/379) removes extension of `SplFileInfo` by the `UploadedFile` class. The signatures of `getSize()` are potentially incompatible, and `UploadedFile` is intended to work with arbitrary PHP and PSR-7 streams, whereas `SplFileInfo` can only model files on the filesystem. While this is technically a BC break, we are treating it as a bugfix, as the class was broken for many use cases.

### Deprecated

- Nothing.

### Removed

- Nothing.

### Fixed

- Nothing.

## 2.2.0 - 2019-11-12

### Added

- [zendframework/zend-diactoros#376](https://github.com/zendframework/zend-diactoros/pull/376) adds support for using the X-Forwarded-Host header for determining the originally requested host name when marshaling the server request.

### Changed

- [zendframework/zend-diactoros#378](https://github.com/zendframework/zend-diactoros/pull/378) updates the `UploadedFile` class to extend `SplFileInfo`, allowing developers to make use of those features in their applications.

### Deprecated

- Nothing.

### Removed

- Nothing.

### Fixed

- Nothing.

## 2.2.0  - 2019-11-08

### Added

- [zendframework/zend-diactoros#377](https://github.com/zendframework/zend-diactoros/issues/377) enables UploadedFile to stand in and be used as an SplFileInfo object.

### Changed

- Nothing.

### Deprecated

- Nothing.

### Removed

- Nothing.

### Fixed

- Nothing.

## 2.1.5 - 2019-10-10

### Added

- Nothing.

### Changed

- Nothing.

### Deprecated

- Nothing.

### Removed

- Nothing.

### Fixed

- [zendframework/zend-diactoros#372](https://github.com/zendframework/zend-diactoros/pull/372) fixes issues that occur in the `Laminas\Diactoros\Uri` class when invalid UTF-8 characters are present the user-info, path, or query string, ensuring they are URL-encoded before being consumed. Previously, such characters could result in a fatal error, which was particularly problematic when marshaling the request URI for an application request cycle.

## 2.1.4 - 2019-10-08

### Added

- Nothing.

### Changed

- Nothing.

### Deprecated

- Nothing.

### Removed

- Nothing.

### Fixed

- [zendframework/zend-diactoros#370](https://github.com/zendframework/zend-diactoros/pull/370) updates `Laminas\Diactoros\marshalHeadersFromSapi()` to ensure all underscores in header name keys are converted to dashes (fixing issues with header names such as `CONTENT_SECURITY_POLICY`, which would previously resolve improperly to `content-security_policy`).

- [zendframework/zend-diactoros#370](https://github.com/zendframework/zend-diactoros/pull/370) updates `Laminas\Diactoros\marshalHeadersFromSapi()` to ignore header names from the `$server` array that resolve to integers; previously, it would raise a fatal error.

## 2.1.3 - 2019-07-10

### Added

- Nothing.

### Changed

- Nothing.

### Deprecated

- Nothing.

### Removed

- Nothing.

### Fixed

- [zendframework/zend-diactoros#363](https://github.com/zendframework/zend-diactoros/issues/363) modifies detection of HTTPS schemas via the `$_SERVER['HTTPS']` value
  such that an empty HTTPS-key will result in a scheme of `http` and not
  `https`.

## 2.1.2 - 2019-04-29

### Added

- Nothing.

### Changed

- Nothing.

### Deprecated

- Nothing.

### Removed

- Nothing.

### Fixed

- [zendframework/zend-diactoros#355](https://github.com/zendframework/zend-diactoros/pull/355) adds `phpdbg` to the list of accepted non-SAPI enviornments for purposes
  of calling `UploadedFile::moveTo()`.

## 2.1.1 - 2019-01-05

### Added

- Nothing.

### Changed

- Nothing.

### Deprecated

- Nothing.

### Removed

- Nothing.

### Fixed

- [zendframework/zend-diactoros#349](https://github.com/zendframework/zend-diactoros/pull/349) fixes an issue when marshaling headers with values of `0` or `0` from the SAPI, ensuring they are detected and injected into the ServerRequest properly.

## 2.1.0 - 2018-12-20

### Added

- [zendframework/zend-diactoros#345](https://github.com/zendframework/zend-diactoros/pull/345) adds support for PHP 7.3.

### Changed

- Nothing.

### Deprecated

- Nothing.

### Removed

- Nothing.

### Fixed

- Nothing.

## 2.0.3 - 2019-01-05

### Added

- Nothing.

### Changed

- Nothing.

### Deprecated

- Nothing.

### Removed

- Nothing.

### Fixed

- [zendframework/zend-diactoros#349](https://github.com/zendframework/zend-diactoros/pull/349) fixes an issue when marshaling headers with values of `0` or `0` from the
  SAPI, ensuring they are detected and injected into the ServerRequest properly.

## 2.0.2 - 2018-12-20

### Added

- Nothing.

### Changed

- Nothing.

### Deprecated

- Nothing.

### Removed

- Nothing.

### Fixed

- [zendframework/zend-diactoros#344](https://github.com/zendframework/zend-diactoros/pull/344) provides a fix to ensure that headers with a value of "0" are retained.

## 2.0.1 - 2018-12-03

### Added

- Nothing.

### Changed

- Nothing.

### Deprecated

- Nothing.

### Removed

- Nothing.

### Fixed

- [zendframework/zend-diactoros#337](https://github.com/zendframework/zend-diactoros/pull/337) ensures that the `ServerRequestFactory::createServerRequest()` method
  creates a `php://temp` stream instead of a `php::input` stream, in compliance
  with the PSR-17 specification.

## 2.0.0 - 2018-09-27

### Added

- [zendframework/zend-diactoros#326](https://github.com/zendframework/zend-diactoros/pull/326) adds [PSR-17](https://www.php-fig.org/psr/psr-17/) HTTP Message Factory implementations, including:

  - `Laminas\Diactoros\RequestFactory`
  - `Laminas\Diactoros\ResponseFactory`
  - `Laminas\Diactoros\ServerRequestFactory`
  - `Laminas\Diactoros\StreamFactory`
  - `Laminas\Diactoros\UploadedFileFactory`
  - `Laminas\Diactoros\UriFactory`

  These factories may be used to produce the associated instances; we encourage
  users to rely on the PSR-17 factory interfaces to allow exchanging PSR-7
  implementations within their applications.

- [zendframework/zend-diactoros#328](https://github.com/zendframework/zend-diactoros/pull/328) adds a package-level exception interface, `Laminas\Diactoros\Exception\ExceptionInterface`,
  and several implementations for specific exceptions raised within the package.
  These include:

  - `Laminas\Diactoros\Exception\DeserializationException` (extends `UnexpectedValueException`)
  - `Laminas\Diactoros\Exception\InvalidArgumentException` (extends `InvalidArgumentException`)
  - `Laminas\Diactoros\Exception\InvalidStreamPointerPositionException` (extends `RuntimeException`)
  - `Laminas\Diactoros\Exception\SerializationException` (extends `UnexpectedValueException`)
  - `Laminas\Diactoros\Exception\UnreadableStreamException` (extends `RuntimeException`)
  - `Laminas\Diactoros\Exception\UnrecognizedProtocolVersionException` (extends `UnexpectedValueException`)
  - `Laminas\Diactoros\Exception\UnrewindableStreamException` (extends `RuntimeException`)
  - `Laminas\Diactoros\Exception\UnseekableStreamException` (extends `RuntimeException`)
  - `Laminas\Diactoros\Exception\UntellableStreamException` (extends `RuntimeException`)
  - `Laminas\Diactoros\Exception\UnwritableStreamException` (extends `RuntimeException`)
  - `Laminas\Diactoros\Exception\UploadedFileAlreadyMovedException` (extends `RuntimeException`)
  - `Laminas\Diactoros\Exception\UploadedFileErrorException` (extends `RuntimeException`)

### Changed

- [zendframework/zend-diactoros#329](https://github.com/zendframework/zend-diactoros/pull/329) adds return type hints and scalar parameter type hints wherever possible.
  The changes were done to help improve code quality, in part by reducing manual
  type checking. If you are extending any classes, you may need to update your
  signatures; check the signatures of the class(es) you are extending for changes.

- [zendframework/zend-diactoros#162](https://github.com/zendframework/zend-diactoros/pull/162) modifies `Serializer\Request` such that it now no longer raises an `UnexpectedValueException` via its `toString()` method
  when an unexpected HTTP method is encountered; this can be done safely, as the value can never
  be invalid due to other changes in the same patch.

- [zendframework/zend-diactoros#162](https://github.com/zendframework/zend-diactoros/pull/162) modifies `RequestTrait` such that it now invalidates non-string method arguments to either
  the constructor or `withMethod()`, raising an `InvalidArgumentException` for any that do not validate.

### Deprecated

- Nothing.

### Removed

- [zendframework/zend-diactoros#308](https://github.com/zendframework/zend-diactoros/pull/308) removes the following methods from the `ServerRequestFactory` class:
  - `normalizeServer()` (use `Laminas\Diactoros\normalizeServer()` instead)
  - `marshalHeaders()` (use `Laminas\Diactoros\marshalHeadersFromSapi()` instead)
  - `marshalUriFromServer()` (use `Laminas\Diactoros\marshalUriFromSapi()` instead)
  - `marshalRequestUri()` (use `Uri::getPath()` from the `Uri` instance returned by `marshalUriFromSapi()` instead)
  - `marshalHostAndPortFromHeaders()` (use `Uri::getHost()` and `Uri::getPort()` from the `Uri` instances returned by `marshalUriFromSapi()` instead)
  - `stripQueryString()` (use `explode("?", $path, 2)[0]` instead)
  - `normalizeFiles()` (use `Laminas\Diactoros\normalizeUploadedFiles()` instead)

- [zendframework/zend-diactoros#295](https://github.com/zendframework/zend-diactoros/pull/295) removes `Laminas\Diactoros\Server`. You can use the `RequestHandlerRunner` class from
  [laminas/laminas-httphandlerrunner](https://docs.laminas.dev/laminas-httphandlerrunner) to provide these capabilities instead.

- [zendframework/zend-diactoros#295](https://github.com/zendframework/zend-diactoros/pull/295) removes `Laminas\Diactoros\Response\EmitterInterface` and the various emitter implementations.
  These can now be found in the package [laminas/laminas-httphandlerrunner](https://docs.laminas.dev/laminas-httphandlerrunner/), which also provides
  a PSR-7-implementation agnostic way of using them.

### Fixed

- Nothing.

## 1.8.7 - 2019-08-06

### Added

- Nothing.

### Changed

- Nothing.

### Deprecated

- Nothing.

### Removed

- Nothing.

### Fixed

- [zendframework/zend-diactoros#364](https://github.com/zendframework/zend-diactoros/issues/364) modifies detection of HTTPS schemas via the `$_SERVER['HTTPS']` value
  such that an empty HTTPS-key will result in a scheme of `http` and not
  `https`.

## 1.8.6 - 2018-09-05

### Added

- Nothing.

### Changed

- [zendframework/zend-diactoros#325](https://github.com/zendframework/zend-diactoros/pull/325) changes the behavior of `ServerRequest::withParsedBody()`. Per
- PSR-7, it now no longer allows values other than `null`, arrays, or objects.

- [zendframework/zend-diactoros#325](https://github.com/zendframework/zend-diactoros/pull/325) changes the behavior of each of `Request`, `ServerRequest`, and
  `Response` in relation to the validation of header values. Previously, we
  allowed empty arrays to be provided via `withHeader()`; however, this was
  contrary to the PSR-7 specification. Empty arrays are no longer allowed.

### Deprecated

- Nothing.

### Removed

- Nothing.

### Fixed

- [zendframework/zend-diactoros#325](https://github.com/zendframework/zend-diactoros/pull/325) ensures that `Uri::withUserInfo()` no longer ignores values of
  `0` (numeric zero).

- [zendframework/zend-diactoros#325](https://github.com/zendframework/zend-diactoros/pull/325) fixes how header values are merged when calling
  `withAddedHeader()`, ensuring that array keys are ignored.

## 1.8.5 - 2018-08-10

### Added

- Nothing.

### Changed

- Nothing.

### Deprecated

- Nothing.

### Removed

- Nothing.

### Fixed

- [zendframework/zend-diactoros#324](https://github.com/zendframework/zend-diactoros/pull/324) fixes a reference
  to an undefined variable in the `ServerRequestFactory`, which made it
  impossible to fetch a specific header by name.

## 1.8.4 - 2018-08-01

### Added

- Nothing.

### Changed

- This release modifies how `ServerRequestFactory` marshals the request URI. In
  prior releases, we would attempt to inspect the `X-Rewrite-Url` and
  `X-Original-Url` headers, using their values, if present. These headers are
  issued by the ISAPI_Rewrite module for IIS (developed by HeliconTech).
  However, we have no way of guaranteeing that the module is what issued the
  headers, making it an unreliable source for discovering the URI. As such, we
  have removed this feature in this release of Diactoros.

  If you are developing a middleware application, you can mimic the
  functionality via middleware as follows:

  ```php
  use Psr\Http\Message\ResponseInterface;
  use Psr\Http\Message\ServerRequestInterface;
  use Psr\Http\Server\RequestHandlerInterface;
  use Laminas\Diactoros\Uri;

  public function process(ServerRequestInterface $request, RequestHandlerInterface $handler) : ResponseInterface
  {
      $requestUri = null;

      $httpXRewriteUrl = $request->getHeaderLine('X-Rewrite-Url');
      if ($httpXRewriteUrl !== null) {
          $requestUri = $httpXRewriteUrl;
      }

      $httpXOriginalUrl = $request->getHeaderLine('X-Original-Url');
      if ($httpXOriginalUrl !== null) {
          $requestUri = $httpXOriginalUrl;
      }

      if ($requestUri !== null) {
          $request = $request->withUri(new Uri($requestUri));
      }

      return $handler->handle($request);
  }
  ```

  If you use middleware such as the above, make sure you also instruct your web
  server to strip any incoming headers of the same name so that you can
  guarantee they are issued by the ISAPI_Rewrite module.

### Deprecated

- Nothing.

### Removed

- Nothing.

### Fixed

- Nothing.

## 1.8.3 - 2018-07-24

### Added

- Nothing.

### Changed

- Nothing.

### Deprecated

- Nothing.

### Removed

- Nothing.

### Fixed

- [zendframework/zend-diactoros#321](https://github.com/zendframework/zend-diactoros/pull/321) updates the logic in `Uri::withPort()` to ensure that it checks that the
  value provided is either an integer or a string integer, as only those values
  may be cast to integer without data loss.

- [zendframework/zend-diactoros#320](https://github.com/zendframework/zend-diactoros/pull/320) adds checking within `Response` to ensure that the provided reason
  phrase is a string; an `InvalidArgumentException` is now raised if it is not. This change
  ensures the class adheres strictly to the PSR-7 specification.

- [zendframework/zend-diactoros#319](https://github.com/zendframework/zend-diactoros/pull/319) provides a fix to `Laminas\Diactoros\Response` that ensures that the status
  code returned is _always_ an integer (and never a string containing an
  integer), thus ensuring it strictly adheres to the PSR-7 specification.

## 1.8.2 - 2018-07-19

### Added

- Nothing.

### Changed

- Nothing.

### Deprecated

- Nothing.

### Removed

- Nothing.

### Fixed

- [zendframework/zend-diactoros#318](https://github.com/zendframework/zend-diactoros/pull/318) fixes the logic for discovering whether an HTTPS scheme is in play
  to be case insensitive when comparing header and SAPI values, ensuring no
  false negative lookups occur.

- [zendframework/zend-diactoros#314](https://github.com/zendframework/zend-diactoros/pull/314) modifies error handling around opening a file resource within
  `Laminas\Diactoros\Stream::setStream()` to no longer use the second argument to
  `set_error_handler()`, and instead check the error type in the handler itself;
  this fixes an issue when the handler is nested inside another error handler,
  which currently has buggy behavior within the PHP engine.

## 1.8.1 - 2018-07-09

### Added

- Nothing.

### Changed

- [zendframework/zend-diactoros#313](https://github.com/zendframework/zend-diactoros/pull/313) changes the reason phrase associated with the status code 425
  to "Too Early", corresponding to a new definition of the code as specified by the IANA.

### Deprecated

- Nothing.

### Removed

- Nothing.

### Fixed

- [zendframework/zend-diactoros#312](https://github.com/zendframework/zend-diactoros/pull/312) fixes how the `normalizeUploadedFiles()` utility function handles nested trees of
  uploaded files, ensuring it detects them properly.

## 1.8.0 - 2018-06-27

### Added

- [zendframework/zend-diactoros#307](https://github.com/zendframework/zend-diactoros/pull/307) adds the following functions under the `Laminas\Diactoros` namespace, each of
  which may be used to derive artifacts from SAPI supergloabls for the purposes
  of generating a `ServerRequest` instance:
  - `normalizeServer(array $server, callable $apacheRequestHeaderCallback = null) : array`
    (main purpose is to aggregate the `Authorization` header in the SAPI params
    when under Apache)
  - `marshalProtocolVersionFromSapi(array $server) : string`
  - `marshalMethodFromSapi(array $server) : string`
  - `marshalUriFromSapi(array $server, array $headers) : Uri`
  - `marshalHeadersFromSapi(array $server) : array`
  - `parseCookieHeader(string $header) : array`
  - `createUploadedFile(array $spec) : UploadedFile` (creates the instance from
    a normal `$_FILES` entry)
  - `normalizeUploadedFiles(array $files) : UploadedFileInterface[]` (traverses
    a potentially nested array of uploaded file instances and/or `$_FILES`
    entries, including those aggregated under mod_php, php-fpm, and php-cgi in
    order to create a flat array of `UploadedFileInterface` instances to use in a
    request)

### Changed

- Nothing.

### Deprecated

- [zendframework/zend-diactoros#307](https://github.com/zendframework/zend-diactoros/pull/307) deprecates `ServerRequestFactory::normalizeServer()`; the method is
  no longer used internally, and users should instead use `Laminas\Diactoros\normalizeServer()`,
  to which it proxies.

- [zendframework/zend-diactoros#307](https://github.com/zendframework/zend-diactoros/pull/307) deprecates `ServerRequestFactory::marshalHeaders()`; the method is
  no longer used internally, and users should instead use `Laminas\Diactoros\marshalHeadersFromSapi()`,
  to which it proxies.

- [zendframework/zend-diactoros#307](https://github.com/zendframework/zend-diactoros/pull/307) deprecates `ServerRequestFactory::marshalUriFromServer()`; the method
  is no longer used internally. Users should use `marshalUriFromSapi()` instead.

- [zendframework/zend-diactoros#307](https://github.com/zendframework/zend-diactoros/pull/307) deprecates `ServerRequestFactory::marshalRequestUri()`. the method is no longer
  used internally, and currently proxies to `marshalUriFromSapi()`, pulling the
  discovered path from the `Uri` instance returned by that function. Users
  should use `marshalUriFromSapi()` instead.

- [zendframework/zend-diactoros#307](https://github.com/zendframework/zend-diactoros/pull/307) deprecates `ServerRequestFactory::marshalHostAndPortFromHeaders()`; the method
  is no longer used internally, and currently proxies to `marshalUriFromSapi()`,
  pulling the discovered host and port from the `Uri` instance returned by that
  function. Users should use `marshalUriFromSapi()` instead.

- [zendframework/zend-diactoros#307](https://github.com/zendframework/zend-diactoros/pull/307) deprecates `ServerRequestFactory::getHeader()`; the method is no longer
  used internally. Users should copy and paste the functionality into their own
  applications if needed, or rely on headers from a fully-populated `Uri`
  instance instead.

- [zendframework/zend-diactoros#307](https://github.com/zendframework/zend-diactoros/pull/307) deprecates `ServerRequestFactory::stripQueryString()`; the method is no longer
  used internally, and users can mimic the functionality via the expression
  `$path = explode('?', $path, 2)[0];`.

- [zendframework/zend-diactoros#307](https://github.com/zendframework/zend-diactoros/pull/307) deprecates `ServerRequestFactory::normalizeFiles()`; the functionality
  is no longer used internally, and users can use `normalizeUploadedFiles()` as
  a replacement.

- [zendframework/zend-diactoros#303](https://github.com/zendframework/zend-diactoros/pull/303) deprecates `Laminas\Diactoros\Response\EmitterInterface` and its various implementations. These are now provided via the
  [laminas/laminas-httphandlerrunner](https://docs.laminas.dev/laminas-httphandlerrunner) package as 1:1 substitutions.

- [zendframework/zend-diactoros#303](https://github.com/zendframework/zend-diactoros/pull/303) deprecates the `Laminas\Diactoros\Server` class. Users are directed to the `RequestHandlerRunner` class from the
  [laminas/laminas-httphandlerrunner](https://docs.laminas.dev/laminas-httphandlerrunner) package as an alternative.

### Removed

- Nothing.

### Fixed

- Nothing.

## 1.7.2 - 2018-05-29

### Added

- Nothing.

### Changed

- Nothing.

### Deprecated

- Nothing.

### Removed

- Nothing.

### Fixed

- [zendframework/zend-diactoros#301](https://github.com/zendframework/zend-diactoros/pull/301) adds stricter comparisons within the `uri` class to ensure non-empty
  values are not treated as empty.

## 1.7.1 - 2018-02-26

### Added

- Nothing.

### Changed

- [zendframework/zend-diactoros#293](https://github.com/zendframework/zend-diactoros/pull/293) updates
  `Uri::getHost()` to cast the value via `strtolower()` before returning it.
  While this represents a change, it is fixing a bug in our implementation:
  the PSR-7 specification for the method, which follows IETF RFC 3986 section
  3.2.2, requires that the host name be normalized to lowercase.

### Deprecated

- Nothing.

### Removed

- Nothing.

### Fixed

- [zendframework/zend-diactoros#290](https://github.com/zendframework/zend-diactoros/pull/290) fixes
  `Stream::getSize()` such that it checks that the result of `fstat` was
  succesful before attempting to return its `size` member; in the case of an
  error, it now returns `null`.

## 1.7.0 - 2018-01-04

### Added

- [zendframework/zend-diactoros#285](https://github.com/zendframework/zend-diactoros/pull/285) adds a new
  custom response type, `Laminas\Diactoros\Response\XmlResponse`, for generating
  responses representing XML. Usage is the same as with the `HtmlResponse` or
  `TextResponse`; the response generated will have a `Content-Type:
  application/xml` header by default.

- [zendframework/zend-diactoros#280](https://github.com/zendframework/zend-diactoros/pull/280) adds the
  response status code/phrase pairing "103 Early Hints" to the
  `Response::$phrases` property. This is a new status proposed via
  [RFC 8297](https://datatracker.ietf.org/doc/rfc8297/).

- [zendframework/zend-diactoros#279](https://github.com/zendframework/zend-diactoros/pull/279) adds explicit
  support for PHP 7.2; previously, we'd allowed build failures, though none
  occured; we now require PHP 7.2 builds to pass.

### Changed

- Nothing.

### Deprecated

- Nothing.

### Removed

- Nothing.

### Fixed

- Nothing.

## 1.6.1 - 2017-10-12

### Added

- Nothing.

### Changed

- [zendframework/zend-diactoros#273](https://github.com/zendframework/zend-diactoros/pull/273) updates each
  of the SAPI emitter implementations to emit the status line after emitting
  other headers; this is done to ensure that the status line is not overridden
  by PHP.

### Deprecated

- Nothing.

### Removed

- Nothing.

### Fixed

- [zendframework/zend-diactoros#273](https://github.com/zendframework/zend-diactoros/pull/273) modifies how
  the `SapiEmitterTrait` calls `header()` to ensure that a response code is
  _always_ passed as the third argument; this is done to prevent PHP from
  silently overriding it.

## 1.6.0 - 2017-09-13

### Added

- Nothing.

### Changed

- [zendframework/zend-diactoros#270](https://github.com/zendframework/zend-diactoros/pull/270) changes the
  behavior of `Laminas\Diactoros\Server`: it no longer creates an output buffer.

- [zendframework/zend-diactoros#270](https://github.com/zendframework/zend-diactoros/pull/270) changes the
  behavior of the two SAPI emitters in two backwards-incompatible ways:

  - They no longer auto-inject a `Content-Length` header. If you need this
    functionality, mezzio/mezzio-helpers 4.1+ provides it via
    `Mezzio\Helper\ContentLengthMiddleware`.

  - They no longer flush the output buffer. Instead, if headers have been sent,
    or the output buffer exists and has a non-zero length, the emitters raise an
    exception, as mixed PSR-7/output buffer content creates a blocking issue.
    If you are emitting content via `echo`, `print`, `var_dump`, etc., or not
    catching PHP errors or exceptions, you will need to either fix your
    application to always work with a PSR-7 response, or provide your own
    emitters that allow mixed output mechanisms.

### Deprecated

- Nothing.

### Removed

- Nothing.

### Fixed

- Nothing.

## 1.5.0 - 2017-08-22

### Added

- [zendframework/zend-diactoros#205](https://github.com/zendframework/zend-diactoros/pull/205) adds support
  for PHP 7.2.

- [zendframework/zend-diactoros#250](https://github.com/zendframework/zend-diactoros/pull/250) adds a new
  API to `JsonResponse` to avoid the need for decoding the response body in
  order to make changes to the underlying content. New methods include:
  - `getPayload()`: retrieve the unencoded payload.
  - `withPayload($data)`: create a new instance with the given data.
  - `getEncodingOptions()`: retrieve the flags to use when encoding the payload
    to JSON.
  - `withEncodingOptions(int $encodingOptions)`: create a new instance that uses
    the provided flags when encoding the payload to JSON.

### Changed

- [zendframework/zend-diactoros#249](https://github.com/zendframework/zend-diactoros/pull/249) changes the
  behavior of the various `Uri::with*()` methods slightly: if the value
  represents no change, these methods will return the same instance instead of a
  new one.

- [zendframework/zend-diactoros#248](https://github.com/zendframework/zend-diactoros/pull/248) changes the
  behavior of `Uri::getUserInfo()` slightly: it now (correctly) returns the
  percent-encoded values for the user and/or password, per RFC 3986 Section
  3.2.1. `withUserInfo()` will percent-encode values, using a mechanism that
  prevents double-encoding.

- [zendframework/zend-diactoros#243](https://github.com/zendframework/zend-diactoros/pull/243) changes the
  exception messages thrown by `UploadedFile::getStream()` and `moveTo()` when
  an upload error exists to include details about the upload error.

- [zendframework/zend-diactoros#233](https://github.com/zendframework/zend-diactoros/pull/233) adds a new
  argument to `SapiStreamEmitter::emit`, `$maxBufferLevel` **between** the
  `$response` and `$maxBufferLength` arguments. This was done because the
  `Server::listen()` method passes only the response and `$maxBufferLevel` to
  emitters; previously, this often meant that streams were being chunked 2 bytes
  at a time versus the expected default of 8kb.

  If you were calling the `SapiStreamEmitter::emit()` method manually
  previously, you will need to update your code.

### Deprecated

- Nothing.

### Removed

- [zendframework/zend-diactoros#205](https://github.com/zendframework/zend-diactoros/pull/205) and
  [zendframework/zend-diactoros#243](https://github.com/zendframework/zend-diactoros/pull/243) **remove
  support for PHP versions prior to 5.6 as well as HHVM**.

### Fixed

- [zendframework/zend-diactoros#248](https://github.com/zendframework/zend-diactoros/pull/248) fixes how the
  `Uri` class provides user-info within the URI authority; the value is now
  correctly percent-encoded , per RFC 3986 Section 3.2.1.

## 1.4.1 - 2017-08-17

### Added

- Nothing.

### Deprecated

- Nothing.

### Removed

- [zendframework/zend-diactoros#260](https://github.com/zendframework/zend-diactoros/pull/260) removes
  support for HHVM, as tests have failed against it for some time.

### Fixed

- [zendframework/zend-diactoros#247](https://github.com/zendframework/zend-diactoros/pull/247) fixes the
  `Stream` and `RelativeStream` `__toString()` method implementations to check
  if the stream `isSeekable()` before attempting to `rewind()` it, ensuring that
  the method does not raise exceptions (PHP does not allow exceptions in that
  method). In particular, this fixes an issue when using AWS S3 streams.

- [zendframework/zend-diactoros#252](https://github.com/zendframework/zend-diactoros/pull/252) provides a
  fix to the `SapiEmitterTrait` to ensure that any `Set-Cookie` headers in the
  response instance do not override those set by PHP when a session is created
  and/or regenerated.

- [zendframework/zend-diactoros#257](https://github.com/zendframework/zend-diactoros/pull/257) provides a
  fix for the `PhpInputStream::read()` method to ensure string content that
  evaluates as empty (including `0`) is still cached.

- [zendframework/zend-diactoros#258](https://github.com/zendframework/zend-diactoros/pull/258) updates the
  `Uri::filterPath()` method to allow parens within a URI path, per [RFC 3986
  section 3.3](https://tools.ietf.org/html/rfc3986#section-3.3) (parens are
  within the character set "sub-delims").

## 1.4.0 - 2017-04-06

### Added

- [zendframework/zend-diactoros#219](https://github.com/zendframework/zend-diactoros/pull/219) adds two new
  classes, `Laminas\Diactoros\Request\ArraySerializer` and
  `Laminas\Diactoros\Response\ArraySerializer`. Each exposes the static methods
  `toArray()` and `fromArray()`, allowing de/serialization of messages from and
  to arrays.

- [zendframework/zend-diactoros#236](https://github.com/zendframework/zend-diactoros/pull/236) adds two new
  constants to the `Response` class: `MIN_STATUS_CODE_VALUE` and
  `MAX_STATUS_CODE_VALUE`.

### Changes

- [zendframework/zend-diactoros#240](https://github.com/zendframework/zend-diactoros/pull/240) changes the
  behavior of `ServerRequestFactory::fromGlobals()` when no `$cookies` argument
  is present. Previously, it would use `$_COOKIES`; now, if a `Cookie` header is
  present, it will parse and use that to populate the instance instead.

  This change allows utilizing cookies that contain period characters (`.`) in
  their names (PHP's built-in cookie handling renames these to replace `.` with
  `_`, which can lead to synchronization issues with clients).

- [zendframework/zend-diactoros#235](https://github.com/zendframework/zend-diactoros/pull/235) changes the
  behavior of `Uri::__toString()` to better follow proscribed behavior in PSR-7.
  In particular, prior to this release, if a scheme was missing but an authority
  was present, the class was incorrectly returning a value that did not include
  a `//` prefix. As of this release, it now does this correctly.

### Deprecated

- Nothing.

### Removed

- Nothing.

### Fixed

- Nothing.

## 1.3.11 - 2017-04-06

### Added

- Nothing.

### Changes

- [zendframework/zend-diactoros#241](https://github.com/zendframework/zend-diactoros/pull/241) changes the
  constraint by which the package provides `psr/http-message-implementation` to
  simply `1.0` instead of `~1.0.0`, to follow how other implementations provide
  PSR-7.

### Deprecated

- Nothing.

### Removed

- Nothing.

### Fixed

- [zendframework/zend-diactoros#161](https://github.com/zendframework/zend-diactoros/pull/161) adds
  additional validations to header names and values to ensure no malformed values
  are provided.

- [zendframework/zend-diactoros#234](https://github.com/zendframework/zend-diactoros/pull/234) fixes a
  number of reason phrases in the `Response` instance, and adds automation from
  the canonical IANA sources to ensure any new phrases added are correct.

## 1.3.10 - 2017-01-23

### Added

- Nothing.

### Deprecated

- Nothing.

### Removed

- Nothing.

### Fixed

- [zendframework/zend-diactoros#226](https://github.com/zendframework/zend-diactoros/pull/226) fixed an
  issue with the `SapiStreamEmitter` causing the response body to be cast
  to `(string)` and also be read as a readable stream, potentially producing
  double output.

## 1.3.9 - 2017-01-17

### Added

- Nothing.

### Deprecated

- Nothing.

### Removed

- Nothing.

### Fixed

- [zendframework/zend-diactoros#223](https://github.com/zendframework/zend-diactoros/issues/223)
  [zendframework/zend-diactoros#224](https://github.com/zendframework/zend-diactoros/pull/224) fixed an issue
  with the `SapiStreamEmitter` consuming too much memory when producing output
  for readable bodies.

## 1.3.8 - 2017-01-05

### Added

- Nothing.

### Deprecated

- Nothing.

### Removed

- Nothing.

### Fixed

- [zendframework/zend-diactoros#222](https://github.com/zendframework/zend-diactoros/pull/222) fixes the
  `SapiStreamEmitter`'s handling of the `Content-Range` header to properly only
  emit a range of bytes if the header value is in the form `bytes {first-last}/length`.
  This allows using other range units, such as `items`, without incorrectly
  emitting truncated content.

## 1.3.7 - 2016-10-11

### Added

- [zendframework/zend-diactoros#208](https://github.com/zendframework/zend-diactoros/pull/208) adds several
  missing response codes to `Laminas\Diactoros\Response`, including:
  - 226 ('IM used')
  - 308 ('Permanent Redirect')
  - 444 ('Connection Closed Without Response')
  - 499 ('Client Closed Request')
  - 510 ('Not Extended')
  - 599 ('Network Connect Timeout Error')
- [zendframework/zend-diactoros#211](https://github.com/zendframework/zend-diactoros/pull/211) adds support
  for UTF-8 characters in query strings handled by `Laminas\Diactoros\Uri`.

### Deprecated

- Nothing.

### Removed

- Nothing.

### Fixed

- Nothing.

## 1.3.6 - 2016-09-07

### Added

- [zendframework/zend-diactoros#170](https://github.com/zendframework/zend-diactoros/pull/170) prepared
  documentation for publication at https://docs.laminas.dev/laminas-diactoros/
- [zendframework/zend-diactoros#165](https://github.com/zendframework/zend-diactoros/pull/165) adds support
  for Apache `REDIRECT_HTTP_*` header detection in the `ServerRequestFactory`.
- [zendframework/zend-diactoros#166](https://github.com/zendframework/zend-diactoros/pull/166) adds support
  for UTF-8 characters in URI paths.
- [zendframework/zend-diactoros#204](https://github.com/zendframework/zend-diactoros/pull/204) adds testing
  against PHP 7.1 release-candidate builds.

### Deprecated

- Nothing.

### Removed

- Nothing.

### Fixed

- [zendframework/zend-diactoros#186](https://github.com/zendframework/zend-diactoros/pull/186) fixes a typo
  in a variable name within the `SapiStreamEmitter`.
- [zendframework/zend-diactoros#200](https://github.com/zendframework/zend-diactoros/pull/200) updates the
  `SapiStreamEmitter` to implement a check for `isSeekable()` prior to attempts
  to rewind; this allows it to work with non-seekable streams such as the
  `CallbackStream`.
- [zendframework/zend-diactoros#169](https://github.com/zendframework/zend-diactoros/pull/169) ensures that
  response serialization always provides a `\r\n\r\n` sequence following the
  headers, even when no message body is present, to ensure it conforms with RFC
  7230.
- [zendframework/zend-diactoros#175](https://github.com/zendframework/zend-diactoros/pull/175) updates the
  `Request` class to set the `Host` header from the URI host if no header is
  already present. (Ensures conformity with PSR-7 specification.)
- [zendframework/zend-diactoros#197](https://github.com/zendframework/zend-diactoros/pull/197) updates the
  `Uri` class to ensure that string serialization does not include a colon after
  the host name if no port is present in the instance.

## 1.3.5 - 2016-03-17

### Added

- Nothing.

### Deprecated

- Nothing.

### Removed

- Nothing.

### Fixed

- [zendframework/zend-diactoros#160](https://github.com/zendframework/zend-diactoros/pull/160) fixes HTTP
  protocol detection in the `ServerRequestFactory` to work correctly with HTTP/2.

## 1.3.4 - 2016-03-17

### Added

- [zendframework/zend-diactoros#119](https://github.com/zendframework/zend-diactoros/pull/119) adds the 451
  (Unavailable for Legal Reasons) status code to the `Response` class.

### Deprecated

- Nothing.

### Removed

- Nothing.

### Fixed

- [zendframework/zend-diactoros#117](https://github.com/zendframework/zend-diactoros/pull/117) provides
  validation of the HTTP protocol version.
- [zendframework/zend-diactoros#127](https://github.com/zendframework/zend-diactoros/pull/127) now properly
  removes attributes with `null` values when calling `withoutAttribute()`.
- [zendframework/zend-diactoros#132](https://github.com/zendframework/zend-diactoros/pull/132) updates the
  `ServerRequestFactory` to marshal the request path fragment, if present.
- [zendframework/zend-diactoros#142](https://github.com/zendframework/zend-diactoros/pull/142) updates the
  exceptions thrown by `HeaderSecurity` to include the header name and/or
  value.
- [zendframework/zend-diactoros#148](https://github.com/zendframework/zend-diactoros/pull/148) fixes several
  stream operations to ensure they raise exceptions when the internal pointer
  is at an invalid position.
- [zendframework/zend-diactoros#151](https://github.com/zendframework/zend-diactoros/pull/151) ensures
  URI fragments are properly encoded.

## 1.3.3 - 2016-01-04

### Added

- Nothing.

### Deprecated

- Nothing.

### Removed

- Nothing.

### Fixed

- [zendframework/zend-diactoros#135](https://github.com/zendframework/zend-diactoros/pull/135) fixes the
  behavior of `ServerRequestFactory::marshalHeaders()` to no longer omit
  `Cookie` headers from the aggregated headers. While the values are parsed and
  injected into the cookie params, it's useful to have access to the raw headers
  as well.

## 1.3.2 - 2015-12-22

### Added

- [zendframework/zend-diactoros#124](https://github.com/zendframework/zend-diactoros/pull/124) adds four
  more optional arguments to the `ServerRequest` constructor:
  - `array $cookies`
  - `array $queryParams`
  - `null|array|object $parsedBody`
  - `string $protocolVersion`
  `ServerRequestFactory` was updated to pass values for each of these parameters
  when creating an instance, instead of using the related `with*()` methods on
  an instance.

### Deprecated

- Nothing.

### Removed

- Nothing.

### Fixed

- [zendframework/zend-diactoros#122](https://github.com/zendframework/zend-diactoros/pull/122) updates the
  `ServerRequestFactory` to retrieve the HTTP protocol version and inject it in
  the generated `ServerRequest`, which previously was not performed.

## 1.3.1 - 2015-12-16

### Added

- Nothing.

### Deprecated

- Nothing.

### Removed

- Nothing.

### Fixed

- [zendframework/zend-diactoros#113](https://github.com/zendframework/zend-diactoros/pull/113) fixes an
  issue in the response serializer, ensuring that the status code in the
  deserialized response is an integer.
- [zendframework/zend-diactoros#115](https://github.com/zendframework/zend-diactoros/pull/115) fixes an
  issue in the various text-basd response types (`TextResponse`, `HtmlResponse`,
  and `JsonResponse`); due to the fact that the constructor was not
  rewinding the message body stream, `getContents()` was thus returning `null`,
  as the pointer was at the end of the stream. The constructor now rewinds the
  stream after populating it in the constructor.

## 1.3.0 - 2015-12-15

### Added

- [zendframework/zend-diactoros#110](https://github.com/zendframework/zend-diactoros/pull/110) adds
  `Laminas\Diactoros\Response\SapiEmitterTrait`, which provides the following
  private method definitions:
  - `injectContentLength()`
  - `emitStatusLine()`
  - `emitHeaders()`
  - `flush()`
  - `filterHeader()`
  The `SapiEmitter` implementation has been updated to remove those methods and
  instead compose the trait.
- [zendframework/zend-diactoros#111](https://github.com/zendframework/zend-diactoros/pull/111) adds
  a new emitter implementation, `SapiStreamEmitter`; this emitter type will
  loop through the stream instead of emitting it in one go, and supports content
  ranges.

### Deprecated

- Nothing.

### Removed

- Nothing.

### Fixed

- Nothing.

## 1.2.1 - 2015-12-15

### Added

- Nothing.

### Deprecated

- Nothing.

### Removed

- Nothing.

### Fixed

- [zendframework/zend-diactoros#101](https://github.com/zendframework/zend-diactoros/pull/101) fixes the
  `withHeader()` implementation to ensure that if the header existed previously
  but using a different casing strategy, the previous version will be removed
  in the cloned instance.
- [zendframework/zend-diactoros#103](https://github.com/zendframework/zend-diactoros/pull/103) fixes the
  constructor of `Response` to ensure that null status codes are not possible.
- [zendframework/zend-diactoros#99](https://github.com/zendframework/zend-diactoros/pull/99) fixes
  validation of header values submitted via request and response constructors as
  follows:
  - numeric (integer and float) values are now properly allowed (this solves
    some reported issues with setting Content-Length headers)
  - invalid header names (non-string values or empty strings) now raise an
    exception.
  - invalid individual header values (non-string, non-numeric) now raise an
    exception.

## 1.2.0 - 2015-11-24

### Added

- [zendframework/zend-diactoros#88](https://github.com/zendframework/zend-diactoros/pull/88) updates the
  `SapiEmitter` to emit a `Content-Length` header with the content length as
  reported by the response body stream, assuming that
  `StreamInterface::getSize()` returns an integer.
- [zendframework/zend-diactoros#77](https://github.com/zendframework/zend-diactoros/pull/77) adds a new
  response type, `Laminas\Diactoros\Response\TextResponse`, for returning plain
  text responses. By default, it sets the content type to `text/plain;
  charset=utf-8`; per the other response types, the signature is `new
  TextResponse($text, $status = 200, array $headers = [])`.
- [zendframework/zend-diactoros#90](https://github.com/zendframework/zend-diactoros/pull/90) adds a new
  `Laminas\Diactoros\CallbackStream`, allowing you to back a stream with a PHP
  callable (such as a generator) to generate the message content. Its
  constructor accepts the callable: `$stream = new CallbackStream($callable);`

### Deprecated

- Nothing.

### Removed

- Nothing.

### Fixed

- [zendframework/zend-diactoros#77](https://github.com/zendframework/zend-diactoros/pull/77) updates the
  `HtmlResponse` to set the charset to utf-8 by default (if no content type
  header is provided at instantiation).

## 1.1.4 - 2015-10-16

### Added

- [zendframework/zend-diactoros#98](https://github.com/zendframework/zend-diactoros/pull/98) adds
  `JSON_UNESCAPED_SLASHES` to the default `json_encode` flags used by
  `Laminas\Diactoros\Response\JsonResponse`.

### Deprecated

- Nothing.

### Removed

- Nothing.

### Fixed

- [zendframework/zend-diactoros#96](https://github.com/zendframework/zend-diactoros/pull/96) updates
  `withPort()` to allow `null` port values (indicating usage of default for
  the given scheme).
- [zendframework/zend-diactoros#91](https://github.com/zendframework/zend-diactoros/pull/91) fixes the
  logic of `withUri()` to do a case-insensitive check for an existing `Host`
  header, replacing it with the new one.

## 1.1.3 - 2015-08-10

### Added

- [zendframework/zend-diactoros#73](https://github.com/zendframework/zend-diactoros/pull/73) adds caching of
  the vendor directory to the Travis-CI configuration, to speed up builds.

### Deprecated

- Nothing.

### Removed

- Nothing.

### Fixed

- [zendframework/zend-diactoros#71](https://github.com/zendframework/zend-diactoros/pull/71) fixes the
  docblock of the `JsonResponse` constructor to typehint the `$data` argument
  as `mixed`.
- [zendframework/zend-diactoros#73](https://github.com/zendframework/zend-diactoros/pull/73) changes the
  behavior in `Request` such that if it marshals a stream during instantiation,
  the stream is marked as writeable (specifically, mode `wb+`).
- [zendframework/zend-diactoros#85](https://github.com/zendframework/zend-diactoros/pull/85) updates the
  behavior of `Laminas\Diactoros\Uri`'s various `with*()` methods that are
  documented as accepting strings to raise exceptions on non-string input.
  Previously, several simply passed non-string input on verbatim, others
  normalized the input, and a few correctly raised the exceptions. Behavior is
  now consistent across each.
- [zendframework/zend-diactoros#87](https://github.com/zendframework/zend-diactoros/pull/87) fixes
  `UploadedFile` to ensure that `moveTo()` works correctly in non-SAPI
  environments when the file provided to the constructor is a path.

## 1.1.2 - 2015-07-12

### Added

- Nothing.

### Deprecated

- Nothing.

### Removed

- Nothing.

### Fixed

- [zendframework/zend-diactoros#67](https://github.com/zendframework/zend-diactoros/pull/67) ensures that
  the `Stream` class only accepts `stream` resources, not any resource.

## 1.1.1 - 2015-06-25

### Added

- Nothing.

### Deprecated

- Nothing.

### Removed

- Nothing.

### Fixed

- [zendframework/zend-diactoros#64](https://github.com/zendframework/zend-diactoros/pull/64) fixes the
  behavior of `JsonResponse` with regards to serialization of `null` and scalar
  values; the new behavior is to serialize them verbatim, without any casting.

## 1.1.0 - 2015-06-24

### Added

- [zendframework/zend-diactoros#52](https://github.com/zendframework/zend-diactoros/pull/52),
  [zendframework/zend-diactoros#58](https://github.com/zendframework/zend-diactoros/pull/58),
  [zendframework/zend-diactoros#59](https://github.com/zendframework/zend-diactoros/pull/59), and
  [zendframework/zend-diactoros#61](https://github.com/zendframework/zend-diactoros/pull/61) create several
  custom response types for simplifying response creation:

  - `Laminas\Diactoros\Response\HtmlResponse` accepts HTML content via its
    constructor, and sets the `Content-Type` to `text/html`.
  - `Laminas\Diactoros\Response\JsonResponse` accepts data to serialize to JSON via
    its constructor, and sets the `Content-Type` to `application/json`.
  - `Laminas\Diactoros\Response\EmptyResponse` allows creating empty, read-only
    responses, with a default status code of 204.
  - `Laminas\Diactoros\Response\RedirectResponse` allows specifying a URI for the
    `Location` header in the constructor, with a default status code of 302.

  Each also accepts an optional status code, and optional headers (which can
  also be used to provide an alternate `Content-Type` in the case of the HTML
  and JSON responses).

### Deprecated

- Nothing.

### Removed

- [zendframework/zend-diactoros#43](https://github.com/zendframework/zend-diactoros/pull/43) removed both
  `ServerRequestFactory::marshalUri()` and `ServerRequestFactory::marshalHostAndPort()`,
  which were deprecated prior to the 1.0 release.

### Fixed

- [zendframework/zend-diactoros#29](https://github.com/zendframework/zend-diactoros/pull/29) fixes request
  method validation to allow any valid token as defined by [RFC
  7230](http://tools.ietf.org/html/rfc7230#appendix-B). This allows usage of
  custom request methods, vs a static, hard-coded list.

## 1.0.5 - 2015-06-24

### Added

- Nothing.

### Deprecated

- Nothing.

### Removed

- Nothing.

### Fixed

- [zendframework/zend-diactoros#60](https://github.com/zendframework/zend-diactoros/pull/60) fixes
  the behavior of `UploadedFile` when the `$errorStatus` provided at
  instantiation is not `UPLOAD_ERR_OK`. Prior to the fix, an
  `InvalidArgumentException` would occur at instantiation due to the fact that
  the upload file was missing or invalid. With the fix, no exception is raised
  until a call to `moveTo()` or `getStream()` is made.

## 1.0.4 - 2015-06-23

This is a security release.

A patch has been applied to `Laminas\Diactoros\Uri::filterPath()` that ensures that
paths can only begin with a single leading slash. This prevents the following
potential security issues:

- XSS vectors. If the URI path is used for links or form targets, this prevents
  cases where the first segment of the path resembles a domain name, thus
  creating scheme-relative links such as `//example.com/foo`. With the patch,
  the leading double slash is reduced to a single slash, preventing the XSS
  vector.
- Open redirects. If the URI path is used for `Location` or `Link` headers,
  without a scheme and authority, potential for open redirects exist if clients
  do not prepend the scheme and authority. Again, preventing a double slash
  corrects the vector.

If you are using `Laminas\Diactoros\Uri` for creating links, form targets, or
redirect paths, and only using the path segment, we recommend upgrading
immediately.

### Added

- [zendframework/zend-diactoros#25](https://github.com/zendframework/zend-diactoros/pull/25) adds
  documentation. Documentation is written in markdown, and can be converted to
  HTML using [bookdown](http://bookdown.io). New features now MUST include
  documentation for acceptance.

### Deprecated

- Nothing.

### Removed

- Nothing.

### Fixed

- [zendframework/zend-diactoros#51](https://github.com/zendframework/zend-diactoros/pull/51) fixes
  `MessageTrait::getHeaderLine()` to return an empty string instead of `null` if
  the header is undefined (which is the behavior specified in PSR-7).
- [zendframework/zend-diactoros#57](https://github.com/zendframework/zend-diactoros/pull/57) fixes the
  behavior of how the `ServerRequestFactory` marshals upload files when they are
  represented as a nested associative array.
- [zendframework/zend-diactoros#49](https://github.com/zendframework/zend-diactoros/pull/49) provides several
  fixes that ensure that Diactoros complies with the PSR-7 specification:
  - `MessageInterface::getHeaderLine()` MUST return a string (that string CAN be
    empty). Previously, Diactoros would return `null`.
  - If no `Host` header is set, the `$preserveHost` flag MUST be ignored when
    calling `withUri()` (previously, Diactoros would not set the `Host` header
    if `$preserveHost` was `true`, but no `Host` header was present).
  - The request method MUST be a string; it CAN be empty. Previously, Diactoros
    would return `null`.
  - The request MUST return a `UriInterface` instance from `getUri()`; that
    instance CAN be empty. Previously, Diactoros would return `null`; now it
    lazy-instantiates an empty `Uri` instance on initialization.
- [ZF2015-05](https://getlaminas.org/security/advisory/ZF2015-05) was
  addressed by altering `Uri::filterPath()` to prevent emitting a path prepended
  with multiple slashes.

## 1.0.3 - 2015-06-04

### Added

- [zendframework/zend-diactoros#48](https://github.com/zendframework/zend-diactoros/pull/48) drops the
  minimum supported PHP version to 5.4, to allow an easier upgrade path for
  Symfony 2.7 users, and potential Drupal 8 usage.

### Deprecated

- Nothing.

### Removed

- Nothing.

### Fixed

- Nothing.

## 1.0.2 - 2015-06-04

### Added

- [zendframework/zend-diactoros#27](https://github.com/zendframework/zend-diactoros/pull/27) adds phonetic
  pronunciation of "Diactoros" to the README file.
- [zendframework/zend-diactoros#36](https://github.com/zendframework/zend-diactoros/pull/36) adds property
  annotations to the class-level docblock of `Laminas\Diactoros\RequestTrait` to
  ensure properties inherited from the `MessageTrait` are inherited by
  implementations.

### Deprecated

- Nothing.

### Removed

- Nothing.
-
### Fixed

- [zendframework/zend-diactoros#41](https://github.com/zendframework/zend-diactoros/pull/41) fixes the
  namespace for test files to begin with `LaminasTest` instead of `Laminas`.
- [zendframework/zend-diactoros#46](https://github.com/zendframework/zend-diactoros/pull/46) ensures that
  the cookie and query params for the `ServerRequest` implementation are
  initialized as arrays.
- [zendframework/zend-diactoros#47](https://github.com/zendframework/zend-diactoros/pull/47) modifies the
  internal logic in `HeaderSecurity::isValid()` to use a regular expression
  instead of character-by-character comparisons, improving performance.

## 1.0.1 - 2015-05-26

### Added

- [zendframework/zend-diactoros#10](https://github.com/zendframework/zend-diactoros/pull/10) adds
  `Laminas\Diactoros\RelativeStream`, which will return stream contents relative to
  a given offset (i.e., a subset of the stream).  `AbstractSerializer` was
  updated to create a `RelativeStream` when creating the body of a message,
  which will prevent duplication of the stream in-memory.
- [zendframework/zend-diactoros#21](https://github.com/zendframework/zend-diactoros/pull/21) adds a
  `.gitattributes` file that excludes directories and files not needed for
  production; this will further minify the package for production use cases.

### Deprecated

- Nothing.

### Removed

- Nothing.

### Fixed

- [zendframework/zend-diactoros#9](https://github.com/zendframework/zend-diactoros/pull/9) ensures that
  attributes are initialized to an empty array, ensuring that attempts to
  retrieve single attributes when none are defined will not produce errors.
- [zendframework/zend-diactoros#14](https://github.com/zendframework/zend-diactoros/pull/14) updates
  `Laminas\Diactoros\Request` to use a `php://temp` stream by default instead of
  `php://memory`, to ensure requests do not create an out-of-memory condition.
- [zendframework/zend-diactoros#15](https://github.com/zendframework/zend-diactoros/pull/15) updates
  `Laminas\Diactoros\Stream` to ensure that write operations trigger an exception
  if the stream is not writeable. Additionally, it adds more robust logic for
  determining if a stream is writeable.

## 1.0.0 - 2015-05-21

First stable release, and first release as `laminas-diactoros`.

### Added

- Nothing.

### Deprecated

- Nothing.

### Removed

- Nothing.

### Fixed

- Nothing.
laminas-diactoros/LICENSE.md000064400000002732147361032560011574 0ustar00Copyright (c) 2020 Laminas Project a Series of LF Projects, LLC.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

- Redistributions of source code must retain the above copyright notice, this
  list of conditions and the following disclaimer.

- Redistributions in binary form must reproduce the above copyright notice,
  this list of conditions and the following disclaimer in the documentation
  and/or other materials provided with the distribution.

- Neither the name of Laminas Foundation nor the names of its contributors may
  be used to endorse or promote products derived from this software without
  specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
laminas-zendframework-bridge/config/replacements.php000064400000042612147361032560016752 0ustar00<?php

return [
    // NEVER REWRITE
    'zendframework/zendframework' => 'zendframework/zendframework',
    'zend-developer-tools/toolbar/bjy' => 'zend-developer-tools/toolbar/bjy',
    'zend-developer-tools/toolbar/doctrine' => 'zend-developer-tools/toolbar/doctrine',

    // NAMESPACES
    // Zend Framework components
    'Zend\\AuraDi\\Config' => 'Laminas\\AuraDi\\Config',
    'Zend\\Authentication' => 'Laminas\\Authentication',
    'Zend\\Barcode' => 'Laminas\\Barcode',
    'Zend\\Cache' => 'Laminas\\Cache',
    'Zend\\Captcha' => 'Laminas\\Captcha',
    'Zend\\Code' => 'Laminas\\Code',
    'ZendCodingStandard\\Sniffs' => 'LaminasCodingStandard\\Sniffs',
    'ZendCodingStandard\\Utils' => 'LaminasCodingStandard\\Utils',
    'Zend\\ComponentInstaller' => 'Laminas\\ComponentInstaller',
    'Zend\\Config' => 'Laminas\\Config',
    'Zend\\ConfigAggregator' => 'Laminas\\ConfigAggregator',
    'Zend\\ConfigAggregatorModuleManager' => 'Laminas\\ConfigAggregatorModuleManager',
    'Zend\\ConfigAggregatorParameters' => 'Laminas\\ConfigAggregatorParameters',
    'Zend\\Console' => 'Laminas\\Console',
    'Zend\\ContainerConfigTest' => 'Laminas\\ContainerConfigTest',
    'Zend\\Crypt' => 'Laminas\\Crypt',
    'Zend\\Db' => 'Laminas\\Db',
    'ZendDeveloperTools' => 'Laminas\\DeveloperTools',
    'Zend\\Di' => 'Laminas\\Di',
    'Zend\\Diactoros' => 'Laminas\\Diactoros',
    'ZendDiagnostics\\Check' => 'Laminas\\Diagnostics\\Check',
    'ZendDiagnostics\\Result' => 'Laminas\\Diagnostics\\Result',
    'ZendDiagnostics\\Runner' => 'Laminas\\Diagnostics\\Runner',
    'Zend\\Dom' => 'Laminas\\Dom',
    'Zend\\Escaper' => 'Laminas\\Escaper',
    'Zend\\EventManager' => 'Laminas\\EventManager',
    'Zend\\Feed' => 'Laminas\\Feed',
    'Zend\\File' => 'Laminas\\File',
    'Zend\\Filter' => 'Laminas\\Filter',
    'Zend\\Form' => 'Laminas\\Form',
    'Zend\\Http' => 'Laminas\\Http',
    'Zend\\HttpHandlerRunner' => 'Laminas\\HttpHandlerRunner',
    'Zend\\Hydrator' => 'Laminas\\Hydrator',
    'Zend\\I18n' => 'Laminas\\I18n',
    'Zend\\InputFilter' => 'Laminas\\InputFilter',
    'Zend\\Json' => 'Laminas\\Json',
    'Zend\\Ldap' => 'Laminas\\Ldap',
    'Zend\\Loader' => 'Laminas\\Loader',
    'Zend\\Log' => 'Laminas\\Log',
    'Zend\\Mail' => 'Laminas\\Mail',
    'Zend\\Math' => 'Laminas\\Math',
    'Zend\\Memory' => 'Laminas\\Memory',
    'Zend\\Mime' => 'Laminas\\Mime',
    'Zend\\ModuleManager' => 'Laminas\\ModuleManager',
    'Zend\\Mvc' => 'Laminas\\Mvc',
    'Zend\\Navigation' => 'Laminas\\Navigation',
    'Zend\\Paginator' => 'Laminas\\Paginator',
    'Zend\\Permissions' => 'Laminas\\Permissions',
    'Zend\\Pimple\\Config' => 'Laminas\\Pimple\\Config',
    'Zend\\ProblemDetails' => 'Mezzio\\ProblemDetails',
    'Zend\\ProgressBar' => 'Laminas\\ProgressBar',
    'Zend\\Psr7Bridge' => 'Laminas\\Psr7Bridge',
    'Zend\\Router' => 'Laminas\\Router',
    'Zend\\Serializer' => 'Laminas\\Serializer',
    'Zend\\Server' => 'Laminas\\Server',
    'Zend\\ServiceManager' => 'Laminas\\ServiceManager',
    'ZendService\\ReCaptcha' => 'Laminas\\ReCaptcha',
    'ZendService\\Twitter' => 'Laminas\\Twitter',
    'Zend\\Session' => 'Laminas\\Session',
    'Zend\\SkeletonInstaller' => 'Laminas\\SkeletonInstaller',
    'Zend\\Soap' => 'Laminas\\Soap',
    'Zend\\Stdlib' => 'Laminas\\Stdlib',
    'Zend\\Stratigility' => 'Laminas\\Stratigility',
    'Zend\\Tag' => 'Laminas\\Tag',
    'Zend\\Test' => 'Laminas\\Test',
    'Zend\\Text' => 'Laminas\\Text',
    'Zend\\Uri' => 'Laminas\\Uri',
    'Zend\\Validator' => 'Laminas\\Validator',
    'Zend\\View' => 'Laminas\\View',
    'ZendXml' => 'Laminas\\Xml',
    'Zend\\Xml2Json' => 'Laminas\\Xml2Json',
    'Zend\\XmlRpc' => 'Laminas\\XmlRpc',
    'ZendOAuth' => 'Laminas\\OAuth',

    // class ZendAcl in zend-expressive-authorization-acl
    'ZendAcl' => 'LaminasAcl',
    'Zend\\Expressive\\Authorization\\Acl\\ZendAcl' => 'Mezzio\\Authorization\\Acl\\LaminasAcl',
    // class ZendHttpClientDecorator in zend-feed
    'ZendHttp' => 'LaminasHttp',
    // class ZendModuleProvider in zend-config-aggregator-modulemanager
    'ZendModule' => 'LaminasModule',
    // class ZendRbac in zend-expressive-authorization-rbac
    'ZendRbac' => 'LaminasRbac',
    'Zend\\Expressive\\Authorization\\Rbac\\ZendRbac' => 'Mezzio\\Authorization\\Rbac\\LaminasRbac',
    // class ZendRouter in zend-expressive-router-zendrouter
    'ZendRouter' => 'LaminasRouter',
    'Zend\\Expressive\\Router\\ZendRouter' => 'Mezzio\\Router\\LaminasRouter',
    // class ZendViewRenderer in zend-expressive-zendviewrenderer
    'ZendViewRenderer' => 'LaminasViewRenderer',
    'Zend\\Expressive\\ZendView\\ZendViewRenderer' => 'Mezzio\\LaminasView\\LaminasViewRenderer',
    'a\\Zend' => 'a\\Zend',
    'b\\Zend' => 'b\\Zend',
    'c\\Zend' => 'c\\Zend',
    'd\\Zend' => 'd\\Zend',
    'e\\Zend' => 'e\\Zend',
    'f\\Zend' => 'f\\Zend',
    'g\\Zend' => 'g\\Zend',
    'h\\Zend' => 'h\\Zend',
    'i\\Zend' => 'i\\Zend',
    'j\\Zend' => 'j\\Zend',
    'k\\Zend' => 'k\\Zend',
    'l\\Zend' => 'l\\Zend',
    'm\\Zend' => 'm\\Zend',
    'n\\Zend' => 'n\\Zend',
    'o\\Zend' => 'o\\Zend',
    'p\\Zend' => 'p\\Zend',
    'q\\Zend' => 'q\\Zend',
    'r\\Zend' => 'r\\Zend',
    's\\Zend' => 's\\Zend',
    't\\Zend' => 't\\Zend',
    'u\\Zend' => 'u\\Zend',
    'v\\Zend' => 'v\\Zend',
    'w\\Zend' => 'w\\Zend',
    'x\\Zend' => 'x\\Zend',
    'y\\Zend' => 'y\\Zend',
    'z\\Zend' => 'z\\Zend',

    // Expressive
    'Zend\\Expressive' => 'Mezzio',
    'ZendAuthentication' => 'LaminasAuthentication',
    'ZendAcl' => 'LaminasAcl',
    'ZendRbac' => 'LaminasRbac',
    'ZendRouter' => 'LaminasRouter',
    'ExpressiveUrlGenerator' => 'MezzioUrlGenerator',
    'ExpressiveInstaller' => 'MezzioInstaller',

    // Apigility
    'ZF\\Apigility' => 'Laminas\\ApiTools',
    'ZF\\ApiProblem' => 'Laminas\\ApiTools\\ApiProblem',
    'ZF\\AssetManager' => 'Laminas\\ApiTools\\AssetManager',
    'ZF\\ComposerAutoloading' => 'Laminas\\ComposerAutoloading',
    'ZF\\Configuration' => 'Laminas\\ApiTools\\Configuration',
    'ZF\\ContentNegotiation' => 'Laminas\\ApiTools\\ContentNegotiation',
    'ZF\\ContentValidation' => 'Laminas\\ApiTools\\ContentValidation',
    'ZF\\DevelopmentMode' => 'Laminas\\DevelopmentMode',
    'ZF\\Doctrine\\QueryBuilder' => 'Laminas\\ApiTools\\Doctrine\\QueryBuilder',
    'ZF\\Hal' => 'Laminas\\ApiTools\\Hal',
    'ZF\\HttpCache' => 'Laminas\\ApiTools\\HttpCache',
    'ZF\\MvcAuth' => 'Laminas\\ApiTools\\MvcAuth',
    'ZF\\OAuth2' => 'Laminas\\ApiTools\\OAuth2',
    'ZF\\Rest' => 'Laminas\\ApiTools\\Rest',
    'ZF\\Rpc' => 'Laminas\\ApiTools\\Rpc',
    'ZF\\Versioning' => 'Laminas\\ApiTools\\Versioning',
    'a\\ZF' => 'a\\ZF',
    'b\\ZF' => 'b\\ZF',
    'c\\ZF' => 'c\\ZF',
    'd\\ZF' => 'd\\ZF',
    'e\\ZF' => 'e\\ZF',
    'f\\ZF' => 'f\\ZF',
    'g\\ZF' => 'g\\ZF',
    'h\\ZF' => 'h\\ZF',
    'i\\ZF' => 'i\\ZF',
    'j\\ZF' => 'j\\ZF',
    'k\\ZF' => 'k\\ZF',
    'l\\ZF' => 'l\\ZF',
    'm\\ZF' => 'm\\ZF',
    'n\\ZF' => 'n\\ZF',
    'o\\ZF' => 'o\\ZF',
    'p\\ZF' => 'p\\ZF',
    'q\\ZF' => 'q\\ZF',
    'r\\ZF' => 'r\\ZF',
    's\\ZF' => 's\\ZF',
    't\\ZF' => 't\\ZF',
    'u\\ZF' => 'u\\ZF',
    'v\\ZF' => 'v\\ZF',
    'w\\ZF' => 'w\\ZF',
    'x\\ZF' => 'x\\ZF',
    'y\\ZF' => 'y\\ZF',
    'z\\ZF' => 'z\\ZF',

    'ApigilityModuleInterface' => 'ApiToolsModuleInterface',
    'ApigilityProviderInterface' => 'ApiToolsProviderInterface',
    'ApigilityVersionController' => 'ApiToolsVersionController',

    // PACKAGES
    // ZF components, MVC
    'zendframework/skeleton-application' => 'laminas/skeleton-application',
    'zendframework/zend-auradi-config' => 'laminas/laminas-auradi-config',
    'zendframework/zend-authentication' => 'laminas/laminas-authentication',
    'zendframework/zend-barcode' => 'laminas/laminas-barcode',
    'zendframework/zend-cache' => 'laminas/laminas-cache',
    'zendframework/zend-captcha' => 'laminas/laminas-captcha',
    'zendframework/zend-code' => 'laminas/laminas-code',
    'zendframework/zend-coding-standard' => 'laminas/laminas-coding-standard',
    'zendframework/zend-component-installer' => 'laminas/laminas-component-installer',
    'zendframework/zend-composer-autoloading' => 'laminas/laminas-composer-autoloading',
    'zendframework/zend-config-aggregator' => 'laminas/laminas-config-aggregator',
    'zendframework/zend-config' => 'laminas/laminas-config',
    'zendframework/zend-console' => 'laminas/laminas-console',
    'zendframework/zend-container-config-test' => 'laminas/laminas-container-config-test',
    'zendframework/zend-crypt' => 'laminas/laminas-crypt',
    'zendframework/zend-db' => 'laminas/laminas-db',
    'zendframework/zend-developer-tools' => 'laminas/laminas-developer-tools',
    'zendframework/zend-diactoros' => 'laminas/laminas-diactoros',
    'zendframework/zenddiagnostics' => 'laminas/laminas-diagnostics',
    'zendframework/zend-di' => 'laminas/laminas-di',
    'zendframework/zend-dom' => 'laminas/laminas-dom',
    'zendframework/zend-escaper' => 'laminas/laminas-escaper',
    'zendframework/zend-eventmanager' => 'laminas/laminas-eventmanager',
    'zendframework/zend-feed' => 'laminas/laminas-feed',
    'zendframework/zend-file' => 'laminas/laminas-file',
    'zendframework/zend-filter' => 'laminas/laminas-filter',
    'zendframework/zend-form' => 'laminas/laminas-form',
    'zendframework/zend-httphandlerrunner' => 'laminas/laminas-httphandlerrunner',
    'zendframework/zend-http' => 'laminas/laminas-http',
    'zendframework/zend-hydrator' => 'laminas/laminas-hydrator',
    'zendframework/zend-i18n' => 'laminas/laminas-i18n',
    'zendframework/zend-i18n-resources' => 'laminas/laminas-i18n-resources',
    'zendframework/zend-inputfilter' => 'laminas/laminas-inputfilter',
    'zendframework/zend-json' => 'laminas/laminas-json',
    'zendframework/zend-json-server' => 'laminas/laminas-json-server',
    'zendframework/zend-ldap' => 'laminas/laminas-ldap',
    'zendframework/zend-loader' => 'laminas/laminas-loader',
    'zendframework/zend-log' => 'laminas/laminas-log',
    'zendframework/zend-mail' => 'laminas/laminas-mail',
    'zendframework/zend-math' => 'laminas/laminas-math',
    'zendframework/zend-memory' => 'laminas/laminas-memory',
    'zendframework/zend-mime' => 'laminas/laminas-mime',
    'zendframework/zend-modulemanager' => 'laminas/laminas-modulemanager',
    'zendframework/zend-mvc' => 'laminas/laminas-mvc',
    'zendframework/zend-navigation' => 'laminas/laminas-navigation',
    'zendframework/zend-oauth' => 'laminas/laminas-oauth',
    'zendframework/zend-paginator' => 'laminas/laminas-paginator',
    'zendframework/zend-permissions-acl' => 'laminas/laminas-permissions-acl',
    'zendframework/zend-permissions-rbac' => 'laminas/laminas-permissions-rbac',
    'zendframework/zend-pimple-config' => 'laminas/laminas-pimple-config',
    'zendframework/zend-progressbar' => 'laminas/laminas-progressbar',
    'zendframework/zend-psr7bridge' => 'laminas/laminas-psr7bridge',
    'zendframework/zend-recaptcha' => 'laminas/laminas-recaptcha',
    'zendframework/zend-router' => 'laminas/laminas-router',
    'zendframework/zend-serializer' => 'laminas/laminas-serializer',
    'zendframework/zend-server' => 'laminas/laminas-server',
    'zendframework/zend-servicemanager' => 'laminas/laminas-servicemanager',
    'zendframework/zendservice-recaptcha' => 'laminas/laminas-recaptcha',
    'zendframework/zendservice-twitter' => 'laminas/laminas-twitter',
    'zendframework/zend-session' => 'laminas/laminas-session',
    'zendframework/zend-skeleton-installer' => 'laminas/laminas-skeleton-installer',
    'zendframework/zend-soap' => 'laminas/laminas-soap',
    'zendframework/zend-stdlib' => 'laminas/laminas-stdlib',
    'zendframework/zend-stratigility' => 'laminas/laminas-stratigility',
    'zendframework/zend-tag' => 'laminas/laminas-tag',
    'zendframework/zend-test' => 'laminas/laminas-test',
    'zendframework/zend-text' => 'laminas/laminas-text',
    'zendframework/zend-uri' => 'laminas/laminas-uri',
    'zendframework/zend-validator' => 'laminas/laminas-validator',
    'zendframework/zend-view' => 'laminas/laminas-view',
    'zendframework/zend-xml2json' => 'laminas/laminas-xml2json',
    'zendframework/zend-xml' => 'laminas/laminas-xml',
    'zendframework/zend-xmlrpc' => 'laminas/laminas-xmlrpc',

    // Expressive packages
    'zendframework/zend-expressive' => 'mezzio/mezzio',
    'zendframework/zend-expressive-zendrouter' => 'mezzio/mezzio-laminasrouter',
    'zendframework/zend-problem-details' => 'mezzio/mezzio-problem-details',
    'zendframework/zend-expressive-zendviewrenderer' => 'mezzio/mezzio-laminasviewrenderer',

    // Apigility packages
    'zfcampus/apigility-documentation' => 'laminas-api-tools/documentation',
    'zfcampus/statuslib-example' => 'laminas-api-tools/statuslib-example',
    'zfcampus/zf-apigility' => 'laminas-api-tools/api-tools',
    'zfcampus/zf-api-problem' => 'laminas-api-tools/api-tools-api-problem',
    'zfcampus/zf-asset-manager' => 'laminas-api-tools/api-tools-asset-manager',
    'zfcampus/zf-configuration' => 'laminas-api-tools/api-tools-configuration',
    'zfcampus/zf-content-negotiation' => 'laminas-api-tools/api-tools-content-negotiation',
    'zfcampus/zf-content-validation' => 'laminas-api-tools/api-tools-content-validation',
    'zfcampus/zf-development-mode' => 'laminas/laminas-development-mode',
    'zfcampus/zf-doctrine-querybuilder' => 'laminas-api-tools/api-tools-doctrine-querybuilder',
    'zfcampus/zf-hal' => 'laminas-api-tools/api-tools-hal',
    'zfcampus/zf-http-cache' => 'laminas-api-tools/api-tools-http-cache',
    'zfcampus/zf-mvc-auth' => 'laminas-api-tools/api-tools-mvc-auth',
    'zfcampus/zf-oauth2' => 'laminas-api-tools/api-tools-oauth2',
    'zfcampus/zf-rest' => 'laminas-api-tools/api-tools-rest',
    'zfcampus/zf-rpc' => 'laminas-api-tools/api-tools-rpc',
    'zfcampus/zf-versioning' => 'laminas-api-tools/api-tools-versioning',

    // CONFIG KEYS, SCRIPT NAMES, ETC
    // ZF components
    '::fromZend' => '::fromLaminas', // psr7bridge
    '::toZend' => '::toLaminas', // psr7bridge
    'use_zend_loader' => 'use_laminas_loader', // zend-modulemanager
    'zend-config' => 'laminas-config',
    'zend-developer-tools/' => 'laminas-developer-tools/',
    'zend-tag-cloud' => 'laminas-tag-cloud',
    'zenddevelopertools' => 'laminas-developer-tools',
    'zendbarcode' => 'laminasbarcode',
    'ZendBarcode' => 'LaminasBarcode',
    'zendcache' => 'laminascache',
    'ZendCache' => 'LaminasCache',
    'zendconfig' => 'laminasconfig',
    'ZendConfig' => 'LaminasConfig',
    'zendfeed' => 'laminasfeed',
    'ZendFeed' => 'LaminasFeed',
    'zendfilter' => 'laminasfilter',
    'ZendFilter' => 'LaminasFilter',
    'zendform' => 'laminasform',
    'ZendForm' => 'LaminasForm',
    'zendi18n' => 'laminasi18n',
    'ZendI18n' => 'LaminasI18n',
    'zendinputfilter' => 'laminasinputfilter',
    'ZendInputFilter' => 'LaminasInputFilter',
    'zendlog' => 'laminaslog',
    'ZendLog' => 'LaminasLog',
    'zendmail' => 'laminasmail',
    'ZendMail' => 'LaminasMail',
    'zendmvc' => 'laminasmvc',
    'ZendMvc' => 'LaminasMvc',
    'zendpaginator' => 'laminaspaginator',
    'ZendPaginator' => 'LaminasPaginator',
    'zendserializer' => 'laminasserializer',
    'ZendSerializer' => 'LaminasSerializer',
    'zendtag' => 'laminastag',
    'ZendTag' => 'LaminasTag',
    'zendtext' => 'laminastext',
    'ZendText' => 'LaminasText',
    'zendvalidator' => 'laminasvalidator',
    'ZendValidator' => 'LaminasValidator',
    'zendview' => 'laminasview',
    'ZendView' => 'LaminasView',
    'zend-framework.flf' => 'laminas-project.flf',

    // Expressive-related
    "'zend-expressive'" => "'mezzio'",
    '"zend-expressive"' => '"mezzio"',
    'zend-expressive.' => 'mezzio.',
    'zend-expressive-authorization' => 'mezzio-authorization',
    'zend-expressive-hal' => 'mezzio-hal',
    'zend-expressive-session' => 'mezzio-session',
    'zend-expressive-swoole' => 'mezzio-swoole',
    'zend-expressive-tooling' => 'mezzio-tooling',

    // Apigility-related
    "'zf-apigility'" => "'api-tools'",
    '"zf-apigility"' => '"api-tools"',
    'zf-apigility/' => 'api-tools/',
    'zf-apigility-admin' => 'api-tools-admin',
    'zf-content-negotiation' => 'api-tools-content-negotiation',
    'zf-hal' => 'api-tools-hal',
    'zf-rest' => 'api-tools-rest',
    'zf-rpc' => 'api-tools-rpc',
    'zf-content-validation' => 'api-tools-content-validation',
    'zf-apigility-ui' => 'api-tools-ui',
    'zf-apigility-documentation-blueprint' => 'api-tools-documentation-blueprint',
    'zf-apigility-documentation-swagger' => 'api-tools-documentation-swagger',
    'zf-apigility-welcome' => 'api-tools-welcome',
    'zf-api-problem' => 'api-tools-api-problem',
    'zf-configuration' => 'api-tools-configuration',
    'zf-http-cache' => 'api-tools-http-cache',
    'zf-mvc-auth' => 'api-tools-mvc-auth',
    'zf-oauth2' => 'api-tools-oauth2',
    'zf-versioning' => 'api-tools-versioning',
    'ZfApigilityDoctrineQueryProviderManager' => 'LaminasApiToolsDoctrineQueryProviderManager',
    'ZfApigilityDoctrineQueryCreateFilterManager' => 'LaminasApiToolsDoctrineQueryCreateFilterManager',
    'zf-apigility-doctrine' => 'api-tools-doctrine',
    'zf-development-mode' => 'laminas-development-mode',
    'zf-doctrine-querybuilder' => 'api-tools-doctrine-querybuilder',

    // 3rd party Apigility packages
    'api-skeletons/zf-' => 'api-skeletons/zf-', // api-skeletons packages
    'zf-oauth2-' => 'zf-oauth2-', // api-skeletons OAuth2-related packages
    'ZF\\OAuth2\\Client' => 'ZF\\OAuth2\\Client', // api-skeletons/zf-oauth2-client
    'ZF\\OAuth2\\Doctrine' => 'ZF\\OAuth2\\Doctrine', // api-skeletons/zf-oauth2-doctrine
];
laminas-zendframework-bridge/COPYRIGHT.md000064400000000133147361032560014174 0ustar00Copyright (c) 2020 Laminas Project a Series of LF Projects, LLC. (https://getlaminas.org/)
laminas-zendframework-bridge/src/autoload.php000064400000000566147361032560015424 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-zendframework-bridge for the canonical source repository
 * @copyright https://github.com/laminas/laminas-zendframework-bridge/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-zendframework-bridge/blob/master/LICENSE.md New BSD License
 */

Laminas\ZendFrameworkBridge\Autoloader::load();
laminas-zendframework-bridge/src/Module.php000064400000003205147361032560015032 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-zendframework-bridge for the canonical source repository
 * @copyright https://github.com/laminas/laminas-zendframework-bridge/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-zendframework-bridge/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\ZendFrameworkBridge;

use Laminas\ModuleManager\Listener\ConfigMergerInterface;
use Laminas\ModuleManager\ModuleEvent;
use Laminas\ModuleManager\ModuleManager;

class Module
{
    /**
     * Initialize the module.
     *
     * Type-hinting deliberately omitted to allow unit testing
     * without dependencies on packages that do not exist yet.
     *
     * @param ModuleManager $moduleManager
     */
    public function init($moduleManager)
    {
        $moduleManager
            ->getEventManager()
            ->attach('mergeConfig', [$this, 'onMergeConfig']);
    }

    /**
     * Perform substitutions in the merged configuration.
     *
     * Rewrites keys and values matching known ZF classes, namespaces, and
     * configuration keys to their Laminas equivalents.
     *
     * Type-hinting deliberately omitted to allow unit testing
     * without dependencies on packages that do not exist yet.
     *
     * @param ModuleEvent $event
     */
    public function onMergeConfig($event)
    {
        /** @var ConfigMergerInterface */
        $configMerger = $event->getConfigListener();
        $processor    = new ConfigPostProcessor();
        $configMerger->setMergedConfig(
            $processor(
                $configMerger->getMergedConfig($returnAsObject = false)
            )
        );
    }
}
laminas-zendframework-bridge/src/ConfigPostProcessor.php000064400000031602147361032560017562 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-zendframework-bridge for the canonical source repository
 * @copyright https://github.com/laminas/laminas-zendframework-bridge/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-zendframework-bridge/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\ZendFrameworkBridge;

use function array_intersect_key;
use function array_key_exists;
use function array_pop;
use function array_push;
use function count;
use function in_array;
use function is_array;
use function is_callable;
use function is_int;
use function is_string;

class ConfigPostProcessor
{
    /** @internal */
    const SERVICE_MANAGER_KEYS_OF_INTEREST = [
        'aliases'    => true,
        'factories'  => true,
        'invokables' => true,
        'services'   => true,
    ];

    /** @var array String keys => string values */
    private $exactReplacements = [
        'zend-expressive' => 'mezzio',
        'zf-apigility'    => 'api-tools',
    ];

    /** @var Replacements */
    private $replacements;

    /** @var callable[] */
    private $rulesets;

    public function __construct()
    {
        $this->replacements = new Replacements();

        /* Define the rulesets for replacements.
         *
         * Each ruleset has the following signature:
         *
         * @param mixed $value
         * @param string[] $keys Full nested key hierarchy leading to the value
         * @return null|callable
         *
         * If no match is made, a null is returned, allowing it to fallback to
         * the next ruleset in the list. If a match is made, a callback is returned,
         * and that will be used to perform the replacement on the value.
         *
         * The callback should have the following signature:
         *
         * @param mixed $value
         * @param string[] $keys
         * @return mixed The transformed value
         */
        $this->rulesets = [
            // Exact values
            function ($value) {
                return is_string($value) && isset($this->exactReplacements[$value])
                    ? [$this, 'replaceExactValue']
                    : null;
            },

            // Router (MVC applications)
            // We do not want to rewrite these.
            function ($value, array $keys) {
                $key = array_pop($keys);
                // Only worried about a top-level "router" key.
                return $key === 'router' && count($keys) === 0 && is_array($value)
                    ? [$this, 'noopReplacement']
                    : null;
            },

            // service- and pluginmanager handling
            function ($value) {
                return is_array($value) && array_intersect_key(self::SERVICE_MANAGER_KEYS_OF_INTEREST, $value) !== []
                    ? [$this, 'replaceDependencyConfiguration']
                    : null;
            },

            // Array values
            function ($value, array $keys) {
                return 0 !== count($keys) && is_array($value)
                    ? [$this, '__invoke']
                    : null;
            },
        ];
    }

    /**
     * @param string[] $keys Hierarchy of keys, for determining location in
     *     nested configuration.
     * @return array
     */
    public function __invoke(array $config, array $keys = [])
    {
        $rewritten = [];

        foreach ($config as $key => $value) {
            // Determine new key from replacements
            $newKey = is_string($key) ? $this->replace($key, $keys) : $key;

            // Keep original values with original key, if the key has changed, but only at the top-level.
            if (empty($keys) && $newKey !== $key) {
                $rewritten[$key] = $value;
            }

            // Perform value replacements, if any
            $newValue = $this->replace($value, $keys, $newKey);

            // Key does not already exist and/or is not an array value
            if (! array_key_exists($newKey, $rewritten) || ! is_array($rewritten[$newKey])) {
                // Do not overwrite existing values with null values
                $rewritten[$newKey] = array_key_exists($newKey, $rewritten) && null === $newValue
                    ? $rewritten[$newKey]
                    : $newValue;
                continue;
            }

            // New value is null; nothing to do.
            if (null === $newValue) {
                continue;
            }

            // Key already exists as an array value, but $value is not an array
            if (! is_array($newValue)) {
                $rewritten[$newKey][] = $newValue;
                continue;
            }

            // Key already exists as an array value, and $value is also an array
            $rewritten[$newKey] = static::merge($rewritten[$newKey], $newValue);
        }

        return $rewritten;
    }

    /**
     * Perform substitutions as needed on an individual value.
     *
     * The $key is provided to allow fine-grained selection of rewrite rules.
     *
     * @param mixed $value
     * @param string[] $keys Key hierarchy
     * @param null|int|string $key
     * @return mixed
     */
    private function replace($value, array $keys, $key = null)
    {
        // Add new key to the list of keys.
        // We do not need to remove it later, as we are working on a copy of the array.
        array_push($keys, $key);

        // Identify rewrite strategy and perform replacements
        $rewriteRule = $this->replacementRuleMatch($value, $keys);
        return $rewriteRule($value, $keys);
    }

    /**
     * Merge two arrays together.
     *
     * If an integer key exists in both arrays, the value from the second array
     * will be appended to the first array. If both values are arrays, they are
     * merged together, else the value of the second array overwrites the one
     * of the first array.
     *
     * Based on zend-stdlib Zend\Stdlib\ArrayUtils::merge
     * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
     *
     * @return array
     */
    public static function merge(array $a, array $b)
    {
        foreach ($b as $key => $value) {
            if (! isset($a[$key]) && ! array_key_exists($key, $a)) {
                $a[$key] = $value;
                continue;
            }

            if (null === $value && array_key_exists($key, $a)) {
                // Leave as-is if value from $b is null
                continue;
            }

            if (is_int($key)) {
                $a[] = $value;
                continue;
            }

            if (is_array($value) && is_array($a[$key])) {
                $a[$key] = static::merge($a[$key], $value);
                continue;
            }

            $a[$key] = $value;
        }

        return $a;
    }

    /**
     * @param mixed $value
     * @param null|int|string $key
     * @return callable Callable to invoke with value
     */
    private function replacementRuleMatch($value, $key = null)
    {
        foreach ($this->rulesets as $ruleset) {
            $result = $ruleset($value, $key);
            if (is_callable($result)) {
                return $result;
            }
        }
        return [$this, 'fallbackReplacement'];
    }

    /**
     * Replace a value using the translation table, if the value is a string.
     *
     * @param mixed $value
     * @return mixed
     */
    private function fallbackReplacement($value)
    {
        return is_string($value)
            ? $this->replacements->replace($value)
            : $value;
    }

    /**
     * Replace a value matched exactly.
     *
     * @param mixed $value
     * @return mixed
     */
    private function replaceExactValue($value)
    {
        return $this->exactReplacements[$value];
    }

    private function replaceDependencyConfiguration(array $config)
    {
        $aliases = isset($config['aliases']) && is_array($config['aliases'])
            ? $this->replaceDependencyAliases($config['aliases'])
            : [];

        if ($aliases) {
            $config['aliases'] = $aliases;
        }

        $config = $this->replaceDependencyInvokables($config);
        $config = $this->replaceDependencyFactories($config);
        $config = $this->replaceDependencyServices($config);

        $keys = self::SERVICE_MANAGER_KEYS_OF_INTEREST;
        foreach ($config as $key => $data) {
            if (isset($keys[$key])) {
                continue;
            }

            $config[$key] = is_array($data) ? $this->__invoke($data, [$key]) :  $data;
        }

        return $config;
    }

    /**
     * Rewrite dependency aliases array
     *
     * In this case, we want to keep the alias as-is, but rewrite the target.
     *
     * We need also provide an additional alias if the alias key is a legacy class.
     *
     * @return array
     */
    private function replaceDependencyAliases(array $aliases)
    {
        foreach ($aliases as $alias => $target) {
            if (! is_string($alias) || ! is_string($target)) {
                continue;
            }

            $newTarget = $this->replacements->replace($target);
            $newAlias  = $this->replacements->replace($alias);

            $notIn = [$newTarget];
            $name  = $newTarget;
            while (isset($aliases[$name])) {
                $notIn[] = $aliases[$name];
                $name    = $aliases[$name];
            }

            if ($newAlias === $alias && ! in_array($alias, $notIn, true)) {
                $aliases[$alias] = $newTarget;
                continue;
            }

            if (isset($aliases[$newAlias])) {
                continue;
            }

            if (! in_array($newAlias, $notIn, true)) {
                $aliases[$alias]    = $newAlias;
                $aliases[$newAlias] = $newTarget;
            }
        }

        return $aliases;
    }

    /**
     * Rewrite dependency invokables array
     *
     * In this case, we want to keep the alias as-is, but rewrite the target.
     *
     * We need also provide an additional alias if invokable is defined with
     * an alias which is a legacy class.
     *
     * @return array
     */
    private function replaceDependencyInvokables(array $config)
    {
        if (empty($config['invokables']) || ! is_array($config['invokables'])) {
            return $config;
        }

        foreach ($config['invokables'] as $alias => $target) {
            if (! is_string($alias)) {
                continue;
            }

            $newTarget = $this->replacements->replace($target);
            $newAlias  = $this->replacements->replace($alias);

            if ($alias === $target || isset($config['aliases'][$newAlias])) {
                $config['invokables'][$alias] = $newTarget;
                continue;
            }

            $config['invokables'][$newAlias] = $newTarget;

            if ($newAlias === $alias) {
                continue;
            }

            $config['aliases'][$alias] = $newAlias;

            unset($config['invokables'][$alias]);
        }

        return $config;
    }

    /**
     * @param mixed $value
     * @return mixed Returns $value verbatim.
     */
    private function noopReplacement($value)
    {
        return $value;
    }

    private function replaceDependencyFactories(array $config)
    {
        if (empty($config['factories']) || ! is_array($config['factories'])) {
            return $config;
        }

        foreach ($config['factories'] as $service => $factory) {
            if (! is_string($service)) {
                continue;
            }

            $replacedService = $this->replacements->replace($service);
            $factory         = is_string($factory) ? $this->replacements->replace($factory) : $factory;
            $config['factories'][$replacedService] = $factory;

            if ($replacedService === $service) {
                continue;
            }

            unset($config['factories'][$service]);
            if (isset($config['aliases'][$service])) {
                continue;
            }

            $config['aliases'][$service] = $replacedService;
        }

        return $config;
    }

    private function replaceDependencyServices(array $config)
    {
        if (empty($config['services']) || ! is_array($config['services'])) {
            return $config;
        }

        foreach ($config['services'] as $service => $serviceInstance) {
            if (! is_string($service)) {
                continue;
            }

            $replacedService = $this->replacements->replace($service);
            $serviceInstance = is_array($serviceInstance) ? $this->__invoke($serviceInstance) : $serviceInstance;

            $config['services'][$replacedService] = $serviceInstance;

            if ($service === $replacedService) {
                continue;
            }

            unset($config['services'][$service]);

            if (isset($config['aliases'][$service])) {
                continue;
            }

            $config['aliases'][$service] = $replacedService;
        }

        return $config;
    }
}
laminas-zendframework-bridge/src/Replacements.php000064400000002614147361032560016232 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-zendframework-bridge for the canonical source repository
 * @copyright https://github.com/laminas/laminas-zendframework-bridge/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-zendframework-bridge/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\ZendFrameworkBridge;

use function array_merge;
use function str_replace;
use function strpos;
use function strtr;

class Replacements
{
    /** @var string[] */
    private $replacements;

    public function __construct(array $additionalReplacements = [])
    {
        $this->replacements = array_merge(
            require __DIR__ . '/../config/replacements.php',
            $additionalReplacements
        );

        // Provide multiple variants of strings containing namespace separators
        foreach ($this->replacements as $original => $replacement) {
            if (false === strpos($original, '\\')) {
                continue;
            }
            $this->replacements[str_replace('\\', '\\\\', $original)] = str_replace('\\', '\\\\', $replacement);
            $this->replacements[str_replace('\\', '\\\\\\\\', $original)] = str_replace('\\', '\\\\\\\\', $replacement);
        }
    }

    /**
     * @param string $value
     * @return string
     */
    public function replace($value)
    {
        return strtr($value, $this->replacements);
    }
}
laminas-zendframework-bridge/src/Autoloader.php000064400000012445147361032560015712 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-zendframework-bridge for the canonical source repository
 * @copyright https://github.com/laminas/laminas-zendframework-bridge/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-zendframework-bridge/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\ZendFrameworkBridge;

use ArrayObject;
use Composer\Autoload\ClassLoader;
use RuntimeException;

use function array_values;
use function class_alias;
use function class_exists;
use function explode;
use function file_exists;
use function interface_exists;
use function spl_autoload_register;
use function strlen;
use function strtr;
use function substr;
use function trait_exists;

/**
 * Alias legacy Zend Framework project classes/interfaces/traits to Laminas equivalents.
 */
class Autoloader
{
    /**
     * Attach autoloaders for managing legacy ZF artifacts.
     *
     * We attach two autoloaders:
     *
     * - The first is _prepended_ to handle new classes and add aliases for
     *   legacy classes. PHP expects any interfaces implemented, classes
     *   extended, or traits used when declaring class_alias() to exist and/or
     *   be autoloadable already at the time of declaration. If not, it will
     *   raise a fatal error. This autoloader helps mitigate errors in such
     *   situations.
     *
     * - The second is _appended_ in order to create aliases for legacy
     *   classes.
     */
    public static function load()
    {
        $loaded = new ArrayObject([]);

        spl_autoload_register(self::createPrependAutoloader(
            RewriteRules::namespaceReverse(),
            self::getClassLoader(),
            $loaded
        ), true, true);

        spl_autoload_register(self::createAppendAutoloader(
            RewriteRules::namespaceRewrite(),
            $loaded
        ));
    }

    /**
     * @return ClassLoader
     * @throws RuntimeException
     */
    private static function getClassLoader()
    {
        if (getenv('COMPOSER_VENDOR_DIR') && file_exists(getenv('COMPOSER_VENDOR_DIR') . '/autoload.php')) {
            return include getenv('COMPOSER_VENDOR_DIR') . '/autoload.php';
        }

        if (file_exists(__DIR__ . '/../../../autoload.php')) {
            return include __DIR__ . '/../../../autoload.php';
        }

        if (file_exists(__DIR__ . '/../vendor/autoload.php')) {
            return include __DIR__ . '/../vendor/autoload.php';
        }

        throw new RuntimeException('Cannot detect composer autoload. Please run composer install');
    }

    /**
     * @return callable
     */
    private static function createPrependAutoloader(array $namespaces, ClassLoader $classLoader, ArrayObject $loaded)
    {
        /**
         * @param  string $class Class name to autoload
         * @return void
         */
        return static function ($class) use ($namespaces, $classLoader, $loaded) {
            if (isset($loaded[$class])) {
                return;
            }

            $segments = explode('\\', $class);

            $i = 0;
            $check = '';

            while (isset($segments[$i + 1], $namespaces[$check . $segments[$i] . '\\'])) {
                $check .= $segments[$i] . '\\';
                ++$i;
            }

            if ($check === '') {
                return;
            }

            if ($classLoader->loadClass($class)) {
                $legacy = $namespaces[$check]
                    . strtr(substr($class, strlen($check)), [
                        'ApiTools' => 'Apigility',
                        'Mezzio' => 'Expressive',
                        'Laminas' => 'Zend',
                    ]);
                class_alias($class, $legacy);
            }
        };
    }

    /**
     * @return callable
     */
    private static function createAppendAutoloader(array $namespaces, ArrayObject $loaded)
    {
        /**
         * @param  string $class Class name to autoload
         * @return void
         */
        return static function ($class) use ($namespaces, $loaded) {
            $segments = explode('\\', $class);

            if ($segments[0] === 'ZendService' && isset($segments[1])) {
                $segments[0] .= '\\' . $segments[1];
                unset($segments[1]);
                $segments = array_values($segments);
            }

            $i = 0;
            $check = '';

            // We are checking segments of the namespace to match quicker
            while (isset($segments[$i + 1], $namespaces[$check . $segments[$i] . '\\'])) {
                $check .= $segments[$i] . '\\';
                ++$i;
            }

            if ($check === '') {
                return;
            }

            $alias = $namespaces[$check]
                . strtr(substr($class, strlen($check)), [
                    'Apigility' => 'ApiTools',
                    'Expressive' => 'Mezzio',
                    'Zend' => 'Laminas',
                    'AbstractZendServer' => 'AbstractZendServer',
                    'ZendServerDisk' => 'ZendServerDisk',
                    'ZendServerShm' => 'ZendServerShm',
                    'ZendMonitor' => 'ZendMonitor',
                ]);

            $loaded[$alias] = true;
            if (class_exists($alias) || interface_exists($alias) || trait_exists($alias)) {
                class_alias($alias, $class);
            }
        };
    }
}
laminas-zendframework-bridge/src/RewriteRules.php000064400000006023147361032560016242 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-zendframework-bridge for the canonical source repository
 * @copyright https://github.com/laminas/laminas-zendframework-bridge/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-zendframework-bridge/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\ZendFrameworkBridge;

class RewriteRules
{
    /**
     * @return array
     */
    public static function namespaceRewrite()
    {
        return [
            // Expressive
            'Zend\\ProblemDetails\\' => 'Mezzio\\ProblemDetails\\',
            'Zend\\Expressive\\'     => 'Mezzio\\',

            // Laminas
            'Zend\\'                    => 'Laminas\\',
            'ZF\\ComposerAutoloading\\' => 'Laminas\\ComposerAutoloading\\',
            'ZF\\DevelopmentMode\\'     => 'Laminas\\DevelopmentMode\\',

            // Apigility
            'ZF\\Apigility\\' => 'Laminas\\ApiTools\\',
            'ZF\\'            => 'Laminas\\ApiTools\\',

            // ZendXml, API wrappers, zend-http OAuth support, zend-diagnostics, ZendDeveloperTools
            'ZendXml\\'                => 'Laminas\\Xml\\',
            'ZendOAuth\\'              => 'Laminas\\OAuth\\',
            'ZendDiagnostics\\'        => 'Laminas\\Diagnostics\\',
            'ZendService\\ReCaptcha\\' => 'Laminas\\ReCaptcha\\',
            'ZendService\\Twitter\\'   => 'Laminas\\Twitter\\',
            'ZendDeveloperTools\\'     => 'Laminas\\DeveloperTools\\',
        ];
    }

    /**
     * @return array
     */
    public static function namespaceReverse()
    {
        return [
            // ZendXml, ZendOAuth, ZendDiagnostics, ZendDeveloperTools
            'Laminas\\Xml\\'            => 'ZendXml\\',
            'Laminas\\OAuth\\'          => 'ZendOAuth\\',
            'Laminas\\Diagnostics\\'    => 'ZendDiagnostics\\',
            'Laminas\\DeveloperTools\\' => 'ZendDeveloperTools\\',

            // Zend Service
            'Laminas\\ReCaptcha\\' => 'ZendService\\ReCaptcha\\',
            'Laminas\\Twitter\\'   => 'ZendService\\Twitter\\',

            // Zend
            'Laminas\\' => 'Zend\\',

            // Expressive
            'Mezzio\\ProblemDetails\\' => 'Zend\\ProblemDetails\\',
            'Mezzio\\'                 => 'Zend\\Expressive\\',

            // Laminas to ZfCampus
            'Laminas\\ComposerAutoloading\\' => 'ZF\\ComposerAutoloading\\',
            'Laminas\\DevelopmentMode\\'     => 'ZF\\DevelopmentMode\\',

            // Apigility
            'Laminas\\ApiTools\\Admin\\'         => 'ZF\\Apigility\\Admin\\',
            'Laminas\\ApiTools\\Doctrine\\'      => 'ZF\\Apigility\\Doctrine\\',
            'Laminas\\ApiTools\\Documentation\\' => 'ZF\\Apigility\\Documentation\\',
            'Laminas\\ApiTools\\Example\\'       => 'ZF\\Apigility\\Example\\',
            'Laminas\\ApiTools\\Provider\\'      => 'ZF\\Apigility\\Provider\\',
            'Laminas\\ApiTools\\Welcome\\'       => 'ZF\\Apiglity\\Welcome\\',
            'Laminas\\ApiTools\\'                => 'ZF\\',
        ];
    }
}
laminas-zendframework-bridge/README.md000064400000001705147361032560013567 0ustar00# laminas-zendframework-bridge

[![Build Status](https://travis-ci.com/laminas/laminas-zendframework-bridge.svg?branch=master)](https://travis-ci.com/laminas/laminas-zendframework-bridge)
[![Coverage Status](https://coveralls.io/repos/github/laminas/laminas-zendframework-bridge/badge.svg?branch=master)](https://coveralls.io/github/laminas/laminas-zendframework-bridge?branch=master)

This library provides a custom autoloader that aliases legacy Zend Framework,
Apigility, and Expressive classes to their replacements under the Laminas
Project.

This package should be installed only if you are also using the composer plugin
that installs Laminas packages to replace ZF/Apigility/Expressive packages.

## Installation

Run the following to install this library:

```bash
$ composer require laminas/laminas-zendframework-bridge
```

## Support

* [Issues](https://github.com/laminas/laminas-zendframework-bridge/issues/)
* [Forum](https://discourse.laminas.dev/)
laminas-zendframework-bridge/CHANGELOG.md000064400000036214147361032560014124 0ustar00# Changelog

All notable changes to this project will be documented in this file, in reverse chronological order by release.

## 1.1.1 - 2020-09-14

### Fixed

- [#71](https://github.com/laminas/laminas-zendframework-bridge/pull/71) fixes detection of the vendor directory when the `COMPOSER_VENDOR_DIR` env variable is missing or empty. Previously, this could lead to scenarios where a non-existent path was used for finding the bridge autoloader.


-----

### Release Notes for [1.1.1](https://github.com/laminas/laminas-zendframework-bridge/milestone/5)



### 1.1.1

- Total issues resolved: **0**
- Total pull requests resolved: **1**
- Total contributors: **1**

#### Bug

 - [71: Verify `COMPOSER&#95;VENDOR&#95;DIR` in conditional](https://github.com/laminas/laminas-zendframework-bridge/pull/71) thanks to @aaronbushnell

## 1.1.0 - 2020-08-18

### Added

- [#68](https://github.com/laminas/laminas-zendframework-bridge/pull/68) adds support for the upcoming PHP 8.0 release.

### Changed

- Nothing.

### Deprecated

- Nothing.

### Removed

- Nothing.

### Fixed

- [#67](https://github.com/laminas/laminas-zendframework-bridge/pull/67) fixes how the Composer autoload file is found, looking first in the `COMPOSER_VENDOR_DIR` before trying to resolve relative to where the package is installed.

## 1.0.4 - 2020-05-20

### Added

- Nothing.

### Changed

- Nothing.

### Deprecated

- Nothing.

### Removed

- Nothing.

### Fixed

- [#66](https://github.com/laminas/laminas-zendframework-bridge/pull/66) ensures that references to BjyAuthorize templates are not rewritten, so that they can be resolved during runtime.

## 1.0.3 - 2020-04-03

### Added

- Nothing.

### Changed

- Nothing.

### Deprecated

- Nothing.

### Removed

- Nothing.

### Fixed

- [#63](https://github.com/laminas/laminas-zendframework-bridge/pull/63) fixes handling of dependency configuration to ensure each of delegators, initializers, and abstract factories are properly handled during configuraiton post processing. The new approach should allow delegators to work post-migration to Laminas or Mezzio.

- [#61](https://github.com/laminas/laminas-zendframework-bridge/pull/61) ensures configuration for delegator factories gets rewritten; the functionality broke in version 1.0.1.

## 1.0.2 - 2020-03-26

### Added

- Nothing.

### Changed

- Nothing.

### Deprecated

- Nothing.

### Removed

- Nothing.

### Fixed

- [#55](https://github.com/laminas/laminas-zendframework-bridge/pull/55) adds provisions to ensure that references to legacy classes/interfaces in dependency configuration always create aliases from the legacy to the new classes. Previously, we did straight replacements in the configuration, which could lead to the legacy service no longer being available. Now it will remain available.

- [#59](https://github.com/laminas/laminas-zendframework-bridge/pull/59) fixes the replacement rules such as to avoid replacing references to API Skeletons packages, classes, or configuration keys.

- [#57](https://github.com/laminas/laminas-zendframework-bridge/pull/57) fixes how references to the "zf-apigility" key are replaced. Previously, they were rewritten to "laminas-api-tools", but the correct replacement is "api-tools".

- [#56](https://github.com/laminas/laminas-zendframework-bridge/pull/56) provides a mechanism to add additional maps with multiple levels of namespace separator escaping, in order to ensure that all various known permutations are matched. The escaping is applied to both the original and target, to ensure that rewrites conform to the original escaping.

- [#56](https://github.com/laminas/laminas-zendframework-bridge/pull/56) makes changes to the replacement rules to ensure we do not replace references to "Zend" or "ZF" if they occur as subnamespaces OR as class names (formerly, we only enforced subnamespaces). Additional rules were provided for cases where one or both occur within our own packages.

- [#52](https://github.com/laminas/laminas-zendframework-bridge/pull/52) fixes a scenario whereby factory _values_ were not being rewritten during configuration post processing.

- [#52](https://github.com/laminas/laminas-zendframework-bridge/pull/52) fixes an issue that occurs with the configuration post processor. Previously, when a service name used as a factory or invokable was encountered that referenced a legacy class, it would get rewritten. This would cause issues if the service was not exposed in the original legacy package, however, as there would now be no alias of the legacy service to the new one. This patch modifies the configuration post processor such that it now tests to see if a service name it will rename exists as an alias; if not, it also creates the alias.

## 1.0.1 - 2020-01-07

### Added

- Nothing.

### Changed

- Nothing.

### Deprecated

- Nothing.

### Removed

- Nothing.

### Fixed

- [#47](https://github.com/laminas/laminas-zendframework-bridge/pull/47) adds entries for rewriting the various `::*Zend()` methods exposed in the psr7bridge to `::*Laminas()` during migrations.

- [#46](https://github.com/laminas/laminas-zendframework-bridge/pull/46) adds a rule to rewrite the config key `use_zend_loader` to `use_laminas_loader`.

- [#45](https://github.com/laminas/laminas-zendframework-bridge/pull/45) adds a rule to exclude rewriting of view paths provided by the various Doctrine modules targeting the developer tools.

## 1.0.0 - 2019-12-31

### Added

- First stable release.

### Changed

- Nothing.

### Deprecated

- Nothing.

### Removed

- Nothing.

### Fixed

- Nothing.

## 0.4.5 - 2019-12-23

### Added

- Nothing.

### Changed

- [#42](https://github.com/laminas/laminas-zendframework-bridge/pull/42) modifies the replacement rules to no longer rewrite zf-deploy; the package will not be coming to the new organizations.

### Deprecated

- Nothing.

### Removed

- Nothing.

### Fixed

- Nothing.

## 0.4.4 - 2019-12-18

### Added

- Nothing.

### Changed

- [#40](https://github.com/laminas/laminas-zendframework-bridge/pull/40) adds exclusion rules for subnamespaces that reference Zend, ZF, ZendService, or ZendOAuth to ensure they are not rewritten.

### Deprecated

- Nothing.

### Removed

- Nothing.

### Fixed

- [#40](https://github.com/laminas/laminas-zendframework-bridge/pull/40) adds exclusions for classes referencing Zend Server product features to ensure they are not rewritten (e.g., `ZendServerDisk`, `ZendServerShm`, `ZendMonitor`).

## 0.4.3 - 2019-12-17

### Added

- Nothing.

### Changed

- Nothing.

### Deprecated

- Nothing.

### Removed

- Nothing.

### Fixed

- [#39](https://github.com/laminas/laminas-zendframework-bridge/pull/39) fixes an issue when using the Auryn DI container. The class `Northwoods\Container\Zend\Config` was incorrectly being renamed to `Northwoods\Container\Laminas\Config` (which should not happen, as it is not a class under our control).

## 0.4.2 - 2019-12-16

### Added

- Nothing.

### Changed

- Nothing.

### Deprecated

- Nothing.

### Removed

- Nothing.

### Fixed

- [#36](https://github.com/laminas/laminas-zendframework-bridge/pull/36) adds some cases for classes that contain the verbiage "Expressive" and "Apigility" ot ensure they are rewritten correctly.

## 0.4.1 - 2019-12-10

### Added

- Nothing.

### Changed

- Nothing.

### Deprecated

- Nothing.

### Removed

- Nothing.

### Fixed

- [#35](https://github.com/laminas/laminas-zendframework-bridge/pull/35) removes zend-debug from the replacement list, as it is not being brought over to Laminas.

## 0.4.0 - 2019-11-27

### Added

- Nothing.

### Changed

- [#32](https://github.com/laminas/laminas-zendframework-bridge/pull/32) changes all references to Expressive to instead reference Mezzio.

- [#32](https://github.com/laminas/laminas-zendframework-bridge/pull/32) changes all references to Apigility to instead reference Laminas API Tools. The vendor becomes laminas-api-tools, the URL becomes api-tools.getlaminas.org, packages and repos are prefixed with api-tools, and namespaces become `Laminas\ApiTools`.

### Deprecated

- Nothing.

### Removed

- Nothing.

### Fixed

- Nothing.

## 0.3.8 - 2019-11-14

### Added

- [#29](https://github.com/laminas/laminas-zendframework-bridge/pull/29) adds entries to translate `ZendDeveloperTools` to `Laminas\DeveloperTools`, and vice-versa.

### Changed

- Nothing.

### Deprecated

- Nothing.

### Removed

- Nothing.

### Fixed

- Nothing.

## 0.3.7 - 2019-11-12

### Added

- Nothing.

### Changed

- Nothing.

### Deprecated

- Nothing.

### Removed

- Nothing.

### Fixed

- [#28](https://github.com/laminas/laminas-zendframework-bridge/pull/28) updates the `zenddevelopertools` string to rewrite to `laminas-developer-tools` instead of `laminasdevelopertools`.

## 0.3.6 - 2019-11-07

### Added

- Nothing.

### Changed

- Nothing.

### Deprecated

- Nothing.

### Removed

- Nothing.

### Fixed

- [#27](https://github.com/laminas/laminas-zendframework-bridge/pull/27) adds a rewrite rule for zend-framework.flf => laminas-project.flf.

## 0.3.5 - 2019-11-06

### Added

- Nothing.

### Changed

- Nothing.

### Deprecated

- Nothing.

### Removed

- Nothing.

### Fixed

- [#25](https://github.com/laminas/laminas-zendframework-bridge/pull/25) adds entries for ZendHttp and ZendModule, which are file name segments in files from the zend-feed and zend-config-aggregator-module packages, respectively.

## 0.3.4 - 2019-11-06

### Added

- Nothing.

### Changed

- Nothing.

### Deprecated

- Nothing.

### Removed

- Nothing.

### Fixed

- [#24](https://github.com/laminas/laminas-zendframework-bridge/pull/24) adds a rule to never rewrite the string `Doctrine\Zend`.

- [#23](https://github.com/laminas/laminas-zendframework-bridge/pull/23) adds a missing map for each of ZendAcl and ZendRbac, which occur in the zend-expressive-authorization-acl and zend-expressive-authorization-rbac packages, respectively.

## 0.3.3 - 2019-11-06

### Added

- [#22](https://github.com/laminas/laminas-zendframework-bridge/pull/22) adds configuration post-processing features, exposed both as a laminas-config-aggregator post processor (for use with Expressive applications) and as a laminas-modulemanager `EVENT_MERGE_CONFIG` listener (for use with MVC applications). When registered, it will post-process the configuration, replacing known Zend Framework-specific strings with their Laminas replacements. A ruleset is provided that ensures dependency configuration is rewritten in a safe manner, routing configuration is skipped, and certain top-level configuration keys are matched exactly (instead of potentially as substrings or word stems). A later release of laminas-migration will auto-register these tools in applications when possible.

### Changed

- [#22](https://github.com/laminas/laminas-zendframework-bridge/pull/22) removes support for PHP versions prior to PHP 5.6. We have decided to only support supported PHP versions, whether that support is via php.net or commercial. The lowest supported PHP version we have found is 5.6. Users wishing to migrate to Laminas must at least update to PHP 5.6 before doing so.

### Deprecated

- Nothing.

### Removed

- Nothing.

### Fixed

- Nothing.

## 0.3.2 - 2019-10-30

### Added

- Nothing.

### Changed

- Nothing.

### Deprecated

- Nothing.

### Removed

- [#21](https://github.com/laminas/laminas-zendframework-bridge/pull/21) removes rewriting of the Amazon library, as it is not moving to Laminas.

- [#21](https://github.com/laminas/laminas-zendframework-bridge/pull/21) removes rewriting of the GCM and APNS libraries, as they are not moving to Laminas.

### Fixed

- [#21](https://github.com/laminas/laminas-zendframework-bridge/pull/21) fixes how the recaptcha and twitter library package and namespaces are rewritten.

## 0.3.1 - 2019-04-25

### Added

- [#20](https://github.com/laminas/laminas-zendframework-bridge/pull/20) provides an additional autoloader that is _prepended_ to the autoloader
  stack. This new autoloader will create class aliases for interfaces, classes,
  and traits referenced in type hints and class declarations, ensuring PHP is
  able to resolve them correctly during class_alias operations.

### Changed

- Nothing.

### Deprecated

- Nothing.

### Removed

- Nothing.

### Fixed

- Nothing.

## 0.3.0 - 2019-04-12

### Added

- Nothing.

### Changed

- Nothing.

### Deprecated

- Nothing.

### Removed

- [#16](https://github.com/laminas/laminas-zendframework-bridge/pull/16) removes the `RewriteRules::classRewrite()` method, as it is no longer
  needed due to internal refactoring.

### Fixed

- [#16](https://github.com/laminas/laminas-zendframework-bridge/pull/16) fixes how the rewrite rules detect the word `Zend` in subnamespaces and
  class names to be both more robust and simpler.

## 0.2.5 - 2019-04-11

### Added

- [#12](https://github.com/laminas/laminas-zendframework-bridge/pull/12) adds functionality for ensuring we alias namespaces and classes that
  include the word `Zend` in them; e.g., `Zend\Expressive\ZendView\ZendViewRendererFactory`
  will now alias to `Expressive\LaminasView\LaminasViewRendererFactory`.

### Changed

- Nothing.

### Deprecated

- Nothing.

### Removed

- Nothing.

### Fixed

- Nothing.

## 0.2.4 - 2019-04-11

### Added

- [#11](https://github.com/laminas/laminas-zendframework-bridge/pull/11) adds maps for the Expressive router adapter packages.

- [#10](https://github.com/laminas/laminas-zendframework-bridge/pull/10) adds a map for the Psr7Bridge package, as it used `Zend` within a subnamespace.

### Changed

- Nothing.

### Deprecated

- Nothing.

### Removed

- Nothing.

### Fixed

- Nothing.

## 0.2.3 - 2019-04-10

### Added

- Nothing.

### Changed

- Nothing.

### Deprecated

- Nothing.

### Removed

- Nothing.

### Fixed

- [#9](https://github.com/laminas/laminas-zendframework-bridge/pull/9) fixes the mapping for the Problem Details package.

## 0.2.2 - 2019-04-10

### Added

- Nothing.

### Changed

- Nothing.

### Deprecated

- Nothing.

### Removed

- Nothing.

### Fixed

- Added a check that the discovered alias exists as a class, interface, or trait
  before attempting to call `class_alias()`.

## 0.2.1 - 2019-04-10

### Added

- Nothing.

### Changed

- Nothing.

### Deprecated

- Nothing.

### Removed

- Nothing.

### Fixed

- [#8](https://github.com/laminas/laminas-zendframework-bridge/pull/8) fixes mappings for each of zend-expressive-authentication-zendauthentication,
  zend-expressive-zendrouter, and zend-expressive-zendviewrenderer.

## 0.2.0 - 2019-04-01

### Added

- Nothing.

### Changed

- [#4](https://github.com/laminas/laminas-zendframework-bridge/pull/4) rewrites the autoloader to be class-based, via the class
  `Laminas\ZendFrameworkBridge\Autoloader`. Additionally, the new approach
  provides a performance boost by using a balanced tree algorithm, ensuring
  matches occur faster.

### Deprecated

- Nothing.

### Removed

- [#4](https://github.com/laminas/laminas-zendframework-bridge/pull/4) removes function aliasing. Function aliasing will move to the packages that
  provide functions.

### Fixed

- Nothing.

## 0.1.0 - 2019-03-27

### Added

- Adds an autoloader file that registers with `spl_autoload_register` a routine
  for aliasing legacy ZF class/interface/trait names to Laminas Project
  equivalents.

- Adds autoloader files for aliasing legacy ZF package functions to Laminas
  Project equivalents.

### Changed

- Nothing.

### Deprecated

- Nothing.

### Removed

- Nothing.

### Fixed

- Nothing.
laminas-zendframework-bridge/LICENSE.md000064400000002732147361032560013715 0ustar00Copyright (c) 2020 Laminas Project a Series of LF Projects, LLC.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

- Redistributions of source code must retain the above copyright notice, this
  list of conditions and the following disclaimer.

- Redistributions in binary form must reproduce the above copyright notice,
  this list of conditions and the following disclaimer in the documentation
  and/or other materials provided with the distribution.

- Neither the name of Laminas Foundation nor the names of its contributors may
  be used to endorse or promote products derived from this software without
  specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
laminas-httphandlerrunner/COPYRIGHT.md000064400000000133147361032560013633 0ustar00Copyright (c) 2020 Laminas Project a Series of LF Projects, LLC. (https://getlaminas.org/)
laminas-httphandlerrunner/src/Emitter/SapiEmitterTrait.php000064400000006111147361032560020106 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-httphandlerrunner for the canonical source repository
 * @copyright https://github.com/laminas/laminas-httphandlerrunner/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-httphandlerrunner/blob/master/LICENSE.md New BSD License
 */

declare(strict_types=1);

namespace Laminas\HttpHandlerRunner\Emitter;

use Laminas\HttpHandlerRunner\Exception\EmitterException;
use Psr\Http\Message\ResponseInterface;

use function ob_get_length;
use function ob_get_level;
use function sprintf;
use function str_replace;
use function ucwords;

trait SapiEmitterTrait
{
    /**
     * Checks to see if content has previously been sent.
     *
     * If either headers have been sent or the output buffer contains content,
     * raises an exception.
     *
     * @throws EmitterException if headers have already been sent.
     * @throws EmitterException if output is present in the output buffer.
     */
    private function assertNoPreviousOutput()
    {
        if (headers_sent()) {
            throw EmitterException::forHeadersSent();
        }

        if (ob_get_level() > 0 && ob_get_length() > 0) {
            throw EmitterException::forOutputSent();
        }
    }

    /**
     * Emit the status line.
     *
     * Emits the status line using the protocol version and status code from
     * the response; if a reason phrase is available, it, too, is emitted.
     *
     * It is important to mention that this method should be called after
     * `emitHeaders()` in order to prevent PHP from changing the status code of
     * the emitted response.
     *
     * @see \Laminas\HttpHandlerRunner\Emitter\SapiEmitterTrait::emitHeaders()
     */
    private function emitStatusLine(ResponseInterface $response) : void
    {
        $reasonPhrase = $response->getReasonPhrase();
        $statusCode   = $response->getStatusCode();

        header(sprintf(
            'HTTP/%s %d%s',
            $response->getProtocolVersion(),
            $statusCode,
            ($reasonPhrase ? ' ' . $reasonPhrase : '')
        ), true, $statusCode);
    }

    /**
     * Emit response headers.
     *
     * Loops through each header, emitting each; if the header value
     * is an array with multiple values, ensures that each is sent
     * in such a way as to create aggregate headers (instead of replace
     * the previous).
     */
    private function emitHeaders(ResponseInterface $response) : void
    {
        $statusCode = $response->getStatusCode();

        foreach ($response->getHeaders() as $header => $values) {
            $name  = $this->filterHeader($header);
            $first = $name === 'Set-Cookie' ? false : true;
            foreach ($values as $value) {
                header(sprintf(
                    '%s: %s',
                    $name,
                    $value
                ), $first, $statusCode);
                $first = false;
            }
        }
    }

    /**
     * Filter a header name to wordcase
     */
    private function filterHeader(string $header) : string
    {
        return ucwords($header, '-');
    }
}
laminas-httphandlerrunner/src/Emitter/SapiEmitter.php000064400000002133147361032560017102 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-httphandlerrunner for the canonical source repository
 * @copyright https://github.com/laminas/laminas-httphandlerrunner/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-httphandlerrunner/blob/master/LICENSE.md New BSD License
 */

declare(strict_types=1);

namespace Laminas\HttpHandlerRunner\Emitter;

use Psr\Http\Message\ResponseInterface;

class SapiEmitter implements EmitterInterface
{
    use SapiEmitterTrait;

    /**
     * Emits a response for a PHP SAPI environment.
     *
     * Emits the status line and headers via the header() function, and the
     * body content via the output buffer.
     */
    public function emit(ResponseInterface $response) : bool
    {
        $this->assertNoPreviousOutput();

        $this->emitHeaders($response);
        $this->emitStatusLine($response);
        $this->emitBody($response);

        return true;
    }

    /**
     * Emit the message body.
     */
    private function emitBody(ResponseInterface $response) : void
    {
        echo $response->getBody();
    }
}
laminas-httphandlerrunner/src/Emitter/EmitterStack.php000064400000005432147361032560017260 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-httphandlerrunner for the canonical source repository
 * @copyright https://github.com/laminas/laminas-httphandlerrunner/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-httphandlerrunner/blob/master/LICENSE.md New BSD License
 */

declare(strict_types=1);

namespace Laminas\HttpHandlerRunner\Emitter;

use Laminas\HttpHandlerRunner\Exception;
use Psr\Http\Message\ResponseInterface;
use SplStack;

/**
 * Provides an EmitterInterface implementation that acts as a stack of Emitters.
 *
 * The implementations emit() method iterates itself.
 *
 * When iterating the stack, the first emitter to return a boolean
 * true value will short-circuit iteration.
 */
class EmitterStack extends SplStack implements EmitterInterface
{
    /**
     * Emit a response
     *
     * Loops through the stack, calling emit() on each; any that return a
     * boolean true value will short-circuit, skipping any remaining emitters
     * in the stack.
     *
     * As such, return a boolean false value from an emitter to indicate it
     * cannot emit the response, allowing the next emitter to try.
     */
    public function emit(ResponseInterface $response) : bool
    {
        foreach ($this as $emitter) {
            if (false !== $emitter->emit($response)) {
                return true;
            }
        }

        return false;
    }

    /**
     * Set an emitter on the stack by index.
     *
     * @param mixed $index
     * @param EmitterInterface $emitter
     * @return void
     * @throws InvalidArgumentException if not an EmitterInterface instance
     */
    public function offsetSet($index, $emitter)
    {
        $this->validateEmitter($emitter);
        parent::offsetSet($index, $emitter);
    }

    /**
     * Push an emitter to the stack.
     *
     * @param EmitterInterface $emitter
     * @return void
     * @throws InvalidArgumentException if not an EmitterInterface instance
     */
    public function push($emitter)
    {
        $this->validateEmitter($emitter);
        parent::push($emitter);
    }

    /**
     * Unshift an emitter to the stack.
     *
     * @param EmitterInterface $emitter
     * @return void
     * @throws InvalidArgumentException if not an EmitterInterface instance
     */
    public function unshift($emitter)
    {
        $this->validateEmitter($emitter);
        parent::unshift($emitter);
    }

    /**
     * Validate that an emitter implements EmitterInterface.
     *
     * @param mixed $emitter
     * @throws Exception\InvalidEmitterException for non-emitter instances
     */
    private function validateEmitter($emitter) : void
    {
        if (! $emitter instanceof EmitterInterface) {
            throw Exception\InvalidEmitterException::forEmitter($emitter);
        }
    }
}
laminas-httphandlerrunner/src/Emitter/SapiStreamEmitter.php000064400000006703147361032560020265 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-httphandlerrunner for the canonical source repository
 * @copyright https://github.com/laminas/laminas-httphandlerrunner/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-httphandlerrunner/blob/master/LICENSE.md New BSD License
 */

declare(strict_types=1);

namespace Laminas\HttpHandlerRunner\Emitter;

use Psr\Http\Message\ResponseInterface;

use function preg_match;
use function strlen;
use function substr;

class SapiStreamEmitter implements EmitterInterface
{
    use SapiEmitterTrait;

    /**
     * @var int Maximum output buffering size for each iteration.
     */
    private $maxBufferLength;

    public function __construct(int $maxBufferLength = 8192)
    {
        $this->maxBufferLength = $maxBufferLength;
    }

    /**
     * Emits a response for a PHP SAPI environment.
     *
     * Emits the status line and headers via the header() function, and the
     * body content via the output buffer.
     */
    public function emit(ResponseInterface $response) : bool
    {
        $this->assertNoPreviousOutput();
        $this->emitHeaders($response);
        $this->emitStatusLine($response);

        flush();

        $range = $this->parseContentRange($response->getHeaderLine('Content-Range'));

        if (null === $range || 'bytes' !== $range[0]) {
            $this->emitBody($response);
            return true;
        }

        $this->emitBodyRange($range, $response);
        return true;
    }

    /**
     * Emit the message body.
     */
    private function emitBody(ResponseInterface $response) : void
    {
        $body = $response->getBody();

        if ($body->isSeekable()) {
            $body->rewind();
        }

        if (! $body->isReadable()) {
            echo $body;
            return;
        }

        while (! $body->eof()) {
            echo $body->read($this->maxBufferLength);
        }
    }

    /**
     * Emit a range of the message body.
     */
    private function emitBodyRange(array $range, ResponseInterface $response) : void
    {
        list($unit, $first, $last, $length) = $range;

        $body = $response->getBody();

        $length = $last - $first + 1;

        if ($body->isSeekable()) {
            $body->seek($first);

            $first = 0;
        }

        if (! $body->isReadable()) {
            echo substr($body->getContents(), $first, $length);
            return;
        }

        $remaining = $length;

        while ($remaining >= $this->maxBufferLength && ! $body->eof()) {
            $contents   = $body->read($this->maxBufferLength);
            $remaining -= strlen($contents);

            echo $contents;
        }

        if ($remaining > 0 && ! $body->eof()) {
            echo $body->read($remaining);
        }
    }

    /**
     * Parse content-range header
     * http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.16
     *
     * @return null|array [unit, first, last, length]; returns null if no
     *     content range or an invalid content range is provided
     */
    private function parseContentRange(string $header) : ?array
    {
        if (! preg_match('/(?P<unit>[\w]+)\s+(?P<first>\d+)-(?P<last>\d+)\/(?P<length>\d+|\*)/', $header, $matches)) {
            return null;
        }

        return [
            $matches['unit'],
            (int) $matches['first'],
            (int) $matches['last'],
            $matches['length'] === '*' ? '*' : (int) $matches['length'],
        ];
    }
}
laminas-httphandlerrunner/src/Emitter/EmitterInterface.php000064400000002237147361032560020113 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-httphandlerrunner for the canonical source repository
 * @copyright https://github.com/laminas/laminas-httphandlerrunner/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-httphandlerrunner/blob/master/LICENSE.md New BSD License
 */

declare(strict_types=1);

namespace Laminas\HttpHandlerRunner\Emitter;

use Psr\Http\Message\ResponseInterface;

interface EmitterInterface
{
    /**
     * Emit a response.
     *
     * Emits a response, including status line, headers, and the message body,
     * according to the environment.
     *
     * Implementations of this method may be written in such a way as to have
     * side effects, such as usage of header() or pushing output to the
     * output buffer.
     *
     * Implementations MAY raise exceptions if they are unable to emit the
     * response; e.g., if headers have already been sent.
     *
     * Implementations MUST return a boolean. A boolean `true` indicates that
     * the emitter was able to emit the response, while `false` indicates
     * it was not.
     */
    public function emit(ResponseInterface $response) : bool;
}
laminas-httphandlerrunner/src/RequestHandlerRunner.php000064400000006372147361032560017374 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-httphandlerrunner for the canonical source repository
 * @copyright https://github.com/laminas/laminas-httphandlerrunner/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-httphandlerrunner/blob/master/LICENSE.md New BSD License
 */

declare(strict_types=1);

namespace Laminas\HttpHandlerRunner;

use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\RequestHandlerInterface;
use Throwable;

/**
 * "Run" a request handler.
 *
 * The RequestHandlerRunner will marshal a request using the composed factory, and
 * then pass the request to the composed handler. Finally, it emits the response
 * returned by the handler using the composed emitter.
 *
 * If the factory for generating the request raises an exception or throwable,
 * then the runner will use the composed error response generator to generate a
 * response, based on the exception or throwable raised.
 */
class RequestHandlerRunner
{
    /**
     * @var Emitter\EmitterInterface
     */
    private $emitter;

    /**
     * A request handler to run as the application.
     *
     * @var RequestHandlerInterface
     */
    private $handler;

    /**
     * A factory capable of generating an error response in the scenario that
     * the $serverRequestFactory raises an exception during generation of the
     * request instance.
     *
     * The factory will receive the Throwable or Exception that caused the error,
     * and must return a Psr\Http\Message\ResponseInterface instance.
     *
     * @var callable
     */
    private $serverRequestErrorResponseGenerator;

    /**
     * A factory capable of generating a Psr\Http\Message\ServerRequestInterface instance.
     * The factory will not receive any arguments.
     *
     * @var callable
     */
    private $serverRequestFactory;

    public function __construct(
        RequestHandlerInterface $handler,
        Emitter\EmitterInterface $emitter,
        callable $serverRequestFactory,
        callable $serverRequestErrorResponseGenerator
    ) {
        $this->handler = $handler;
        $this->emitter = $emitter;

        // Factories are cast as Closures to ensure return type safety.
        $this->serverRequestFactory = function () use ($serverRequestFactory) : ServerRequestInterface {
            return $serverRequestFactory();
        };

        $this->serverRequestErrorResponseGenerator =
            function (Throwable $exception) use ($serverRequestErrorResponseGenerator) : ResponseInterface {
                return $serverRequestErrorResponseGenerator($exception);
            };
    }

    /**
     * Run the application
     */
    public function run() : void
    {
        try {
            $request = ($this->serverRequestFactory)();
        } catch (Throwable $e) {
            // Error in generating the request
            $this->emitMarshalServerRequestException($e);
            return;
        }

        $response = $this->handler->handle($request);

        $this->emitter->emit($response);
    }

    private function emitMarshalServerRequestException(Throwable $exception) : void
    {
        $response = ($this->serverRequestErrorResponseGenerator)($exception);
        $this->emitter->emit($response);
    }
}
laminas-httphandlerrunner/src/ConfigProvider.php000064400000001132147361032560016161 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-httphandlerrunner for the canonical source repository
 * @copyright https://github.com/laminas/laminas-httphandlerrunner/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-httphandlerrunner/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\HttpHandlerRunner;

class ConfigProvider
{
    public function __invoke() : array
    {
        return [
            'dependencies' => $this->getDependencies(),
        ];
    }

    public function getDependencies() : array
    {
        return [
        ];
    }
}
laminas-httphandlerrunner/src/Exception/InvalidEmitterException.php000064400000002036147361032560022002 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-httphandlerrunner for the canonical source repository
 * @copyright https://github.com/laminas/laminas-httphandlerrunner/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-httphandlerrunner/blob/master/LICENSE.md New BSD License
 */

declare(strict_types=1);

namespace Laminas\HttpHandlerRunner\Exception;

use InvalidArgumentException;
use Laminas\HttpHandlerRunner\Emitter;

use function get_class;
use function gettype;
use function is_object;
use function sprintf;

class InvalidEmitterException extends InvalidArgumentException implements ExceptionInterface
{
    /**
     * @var mixed $emitter Invalid emitter type
     */
    public static function forEmitter($emitter) : self
    {
        return new self(sprintf(
            '%s can only compose %s implementations; received %s',
            Emitter\EmitterStack::class,
            Emitter\EmitterInterface::class,
            is_object($emitter) ? get_class($emitter) : gettype($emitter)
        ));
    }
}
laminas-httphandlerrunner/src/Exception/EmitterException.php000064400000001415147361032560020473 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-httphandlerrunner for the canonical source repository
 * @copyright https://github.com/laminas/laminas-httphandlerrunner/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-httphandlerrunner/blob/master/LICENSE.md New BSD License
 */

declare(strict_types=1);

namespace Laminas\HttpHandlerRunner\Exception;

use RuntimeException;

class EmitterException extends RuntimeException implements ExceptionInterface
{
    public static function forHeadersSent() : self
    {
        return new self('Unable to emit response; headers already sent');
    }

    public static function forOutputSent() : self
    {
        return new self('Output has been emitted previously; cannot emit response');
    }
}
laminas-httphandlerrunner/src/Exception/ExceptionInterface.php000064400000000734147361032560020765 0ustar00<?php

/**
 * @see       https://github.com/laminas/laminas-httphandlerrunner for the canonical source repository
 * @copyright https://github.com/laminas/laminas-httphandlerrunner/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-httphandlerrunner/blob/master/LICENSE.md New BSD License
 */

declare(strict_types=1);

namespace Laminas\HttpHandlerRunner\Exception;

/**
 * Marker interface for package exceptions.
 */
interface ExceptionInterface
{
}
laminas-httphandlerrunner/README.md000064400000002364147361032560013230 0ustar00# laminas-httphandlerrunner

[![Build Status](https://travis-ci.com/laminas/laminas-httphandlerrunner.svg?branch=master)](https://travis-ci.com/laminas/laminas-httphandlerrunner)
[![Coverage Status](https://coveralls.io/repos/github/laminas/laminas-httphandlerrunner/badge.svg?branch=master)](https://coveralls.io/github/laminas/laminas-httphandlerrunner?branch=master)

This library provides utilities for:

- Emitting [PSR-7](https://www.php-fig.org/psr/psr-7) responses.
- Running [PSR-15](https://www.php-fig.org/psr/psr-15) server request handlers,
  which involves marshaling a PSR-7 `ServerRequestInterface`, handling
  exceptions due to request creation, and emitting the response returned by the
  composed request handler.

The `RequestHandlerRunner` will be used in the bootstrap of your application to
fire off the `RequestHandlerInterface` representing your application.

## Installation

Run the following to install this library:

```bash
$ composer require laminas/laminas-httphandlerrunner
```

## Documentation

Documentation is [in the doc tree](docs/book/), and can be compiled using [mkdocs](https://www.mkdocs.org):

```bash
$ mkdocs build
```

You may also [browse the documentation online](https://docs.laminas.dev/laminas-httphandlerrunner/).
laminas-httphandlerrunner/CHANGELOG.md000064400000004744147361032560013566 0ustar00# Changelog

All notable changes to this project will be documented in this file, in reverse chronological order by release.

## 1.2.0 - 2020-06-03

### Added

- Nothing.

### Changed

- [#4](https://github.com/laminas/laminas-httphandlerrunner/pull/4) adds a call to `flush()` within the `SapiStreamEmitter`, after emitting headers and the status line, but before emitting content. This change allows providing a response to the browser more quickly, allowing it to process the stream as it is pushed.

### Deprecated

- Nothing.

### Removed

- Nothing.

### Fixed

- Nothing.

## 1.1.0 - 2019-02-19

### Added

- [zendframework/zend-httphandlerrunner#10](https://github.com/zendframework/zend-httphandlerrunner/pull/10) adds support for laminas-diactoros v2 releases.

### Changed

- Nothing.

### Deprecated

- Nothing.

### Removed

- Nothing.

### Fixed

- Nothing.

## 1.0.2 - 2019-02-19

### Added

- [zendframework/zend-httphandlerrunner#9](https://github.com/zendframework/zend-httphandlerrunner/pull/9) adds support for PHP 7.3.

### Changed

- Nothing.

### Deprecated

- Nothing.

### Removed

- Nothing.

### Fixed

- Nothing.

## 1.0.1 - 2018-02-21

### Added

- Nothing.

### Changed

- [zendframework/zend-httphandlerrunner#2](https://github.com/zendframework/zend-httphandlerrunner/pull/2) modifies
  how the request and error response factories are composed with the
  `RequestHandlerRunner` class. In both cases, they are now encapsulated in a
  closure which also defines a return type hint, ensuring that if the factories
  produce an invalid return type, a PHP `TypeError` will be raised.

### Deprecated

- Nothing.

### Removed

- Nothing.

### Fixed

- Nothing.

## 1.0.0 - 2018-02-05

Initial stable release.

The `Laminas\HttpRequestHandler\Emitter` subcomponent was originally released as
part of two packages:

- `EmitterInterface` and the two SAPI emitter implementations were released
  previously as part of the [laminas-diactoros](https://docs.laminas.dev/laminas-daictoros)
  package.

- `EmitterStack` was previously released as part of the
  [mezzio](https://docs.mezzio.dev/mezzio/) package.

These features are mostly verbatim from that package, with minor API changes.

The `RequestHandlerRunner` was originally developed as part of version 3
development of mezzio, but extracted here for general use with
[PSR-15](https://www.php-fig.org/psr/psr-15) applications.

### Added

- Everything.

### Changed

- Nothing.

### Deprecated

- Nothing.

### Removed

- Nothing.

### Fixed

- Nothing.
laminas-httphandlerrunner/LICENSE.md000064400000002732147361032560013354 0ustar00Copyright (c) 2020 Laminas Project a Series of LF Projects, LLC.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

- Redistributions of source code must retain the above copyright notice, this
  list of conditions and the following disclaimer.

- Redistributions in binary form must reproduce the above copyright notice,
  this list of conditions and the following disclaimer in the documentation
  and/or other materials provided with the distribution.

- Neither the name of Laminas Foundation nor the names of its contributors may
  be used to endorse or promote products derived from this software without
  specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.