<?php
/**
 * @link http://www.yiiframework.com/
 * @copyright Copyright (c) 2008 Yii Software LLC
 * @license http://www.yiiframework.com/license/
 */

namespace yii\web;

use Yii;
use yii\base\Component;
use yii\base\InvalidConfigException;
use yii\base\InvalidParamException;
use yii\helpers\FileHelper;
use yii\helpers\Url;

/**
 * AssetManager manages asset bundle configuration and loading.
 *
 * AssetManager is configured as an application component in [[\yii\web\Application]] by default.
 * You can access that instance via `Yii::$app->assetManager`.
 *
 * You can modify its configuration by adding an array to your application config under `components`
 * as shown in the following example:
 *
 * ```php
 * 'assetManager' => [
 *     'bundles' => [
 *         // you can override AssetBundle configs here
 *     ],
 * ]
 * ```
 *
 * @property AssetConverterInterface $converter The asset converter. Note that the type of this property
 * differs in getter and setter. See [[getConverter()]] and [[setConverter()]] for details.
 *
 * @author Qiang Xue <qiang.xue@gmail.com>
 * @since 2.0
 */
class AssetManager extends Component
{
    /**
     * @var array|boolean list of asset bundle configurations. This property is provided to customize asset bundles.
     * When a bundle is being loaded by [[getBundle()]], if it has a corresponding configuration specified here,
     * the configuration will be applied to the bundle.
     *
     * The array keys are the asset bundle names, which typically are asset bundle class names without leading backslash.
     * The array values are the corresponding configurations. If a value is false, it means the corresponding asset
     * bundle is disabled and [[getBundle()]] should return null.
     *
     * If this property is false, it means the whole asset bundle feature is disabled and [[getBundle()]]
     * will always return null.
     *
     * The following example shows how to disable the bootstrap css file used by Bootstrap widgets
     * (because you want to use your own styles):
     *
     * ```php
     * [
     *     'yii\bootstrap\BootstrapAsset' => [
     *         'css' => [],
     *     ],
     * ]
     * ```
     */
    public $bundles = [];
    /**
     * @var string the root directory storing the published asset files.
     */
    public $basePath = '@webroot/assets';
    /**
     * @var string the base URL through which the published asset files can be accessed.
     */
    public $baseUrl = '@web/assets';
    /**
     * @var array mapping from source asset files (keys) to target asset files (values).
     *
     * This property is provided to support fixing incorrect asset file paths in some asset bundles.
     * When an asset bundle is registered with a view, each relative asset file in its [[AssetBundle::css|css]]
     * and [[AssetBundle::js|js]] arrays will be examined against this map. If any of the keys is found
     * to be the last part of an asset file (which is prefixed with [[AssetBundle::sourcePath]] if available),
     * the corresponding value will replace the asset and be registered with the view.
     * For example, an asset file `my/path/to/jquery.js` matches a key `jquery.js`.
     *
     * Note that the target asset files should be absolute URLs, domain relative URLs (starting from '/') or paths
     * relative to [[baseUrl]] and [[basePath]].
     *
     * In the following example, any assets ending with `jquery.min.js` will be replaced with `jquery/dist/jquery.js`
     * which is relative to [[baseUrl]] and [[basePath]].
     *
     * ```php
     * [
     *     'jquery.min.js' => 'jquery/dist/jquery.js',
     * ]
     * ```
     *
     * You may also use aliases while specifying map value, for example:
     *
     * ```php
     * [
     *     'jquery.min.js' => '@web/js/jquery/jquery.js',
     * ]
     * ```
     */
    public $assetMap = [];
    /**
     * @var boolean whether to use symbolic link to publish asset files. Defaults to false, meaning
     * asset files are copied to [[basePath]]. Using symbolic links has the benefit that the published
     * assets will always be consistent with the source assets and there is no copy operation required.
     * This is especially useful during development.
     *
     * However, there are special requirements for hosting environments in order to use symbolic links.
     * In particular, symbolic links are supported only on Linux/Unix, and Windows Vista/2008 or greater.
     *
     * Moreover, some Web servers need to be properly configured so that the linked assets are accessible
     * to Web users. For example, for Apache Web server, the following configuration directive should be added
     * for the Web folder:
     *
     * ```apache
     * Options FollowSymLinks
     * ```
     */
    public $linkAssets = false;
    /**
     * @var integer the permission to be set for newly published asset files.
     * This value will be used by PHP chmod() function. No umask will be applied.
     * If not set, the permission will be determined by the current environment.
     */
    public $fileMode;
    /**
     * @var integer the permission to be set for newly generated asset directories.
     * This value will be used by PHP chmod() function. No umask will be applied.
     * Defaults to 0775, meaning the directory is read-writable by owner and group,
     * but read-only for other users.
     */
    public $dirMode = 0775;
    /**
     * @var callback a PHP callback that is called before copying each sub-directory or file.
     * This option is used only when publishing a directory. If the callback returns false, the copy
     * operation for the sub-directory or file will be cancelled.
     *
     * The signature of the callback should be: `function ($from, $to)`, where `$from` is the sub-directory or
     * file to be copied from, while `$to` is the copy target.
     *
     * This is passed as a parameter `beforeCopy` to [[\yii\helpers\FileHelper::copyDirectory()]].
     */
    public $beforeCopy;
    /**
     * @var callback a PHP callback that is called after a sub-directory or file is successfully copied.
     * This option is used only when publishing a directory. The signature of the callback is the same as
     * for [[beforeCopy]].
     * This is passed as a parameter `afterCopy` to [[\yii\helpers\FileHelper::copyDirectory()]].
     */
    public $afterCopy;
    /**
     * @var boolean whether the directory being published should be copied even if
     * it is found in the target directory. This option is used only when publishing a directory.
     * You may want to set this to be `true` during the development stage to make sure the published
     * directory is always up-to-date. Do not set this to true on production servers as it will
     * significantly degrade the performance.
     */
    public $forceCopy = false;
    /**
     * @var boolean whether to append a timestamp to the URL of every published asset. When this is true,
     * the URL of a published asset may look like `/path/to/asset?v=timestamp`, where `timestamp` is the
     * last modification time of the published asset file.
     * You normally would want to set this property to true when you have enabled HTTP caching for assets,
     * because it allows you to bust caching when the assets are updated.
     * @since 2.0.3
     */
    public $appendTimestamp = false;
    /**
     * @var callable a callback that will be called to produce hash for asset directory generation.
     * The signature of the callback should be as follows:
     *
     * ```
     * function ($path)
     * ```
     *
     * where `$path` is the asset path. Note that the `$path` can be either directory where the asset
     * files reside or a single file. For a CSS file that uses relative path in `url()`, the hash
     * implementation should use the directory path of the file instead of the file path to include
     * the relative asset files in the copying.
     *
     * If this is not set, the asset manager will use the default CRC32 and filemtime in the `hash`
     * method.
     *
     * Example of an implementation using MD4 hash:
     *
     * ```php
     * function ($path) {
     *     return hash('md4', $path);
     * }
     * ```
     *
     * @since 2.0.6
     */
    public $hashCallback;

    private $_dummyBundles = [];

    /**
     * Initializes the component.
     * @throws InvalidConfigException if [[basePath]] is invalid
     */
    public function init()
    {
        parent::init();
        $this->basePath = Yii::getAlias($this->basePath);
        if (!is_dir($this->basePath)) {
            throw new InvalidConfigException("The directory does not exist: {$this->basePath}");
        } elseif (!is_writable($this->basePath)) {
            throw new InvalidConfigException("The directory is not writable by the Web process: {$this->basePath}");
        } else {
            $this->basePath = realpath($this->basePath);
        }
        $this->baseUrl = rtrim(Yii::getAlias($this->baseUrl), '/');
    }

    /**
     * Returns the named asset bundle.
     *
     * This method will first look for the bundle in [[bundles]]. If not found,
     * it will treat `$name` as the class of the asset bundle and create a new instance of it.
     *
     * @param string $name the class name of the asset bundle (without the leading backslash)
     * @param boolean $publish whether to publish the asset files in the asset bundle before it is returned.
     * If you set this false, you must manually call `AssetBundle::publish()` to publish the asset files.
     * @return AssetBundle the asset bundle instance
     * @throws InvalidConfigException if $name does not refer to a valid asset bundle
     */
    public function getBundle($name, $publish = true)
    {
        if ($this->bundles === false) {
            return $this->loadDummyBundle($name);
        } elseif (!isset($this->bundles[$name])) {
            return $this->bundles[$name] = $this->loadBundle($name, [], $publish);
        } elseif ($this->bundles[$name] instanceof AssetBundle) {
            return $this->bundles[$name];
        } elseif (is_array($this->bundles[$name])) {
            return $this->bundles[$name] = $this->loadBundle($name, $this->bundles[$name], $publish);
        } elseif ($this->bundles[$name] === false) {
            return $this->loadDummyBundle($name);
        } else {
            throw new InvalidConfigException("Invalid asset bundle configuration: $name");
        }
    }

    /**
     * Loads asset bundle class by name
     *
     * @param string $name bundle name
     * @param array $config bundle object configuration
     * @param boolean $publish if bundle should be published
     * @return AssetBundle
     * @throws InvalidConfigException if configuration isn't valid
     */
    protected function loadBundle($name, $config = [], $publish = true)
    {
        if (!isset($config['class'])) {
            $config['class'] = $name;
        }
        /* @var $bundle AssetBundle */
        $bundle = Yii::createObject($config);
        if ($publish) {
            $bundle->publish($this);
        }
        return $bundle;
    }

    /**
     * Loads dummy bundle by name
     *
     * @param string $name
     * @return AssetBundle
     */
    protected function loadDummyBundle($name)
    {
        if (!isset($this->_dummyBundles[$name])) {
            $this->_dummyBundles[$name] = $this->loadBundle($name, [
                'sourcePath' => null,
                'js' => [],
                'css' => [],
                'depends' => [],
            ]);
        }
        return $this->_dummyBundles[$name];
    }

    /**
     * Returns the actual URL for the specified asset.
     * The actual URL is obtained by prepending either [[baseUrl]] or [[AssetManager::baseUrl]] to the given asset path.
     * @param AssetBundle $bundle the asset bundle which the asset file belongs to
     * @param string $asset the asset path. This should be one of the assets listed in [[js]] or [[css]].
     * @return string the actual URL for the specified asset.
     */
    public function getAssetUrl($bundle, $asset)
    {
        if (($actualAsset = $this->resolveAsset($bundle, $asset)) !== false) {
            if (strncmp($actualAsset, '@web/', 5) === 0) {
                $asset = substr($actualAsset, 5);
                $basePath = Yii::getAlias('@webroot');
                $baseUrl = Yii::getAlias('@web');
            } else {
                $asset = Yii::getAlias($actualAsset);
                $basePath = $this->basePath;
                $baseUrl = $this->baseUrl;
            }
        } else {
            $basePath = $bundle->basePath;
            $baseUrl = $bundle->baseUrl;
        }

        if (!Url::isRelative($asset) || strncmp($asset, '/', 1) === 0) {
            return $asset;
        }

        if ($this->appendTimestamp && ($timestamp = @filemtime("$basePath/$asset")) > 0) {
            return "$baseUrl/$asset?v=$timestamp";
        } else {
            return "$baseUrl/$asset";
        }
    }

    /**
     * Returns the actual file path for the specified asset.
     * @param AssetBundle $bundle the asset bundle which the asset file belongs to
     * @param string $asset the asset path. This should be one of the assets listed in [[js]] or [[css]].
     * @return string|boolean the actual file path, or false if the asset is specified as an absolute URL
     */
    public function getAssetPath($bundle, $asset)
    {
        if (($actualAsset = $this->resolveAsset($bundle, $asset)) !== false) {
            return Url::isRelative($actualAsset) ? $this->basePath . '/' . $actualAsset : false;
        } else {
            return Url::isRelative($asset) ? $bundle->basePath . '/' . $asset : false;
        }
    }

    /**
     * @param AssetBundle $bundle
     * @param string $asset
     * @return string|boolean
     */
    protected function resolveAsset($bundle, $asset)
    {
        if (isset($this->assetMap[$asset])) {
            return $this->assetMap[$asset];
        }
        if ($bundle->sourcePath !== null && Url::isRelative($asset)) {
            $asset = $bundle->sourcePath . '/' . $asset;
        }

        $n = mb_strlen($asset, Yii::$app->charset);
        foreach ($this->assetMap as $from => $to) {
            $n2 = mb_strlen($from, Yii::$app->charset);
            if ($n2 <= $n && substr_compare($asset, $from, $n - $n2, $n2) === 0) {
                return $to;
            }
        }

        return false;
    }

    private $_converter;

    /**
     * Returns the asset converter.
     * @return AssetConverterInterface the asset converter.
     */
    public function getConverter()
    {
        if ($this->_converter === null) {
            $this->_converter = Yii::createObject(AssetConverter::className());
        } elseif (is_array($this->_converter) || is_string($this->_converter)) {
            if (is_array($this->_converter) && !isset($this->_converter['class'])) {
                $this->_converter['class'] = AssetConverter::className();
            }
            $this->_converter = Yii::createObject($this->_converter);
        }

        return $this->_converter;
    }

    /**
     * Sets the asset converter.
     * @param array|AssetConverterInterface $value the asset converter. This can be either
     * an object implementing the [[AssetConverterInterface]], or a configuration
     * array that can be used to create the asset converter object.
     */
    public function setConverter($value)
    {
        $this->_converter = $value;
    }

    /**
     * @var array published assets
     */
    private $_published = [];

    /**
     * Publishes a file or a directory.
     *
     * This method will copy the specified file or directory to [[basePath]] so that
     * it can be accessed via the Web server.
     *
     * If the asset is a file, its file modification time will be checked to avoid
     * unnecessary file copying.
     *
     * If the asset is a directory, all files and subdirectories under it will be published recursively.
     * Note, in case $forceCopy is false the method only checks the existence of the target
     * directory to avoid repetitive copying (which is very expensive).
     *
     * By default, when publishing a directory, subdirectories and files whose name starts with a dot "."
     * will NOT be published. If you want to change this behavior, you may specify the "beforeCopy" option
     * as explained in the `$options` parameter.
     *
     * Note: On rare scenario, a race condition can develop that will lead to a
     * one-time-manifestation of a non-critical problem in the creation of the directory
     * that holds the published assets. This problem can be avoided altogether by 'requesting'
     * in advance all the resources that are supposed to trigger a 'publish()' call, and doing
     * that in the application deployment phase, before system goes live. See more in the following
     * discussion: http://code.google.com/p/yii/issues/detail?id=2579
     *
     * @param string $path the asset (file or directory) to be published
     * @param array $options the options to be applied when publishing a directory.
     * The following options are supported:
     *
     * - only: array, list of patterns that the file paths should match if they want to be copied.
     * - except: array, list of patterns that the files or directories should match if they want to be excluded from being copied.
     * - caseSensitive: boolean, whether patterns specified at "only" or "except" should be case sensitive. Defaults to true.
     * - beforeCopy: callback, a PHP callback that is called before copying each sub-directory or file.
     *   This overrides [[beforeCopy]] if set.
     * - afterCopy: callback, a PHP callback that is called after a sub-directory or file is successfully copied.
     *   This overrides [[afterCopy]] if set.
     * - forceCopy: boolean, whether the directory being published should be copied even if
     *   it is found in the target directory. This option is used only when publishing a directory.
     *   This overrides [[forceCopy]] if set.
     *
     * @return array the path (directory or file path) and the URL that the asset is published as.
     * @throws InvalidParamException if the asset to be published does not exist.
     */
    public function publish($path, $options = [])
    {
        $path = Yii::getAlias($path);

        if (isset($this->_published[$path])) {
            return $this->_published[$path];
        }

        if (!is_string($path) || ($src = realpath($path)) === false) {
            throw new InvalidParamException("The file or directory to be published does not exist: $path");
        }

        if (is_file($src)) {
            return $this->_published[$path] = $this->publishFile($src);
        } else {
            return $this->_published[$path] = $this->publishDirectory($src, $options);
        }
    }

    /**
     * Publishes a file.
     * @param string $src the asset file to be published
     * @return array the path and the URL that the asset is published as.
     * @throws InvalidParamException if the asset to be published does not exist.
     */
    protected function publishFile($src)
    {
        $dir = $this->hash($src);
        $fileName = basename($src);
        $dstDir = $this->basePath . DIRECTORY_SEPARATOR . $dir;
        $dstFile = $dstDir . DIRECTORY_SEPARATOR . $fileName;

        if (!is_dir($dstDir)) {
            FileHelper::createDirectory($dstDir, $this->dirMode, true);
        }

        if ($this->linkAssets) {
            if (!is_file($dstFile)) {
                symlink($src, $dstFile);
            }
        } elseif (@filemtime($dstFile) < @filemtime($src)) {
            copy($src, $dstFile);
            if ($this->fileMode !== null) {
                @chmod($dstFile, $this->fileMode);
            }
        }

        return [$dstFile, $this->baseUrl . "/$dir/$fileName"];
    }

    /**
     * Publishes a directory.
     * @param string $src the asset directory to be published
     * @param array $options the options to be applied when publishing a directory.
     * The following options are supported:
     *
     * - only: array, list of patterns that the file paths should match if they want to be copied.
     * - except: array, list of patterns that the files or directories should match if they want to be excluded from being copied.
     * - caseSensitive: boolean, whether patterns specified at "only" or "except" should be case sensitive. Defaults to true.
     * - beforeCopy: callback, a PHP callback that is called before copying each sub-directory or file.
     *   This overrides [[beforeCopy]] if set.
     * - afterCopy: callback, a PHP callback that is called after a sub-directory or file is successfully copied.
     *   This overrides [[afterCopy]] if set.
     * - forceCopy: boolean, whether the directory being published should be copied even if
     *   it is found in the target directory. This option is used only when publishing a directory.
     *   This overrides [[forceCopy]] if set.
     *
     * @return array the path directory and the URL that the asset is published as.
     * @throws InvalidParamException if the asset to be published does not exist.
     */
    protected function publishDirectory($src, $options)
    {
        $dir = $this->hash($src);
        $dstDir = $this->basePath . DIRECTORY_SEPARATOR . $dir;
        if ($this->linkAssets) {
            if (!is_dir($dstDir)) {
                FileHelper::createDirectory(dirname($dstDir), $this->dirMode, true);
                symlink($src, $dstDir);
            }
        } elseif (!empty($options['forceCopy']) || ($this->forceCopy && !isset($options['forceCopy'])) || !is_dir($dstDir)) {
            $opts = array_merge(
                $options,
                [
                    'dirMode' => $this->dirMode,
                    'fileMode' => $this->fileMode,
                ]
            );
            if (!isset($opts['beforeCopy'])) {
                if ($this->beforeCopy !== null) {
                    $opts['beforeCopy'] = $this->beforeCopy;
                } else {
                    $opts['beforeCopy'] = function ($from, $to) {
                        return strncmp(basename($from), '.', 1) !== 0;
                    };
                }
            }
            if (!isset($opts['afterCopy']) && $this->afterCopy !== null) {
                $opts['afterCopy'] = $this->afterCopy;
            }
            FileHelper::copyDirectory($src, $dstDir, $opts);
        }

        return [$dstDir, $this->baseUrl . '/' . $dir];
    }

    /**
     * Returns the published path of a file path.
     * This method does not perform any publishing. It merely tells you
     * if the file or directory is published, where it will go.
     * @param string $path directory or file path being published
     * @return string|false string the published file path. False if the file or directory does not exist
     */
    public function getPublishedPath($path)
    {
        $path = Yii::getAlias($path);

        if (isset($this->_published[$path])) {
            return $this->_published[$path][0];
        }
        if (is_string($path) && ($path = realpath($path)) !== false) {
            return $this->basePath . DIRECTORY_SEPARATOR . $this->hash($path) . (is_file($path) ? DIRECTORY_SEPARATOR . basename($path) : '');
        } else {
            return false;
        }
    }

    /**
     * Returns the URL of a published file path.
     * This method does not perform any publishing. It merely tells you
     * if the file path is published, what the URL will be to access it.
     * @param string $path directory or file path being published
     * @return string|false string the published URL for the file or directory. False if the file or directory does not exist.
     */
    public function getPublishedUrl($path)
    {
        $path = Yii::getAlias($path);

        if (isset($this->_published[$path])) {
            return $this->_published[$path][1];
        }
        if (is_string($path) && ($path = realpath($path)) !== false) {
            return $this->baseUrl . '/' . $this->hash($path) . (is_file($path) ? '/' . basename($path) : '');
        } else {
            return false;
        }
    }

    /**
     * Generate a CRC32 hash for the directory path. Collisions are higher
     * than MD5 but generates a much smaller hash string.
     * @param string $path string to be hashed.
     * @return string hashed string.
     */
    protected function hash($path)
    {
        if (is_callable($this->hashCallback)) {
            return call_user_func($this->hashCallback, $path);
        }
        $path = (is_file($path) ? dirname($path) : $path) . filemtime($path);
        return sprintf('%x', crc32($path . Yii::getVersion()));
    }
}


<?php
/*
 * Copyright (c) 2015 @trashtoy
 * https://github.com/trashtoy/
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of
 * this software and associated documentation files (the "Software"), to deal in
 * the Software without restriction, including without limitation the rights to use,
 * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
 * Software, and to permit persons to whom the Software is furnished to do so,
 * subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */
/**
 * PHP class file.
 * @auhtor trashtoy
 * @since  2.1.0
 * @ignore
 */
namespace Peach\DF\JsonCodec;

/**
 * RFC 7159 で "six structural characters" として挙げられている以下の BNF ルールを解釈する
 * Expression です.
 *
 * <pre>
 * begin-array     = ws %x5B ws  ; [ left square bracket
 *
 * begin-object    = ws %x7B ws  ; { left curly bracket
 *
 * end-array       = ws %x5D ws  ; ] right square bracket
 *
 * end-object      = ws %x7D ws  ; } right curly bracket
 *
 * name-separator  = ws %x3A ws  ; : colon
 *
 * value-separator = ws %x2C ws  ; , comma
 * </pre>
 *
 * @ignore
 */
class StructuralChar implements Expression
{
    /**
     * 例えば array(",", "]") など
     *
     * @var array
     */
    private $expected;

    /**
     * "[", "{", "]", "}", ":", "," のうちのどれかが入ります.
     *
     * @var string
     */
    private $result;

    /**
     * 指定された文字を受理する StructuralChar インスタンスを構築します.
     * @param array $expected 受理される文字のリスト
     */
    public function __construct(array $expected)
    {
        $this->expected = $expected;
        $this->result   = null;
    }

    /**
     * 現在の Context から空白および想定される文字を読み込みます.
     * もしも想定外の文字を検知した場合は DecodeException をスローします.
     *
     * @param Context $context
     */
    public function handle(Context $context)
    {
        $ws = WS::getInstance();
        $ws->handle($context);
        if (!$context->hasNext()) {
            throw $context->createException("Unexpected end of JSON");
        }
        $this->handleChar($context);
        $ws->handle($context);
    }

    /**
     * 空白以外の文字を検知した際の処理です.
     *
     * @param Context $context
     * @throws DecodeException 期待されている文字以外の文字を検知した場合
     */
    private function handleChar(Context $context)
    {
        $chr      = $context->current();
        $expected = $this->expected;
        if (in_array($chr, $expected, true)) {
            $this->result = $chr;
            $context->next();
            return;
        }

        $quote = function ($chr) {
            return "'{$chr}'";
        };
        $expectedList = implode(", ", array_map($quote, $expected));
        throw $context->createException("'{$chr}' is not allowed (expected: {$expectedList})");
    }

    /**
     * handle() の結果を返します.
     *
     * @return string
     */
    public function getResult()
    {
        return $this->result;
    }
}


<?php
/*
 * Copyright (c) 2014 @trashtoy
 * https://github.com/trashtoy/
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of
 * this software and associated documentation files (the "Software"), to deal in
 * the Software without restriction, including without limitation the rights to use,
 * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
 * Software, and to permit persons to whom the Software is furnished to do so,
 * subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */
/**
 * PHP class file.
 * @auhtor trashtoy
 * @since  2.0.0
 */
namespace Peach\DT;

/**
 * HTTP-Date の書式を扱うクラスです.
 * parse 系メソッドは, 以下の 3 種類のフォーマットを解釈することが出来ます.
 *
 * <code>
 * "Fri, 13 Feb 2009 23:31:30 GMT"   #RFC 822, updated by RFC 1123
 * "Friday, 13-Feb-09 23:31:30 GMT"  #RFC 850, obsoleted by RFC 1036
 * "Fri Feb 13 23:31:30 2009"        #ANSI C's asctime() format
 * </code>
 *
 * format 系メソッドは, 一番上の RFC 1123 形式のフォーマットで文字列を生成します.
 *
 * このクラスは parse および format を行う際に, 内部時刻と GMT の自動変換を行います.
 *
 * 参考文献:
 * {@link http://www.arielworks.net/articles/2004/0125a モジュール版PHPで「If-Modified-Since」に対応する}
 */
class HttpDateFormat implements Format
{
    /**
     * システム時刻の時差です (単位は分)
     * @var int
     */
    private $internalOffset;

    /**
     * 新しいフォーマットを生成します.
     * 引数 $offset を指定した場合, parse または format を行った際に,
     * 指定された時差の量だけ時刻に補正がかかります.
     * もしも時差に応じた自動変換が必要ない場合は $offset に 0 を指定してください.
     *
     * 引数を省略した場合は, システム時刻の時差 ({@link Util::getTimeZoneOffset()} の返り値と等価)
     * を使用します. 特に必要がなければ引数なしのコンストラクタを使う代わりに
     * {@link HttpDateFormat::getInstance()} を使ってください.
     *
     * @param int $offset 時間オブジェクトの時差 (単位は分, 省略した場合はシステム設定の値を使用)
     */
    public function __construct($offset = null)
    {
        $this->internalOffset = Util::cleanTimeZoneOffset($offset);
    }

    /**
     * デフォルトのインスタンスを返します.
     * このメソッドは引数なしでコンストラクタを呼び出した場合と同じ結果を返しますが,
     * 返り値がキャッシュされるため, 複数の場所で同じインスタンスを使いまわすことができます.
     *
     * システムのタイムゾーン設定を動的に変更した場合は, 変更前のキャッシュを破棄する必要があるため,
     * 引数 $clearCache に TRUE を指定して実行してください.
     *
     * @param  bool $clearCache  キャッシュを破棄してインスタンスを再生成する場合は TRUE
     * @return HttpDateFormat デフォルトのインスタンス
     */
    public static function getInstance($clearCache = false)
    {
        static $instance = null;
        if (!isset($instance) || $clearCache) {
            $instance = new self();
        }
        return $instance;
    }

    /**
     * {@link HttpDateFormat::parseTimestamp()} の実行結果を Date にキャストします.
     *
     * @param  string $format            HTTP-date 形式の文字列
     * @return Date                      変換結果
     * @throws \InvalidArgumentException フォーマットが不正な場合
     */
    public function parseDate($format)
    {
        return $this->parseTimestamp($format)->toDate();
    }

    /**
     * {@link HttpDateFormat::parseTimestamp()} の実行結果を Datetime にキャストします.
     *
     * @param  string $format            HTTP-date 形式の文字列
     * @return Datetime                  変換結果
     * @throws \InvalidArgumentException フォーマットが不正な場合
     */
    public function parseDatetime($format)
    {
        return $this->parseTimestamp($format)->toDatetime();
    }

    /**
     * HTTP-date 形式のフォーマットを Timestamp に変換します.
     *
     * @param  string $format            HTTP-date 形式の文字列
     * @return Timestamp                 変換結果
     * @throws \InvalidArgumentException フォーマットが不正な場合
     */
    public function parseTimestamp($format)
    {
        $temp_date = array();
        if (preg_match("/^(Mon|Tue|Wed|Thu|Fri|Sat|Sun), ([0-3][0-9]) (Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) ([0-9]{4}) ([0-2][0-9]):([0-5][0-9]):([0-5][0-9]) GMT$/", $format, $temp_date)) {
            $date["hour"]   = $temp_date[5];
            $date["minute"] = $temp_date[6];
            $date["second"] = $temp_date[7];
            $date["month"]  = $this->parseMonthDescription($temp_date[3]);
            $date["day"]    = $temp_date[2];
            $date["year"]   = $temp_date[4];
        } else if (preg_match("/^(Monday|Tuesday|Wednesday|Thursday|Friday|Saturday|Sunday), ([0-3][0-9])-(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)-([0-9]{2}) ([0-2][0-9]):([0-5][0-9]):([0-5][0-9]) GMT$/", $format, $temp_date)) {
            $date["hour"]   = $temp_date[5];
            $date["minute"] = $temp_date[6];
            $date["second"] = $temp_date[7];
            $date["month"]  = $this->parseMonthDescription($temp_date[3]);
            $date["day"]    = $temp_date[2];
            $date["year"]   = $this->getFullYear($temp_date[4]);
        } else if (preg_match("/^(Mon|Tue|Wed|Thu|Fri|Sat|Sun) (Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) ([0-3 ][0-9]) ([0-2][0-9]):([0-5][0-9]):([0-5][0-9]) ([0-9]{4})$/", $format, $temp_date)) {
            $date["hour"]   = $temp_date[4];
            $date["minute"] = $temp_date[5];
            $date["second"] = $temp_date[6];
            $date["month"]  = $this->parseMonthDescription($temp_date[2]);
            // 日が1桁の場合先、半角スペースを0に置換
            $date["day"]    = str_replace(" ", "0", $temp_date[3]);
            // 定義済みの月の名前を数字に変換する
            $date["year"]   = $temp_date[7];
        } else {
            $this->throwFormatException($format);
        }

        $parsed = new Timestamp($date["year"], $date["month"], $date["day"], $date["hour"], $date["minute"], $date["second"]);
        return $parsed->add("minute", - $this->internalOffset);
    }

    /**
     * この日付の 00:00 の時刻を GMT に変換した結果を Http-date にして返します.
     * 例えばシステム時刻の時差が UTC+9 だった場合, 前日の 15:00 の HTTP-date 表現を返り値とします.
     *
     * @param  Date $d 書式化対象の時間オブジェクト
     * @return string  この日付の HTTP-date 表現
     */
    public function formatDate(Date $d)
    {
        return $this->formatDatetime($d->toDatetime());
    }

    /**
     * この時刻の HTTP-date 表現を返します.
     *
     * @param  Datetime $d 書式化対象の時間オブジェクト
     * @return string      この時刻の HTTP-date 表現
     */
    public function formatDatetime(Datetime $d)
    {
        $d = $d->add("minute", $this->internalOffset);

        $format  = '';
        $format .= $this->getDayDescription($d->getDay()).', ';
        $format .= str_pad($d->get('date'), 2, '0', STR_PAD_LEFT) . ' ';
        $format .= $this->getMonthDescription($d->get('month'))   . ' ';
        $format .= str_pad($d->get('year'), 4, '0', STR_PAD_LEFT) . ' ';
        $format .= $d->formatTime() . ' ';
        $format .= 'GMT';
        return $format;
    }

    /**
     * この時刻の HTTP-date 表現を返します.
     *
     * @param  Timestamp $d 書式化対象の時間オブジェクト
     * @return string       この時刻の HTTP-date 表現
     */
    public function formatTimestamp(Timestamp $d)
    {
        return $this->formatDatetime($d);
    }

    /**
     * parse に失敗した場合に呼び出されます.
     *
     * @param  string $format parse に失敗した文字列
     * @throws \InvalidArgumentException
     */
    private function throwFormatException($format)
    {
        throw new \InvalidArgumentException("Illegal format({$format}). HTTP-date format required.");
    }

    /**
     * 月の略称一覧です
     * @return array "Jan" から "Dec" までの月の略称を持つ配列
     * @codeCoverageIgnore
     */
    private function getMonthMapping()
    {
        static $mapping = array('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec');
        return $mapping;
    }

    /**
     * 月の略称を書式化します.
     * @param  int $month 月
     * @return string     引数の月の略称
     */
    private function getMonthDescription($month)
    {
        $mapping = $this->getMonthMapping();
        return $mapping[$month - 1];
    }

    /**
     * 月の略称を月に変換します.
     * @param  string $mon 月の略称
     * @return int 引数の略称の数値表現 (1 から 12)
     */
    private function parseMonthDescription($mon)
    {
        $mapping = $this->getMonthMapping();
        $month   = array_search($mon, $mapping) + 1;
        return str_pad($month, 2, '0', STR_PAD_LEFT);
    }

    /**
     * 2 桁の年表示を 4 桁に変換します.
     * もしも引数の 2 桁年が, 現在の 2 桁年よりも大きい場合,
     * 前世紀の年と判断します.
     *
     * @param  int $y 変換対象の 2 桁年
     * @return int    4 桁の年
     */
    private function getFullYear($y)
    {
        $currentYear = intval(date("Y"));
        $century     = intval($currentYear / 100);
        $smallY      = $currentYear % 100;
        $resultC     = ($smallY < $y) ? $century - 1 : $century;
        return $resultC * 100 + $y;
    }

    /**
     * 曜日の略称を書式化します.
     * @param  int $day 曜日の値
     * @return string   曜日の略称
     */
    private function getDayDescription($day)
    {
        switch ($day) {
            case 0: return "Sun";
            case 1: return "Mon";
            case 2: return "Tue";
            case 3: return "Wed";
            case 4: return "Thu";
            case 5: return "Fri";
            case 6: return "Sat";
        }
        // @codeCoverageIgnoreStart
        throw new \Exception("day: Out of range");
        // @codeCoverageIgnoreEnd
    }
}


<?php
/*
This is part of Wedeto, the WEb DEvelopment TOolkit.
It is published under the MIT Open Source License.

Copyright 2017, Egbert van der Wal

Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

namespace Wedeto\Application\Dispatch;

use Locale;

use Wedeto\HTTP\URL;
use Wedeto\Util\Dictionary;

class Site
{
    private $vhosts = array();
    private $locales = array();
    private $name = "default";

    public function __construct()
    {}

    public function setName(string $name)
    {
        $this->name = $name;
    }

    public function getName()
    {
        return $this->name;
    }

    public function addVirtualHost(VirtualHost $host)
    {
        $host->setSite($this);
        $this->vhosts[] = $host;
        foreach ($host->getLocales() as $locale)
            $this->locales[$locale->getLocale()] = true;
    }

    public function getVirtualHosts()
    {
        return $this->vhosts;
    }

    public function getLocales()
    {
        return array_keys($this->locales);
    }

    public function match($webroot)
    {
        $url = new URL($webroot);
        foreach ($this->vhosts as $vhost)
        {
            if ($vhost->match($url))
                return $vhost;
        }
        return null;
    }

    public function checkRedirect($url)
    {
        $url = new URL($url);
        foreach ($this->vhosts as $vhost)
        {
            if (!$vhost->match($url))
                continue;

            $redirect = $vhost->getRedirect($url);
            if ($redirect)
                return $redirect;

            $host = $vhost->getHost();
            if ($host->scheme !== $url->scheme)
            {
                $url->scheme = $host->scheme;
                return $url;
            }
        }
        return false;
    }

    public function URL($path, $locale = null)
    {
        foreach ($this->vhosts as $vhost)
        {
            if ($vhost->matchLocale($locale))
                return $vhost->URL($path);
        }
        return null;
    }

    /**
     * Set up the Site / VirtualHost structure based on the provided
     * configuration.
     *
     * A Site is a collection of VirtualHosts that each provide a localized version
     * of the same content. The VirtualHost in use determines the locale set in Wedeto.
     *
     * Wedeto can serve multiple sites that contain different content. In absence of
     * multi-site, multi-vhost information, a single site with a single virtual
     * host is set up.
     *
     * Vhosts can be set up to redirect to different addresses, or to define
     * the language in use.
     *
     * A very basic structure is defined as follows:
     *
     * [site]
     * url = "https://www.example.com"
     *
     * This will result in one single vhost for one site. A redirect to www can
     * be accomplished by using:
     *
     * [site]
     * url[0] = "https://www.example.com"
     * url[1] = "https://example.com"
     * redirect[1] = "http://www.example.com"
     *
     * This will result in a single site with two vhosts, where one redirects to the other.
     *
     * A multi-site system with language information could be:
     *
     * [site]
     * url[0] = "https://www.example.com"
     * site[0] = "default"
     * url[1] = "https://example.com"
     * site[1] = "default"
     * redirect[1] = "https://www.example.com"
     *
     * url[2] = "https:://www.foobar.com"
     * site[2] = "foobar"
     * language[2] = "en"
     * url[3] = "https://www.foobar.de"
     * site[3] = "foobar"
     * language[3] = "de"
     *
     * This will result in two sites, default and foobar, each with two vhosts.
     * For the default vhost, these are a www. and a non-www. version. The non-www version
     * will redirect to the www. version.
     *
     * For foobar, there is a English and a German site, identified by
     * different domains, foobar.com and foobar.de.
     */
    public static function setupSites(Dictionary $config)
    {
        $urls = $config->getSection('url');
        $languages = $config->getSection('language');
        $sitenames = $config->getSection('site');
        $redirects = $config->getSection('redirect');
        $default_language = $config->get('default_language');
        $sites = array();

        foreach ($urls as $host_idx => $url)
        {
            $lang = isset($languages[$host_idx]) ? $languages[$host_idx] : $default_language;
            $site = isset($sitenames[$host_idx]) ? $sitenames[$host_idx] : "default";
            $redirect = isset($redirects[$host_idx]) ? $redirects[$host_idx] : null;

            if (!isset($sites[$site]))
            {
                $sites[$site] = new Site;
                $sites[$site]->setName($site);
            }

            $vhost = new VirtualHost($url, $lang);
            if ($redirect)
                $vhost->setRedirect($redirect);

            $sites[$site]->addVirtualHost($vhost);
        }

        return $sites;
    }
}


<?php
/**
 * @link http://www.yiiframework.com/
 * @copyright Copyright (c) 2008 Yii Software LLC
 * @license http://www.yiiframework.com/license/
 */

namespace yii\web;

use Yii;
use yii\caching\Cache;
use yii\di\Instance;

/**
 * CacheSession implements a session component using cache as storage medium.
 *
 * The cache being used can be any cache application component.
 * The ID of the cache application component is specified via [[cache]], which defaults to 'cache'.
 *
 * Beware, by definition cache storage are volatile, which means the data stored on them
 * may be swapped out and get lost. Therefore, you must make sure the cache used by this component
 * is NOT volatile. If you want to use database as storage medium, [[DbSession]] is a better choice.
 *
 * The following example shows how you can configure the application to use CacheSession:
 * Add the following to your application config under `components`:
 *
 * ```php
 * 'session' => [
 *     'class' => 'yii\web\CacheSession',
 *     // 'cache' => 'mycache',
 * ]
 * ```
 *
 * @property boolean $useCustomStorage Whether to use custom storage. This property is read-only.
 *
 * @author Qiang Xue <qiang.xue@gmail.com>
 * @since 2.0
 */
class CacheSession extends Session
{
    /**
     * @var Cache|array|string the cache object or the application component ID of the cache object.
     * The session data will be stored using this cache object.
     *
     * After the CacheSession object is created, if you want to change this property,
     * you should only assign it with a cache object.
     *
     * Starting from version 2.0.2, this can also be a configuration array for creating the object.
     */
    public $cache = 'cache';

    /**
     * Initializes the application component.
     */
    public function init()
    {
        parent::init();
        $this->cache = Instance::ensure($this->cache, Cache::className());
    }

    /**
     * Returns a value indicating whether to use custom session storage.
     * This method overrides the parent implementation and always returns true.
     * @return boolean whether to use custom storage.
     */
    public function getUseCustomStorage()
    {
        return true;
    }

    /**
     * Session read handler.
     * Do not call this method directly.
     * @param string $id session ID
     * @return string the session data
     */
    public function readSession($id)
    {
        $data = $this->cache->get($this->calculateKey($id));

        return $data === false ? '' : $data;
    }

    /**
     * Session write handler.
     * Do not call this method directly.
     * @param string $id session ID
     * @param string $data session data
     * @return boolean whether session write is successful
     */
    public function writeSession($id, $data)
    {
        return $this->cache->set($this->calculateKey($id), $data, $this->getTimeout());
    }

    /**
     * Session destroy handler.
     * Do not call this method directly.
     * @param string $id session ID
     * @return boolean whether session is destroyed successfully
     */
    public function destroySession($id)
    {
        return $this->cache->delete($this->calculateKey($id));
    }

    /**
     * Generates a unique key used for storing session data in cache.
     * @param string $id session variable name
     * @return mixed a safe cache key associated with the session variable name
     */
    protected function calculateKey($id)
    {
        return [__CLASS__, $id];
    }
}


<?php

/**
 * This file is part of the Minion package.
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * @license MIT License
 */

namespace Minion\Twig;

use Minion\Application;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;

/**
 * Class UrlExtension.
 *
 * @package Minion
 * @author Damian Szczerbiński <dszczer@gmail.com>
 */
class UrlExtension extends \Twig_Extension
{
    /** @var Application Application container */
    private $container;

    /**
     * UrlExtension constructor.
     *
     * Inject dependencies.
     *
     * @param Application $app Framework
     */
    public function __construct(Application $app) {
        $this->container = $app;
    }

    /**
     * {@inheritdoc}
     */
    public function getName() {
        return 'minion_twig_url';
    }

    /**
     * {@inheritdoc}
     */
    public function getFunctions() {
        return [
            new \Twig_Function('url', [$this, 'urlFunction']),
            new \Twig_Function('path', [$this, 'pathFunction']),
        ];
    }

    /**
     * Generate absolute URL path.
     *
     * @param string $route  Route name
     * @param array  $params Parameters
     *
     * @return string
     */
    public function urlFunction($route, array $params = []) {
        return $this->container['url_generator']->generate($route, $params, UrlGeneratorInterface::ABSOLUTE_URL);
    }

    /**
     * Generate relative URL path.
     *
     * @param string $route  Route name
     * @param array  $params Parameters
     *
     * @return string
     */
    public function pathFunction($route, array $params = []) {
        return $this->container['url_generator']->generate($route, $params, UrlGeneratorInterface::ABSOLUTE_PATH);
    }
}


<?php

namespace Dhii\Data\Object;

use ArrayObject;
use InvalidArgumentException;
use stdClass;

/**
 * Functionality for retrieval of the data store.
 *
 * @since [*next-version*]
 */
trait GetDataStoreCapableTrait
{
    /**
     * The data store.
     *
     * @since [*next-version*]
     *
     * @var ArrayObject|null
     */
    protected $dataStore;

    /**
     * Retrieves a pointer to the data store.
     *
     * @since [*next-version*]
     *
     * @return ArrayObject The data store.
     */
    protected function _getDataStore()
    {
        return $this->dataStore === null
                ? $this->dataStore = $this->_createDataStore()
                : $this->dataStore;
    }

    /**
     * Creates a new data store.
     *
     * @since [*next-version*]
     *
     * @param stdClass|array|null $data The data for the store, if any.
     *
     * @throws InvalidArgumentException If the type of data for the store is invalid.
     *
     * @return ArrayObject The new data store.
     */
    abstract protected function _createDataStore($data = null);
}


<?php
/*
 * Copyright (c) 2014 @trashtoy
 * https://github.com/trashtoy/
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of
 * this software and associated documentation files (the "Software"), to deal in
 * the Software without restriction, including without limitation the rights to use,
 * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
 * Software, and to permit persons to whom the Software is furnished to do so,
 * subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */
/**
 * PHP class file.
 * @auhtor trashtoy
 * @since  2.0.0
 */
namespace Peach\DT;
use Peach\Util\Values;
use Peach\Util\Arrays;

/**
 * 時間関連のユーティリティクラスです.
 */
class Util
{
    /**
     * このクラスはインスタンス化できません.
     */
    private function __construct() {}

    /**
     * 2つの時間オブジェクトを比較します. 一つめの引数のほうが後 (未来) の場合は正の値,
     * 前 (過去) の場合は負の値, 同じ場合は 0 を返します.
     *
     * このメソッドは, 一つ目の時間オブジェクトの {@link Time::compareTo} メソッドを呼び出し
     * 二つ目の時間オブジェクトと比較した結果を返します.
     *
     * @param  Time $time1 1つ目の時間
     * @param  Time $time2 2つ目の時間
     * @return int         1つ目の時間を2つ目の時間と比較した結果
     * @see    Time::compareTo()
     */
    public static function compareTime(Time $time1, Time $time2)
    {
        return $time1->compareTo($time2);
    }

    /**
     * 引数に渡された時間オブジェクトの中で最も古いものを返します.
     * 引数に Time 型オブジェクトを羅列するか, Time 型オブジェクトの配列を指定してください.
     * 引数に Time が一つも存在しない場合は NULL を返します.
     *
     * @param array|Time $time...
     * @return Time      引数の中で最も古い Time オブジェクト.
     *                   引数が空か, Time オブジェクトが含まれていない場合は NULL
     */
    public static function oldest()
    {
        $args = func_get_args();
        if (isset($args[0]) && is_array($args[0])) {
            $args = $args[0];
        }
        return Arrays::min(Arrays::pickup($args, "Peach\\DT\\Time"));
    }

    /**
     * 引数に渡された時間オブジェクトの中で最新のものを返します.
     * 引数に Time 型オブジェクトを羅列するか, Time 型オブジェクトの配列を指定してください.
     * 引数に Time が一つも存在しない場合は NULL を返します.
     *
     * @param  array|Time $time...
     * @return Time       引数の中で最新の Time オブジェクト.
     *                    引数が空か, Time オブジェクトが含まれていない場合は NULL
     */
    public static function latest()
    {
        $args = func_get_args();
        if (isset($args[0]) && is_array($args[0])) {
            $args = $args[0];
        }
        return Arrays::max(Arrays::pickup($args, "Peach\\DT\\Time"));
    }

    /**
     * 引数に指定された年・月・日 (オプションで時・分・秒) の妥当性を検証します.
     * 妥当な組み合わせの場合は TRUE, それ以外は FALSE を返します.
     * 引数に数値以外の型が含まれていた場合, それが数値文字列
     * ({@link http://www.php.net/manual/ja/function.is-numeric.php is_numeric()} が TRUE を返す)
     * の場合のみ妥当とみなします.
     *
     * @param int $year   年
     * @param int $month  月
     * @param int $date   日
     * @param int $hour   時
     * @param int $minute 分
     * @param int $second 秒
     * @return bool 組み合わせが妥当な場合に TRUE, それ以外は FALSE
     */
    public static function validate($year, $month, $date, $hour = 0, $minute = 0, $second = 0)
    {
        $test = array("year" => $year, "month" => $month, "date" => $date, "hour" => $hour, "minute" => $minute, "second" => $second);
        $d    = new Timestamp($year, $month, $date, $hour, $minute, $second);
        foreach ($test as $key => $value) {
            if (!is_numeric($value) || $d->get($key) !== intval($value)) {
                return false;
            }
        }
        return true;
    }

    /**
     * システム時刻と GMT との時差を, 分単位で返します.
     *
     * システム時刻が GMT よりも未来の場合 (UTC + 1 以上) は負の値,
     * システム時刻が GMT よりも過去の場合 (UTF - 1 以下) は正の値を返します.
     * 例えばタイムゾーンが "Asia/Tokyo" (+09:00) の場合,
     * 返り値は -540 となります.
     *
     * @return int
     */
    public static function getTimeZoneOffset()
    {
        $local = mktime(0, 0, 0, 1, 1, 1970);
        $gmt   = gmmktime(0, 0, 0, 1, 1, 1970);
        return ($local - $gmt) / 60;
    }

    /**
     * 指定された時差 (分単位) の値が妥当かどうかを調べ, 必要に応じて値を丸めた結果を返します.
     * 世界で実際に使用されているタイムゾーンは UTC-12 から UTC+14 ですが,
     * このメソッドでは -23:45 から +23:45 を妥当なタイムゾーンとみなします.
     * もしも -23:45 以前の時差が指定された場合は -23:45 (1425),
     * +23:45 以降の時差が指定された場合は +23:45 (-1425) に丸めた結果を返します.
     *
     * もしも NULL が指定された場合は {@link Util::getTimeZoneOffset} の結果を返します.
     * それ以外の数値以外の値が指定された場合は, 整数にキャストした値を使用します.
     *
     * @param  int $offset
     * @return int 引数を -1425 以上 1425 以下に丸めた値
     */
    public static function cleanTimeZoneOffset($offset)
    {
        return isset($offset) ?
            Values::intValue($offset, -1425, 1425) : // -23:45 から +23:45 まで
            Util::getTimeZoneOffset();
    }
}


<?php

/**
 * Path object
 *
 * @package    RpkUtils\Os
 * @author     Repkit <repkit@gmail.com>
 * @copyright  2015 Repkit
 * @license    MIT <http://opensource.org/licenses/MIT>
 * @since      2015-11-12
 */

 namespace RpkUtils\Os;

 class Path
 {
     /**
      * List files from a path based filtered by extensions
      * @param string $path path to scan
      * @param option array $extensions a list o extensions that will filter the file's list
      *         example array( 'jpg', 'png' ,'txt' )
      * @return array of SplFileInfo
     */
    public static function files($path, array $extensions = array())
    {
        $files = array();
        $it = new \RecursiveDirectoryIterator($path);
        $filter = false;
        if(!empty($extensions) && is_array($extensions)){
            $filter = true;
        }
        foreach(new \RecursiveIteratorIterator($it) as $file){
            if($filter){
                $f = explode('.', $file);
            	$ext = strtolower(array_pop($f));
                if (in_array($ext, $extensions)){
                // 	$files[] = $file->__toString();
                    $files[] = $file;
                }
            }else{
                $files[] = $file;
            }
        }

        return $files;
    }
 }


<?php

namespace Data\Type;

use Iterator;
use Countable;
use ArrayAccess;
use LengthException;
use InvalidArgumentException;

class StringType extends Type implements ArrayAccess, Iterator, Countable
{
    protected static $supported_encodings;

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

    /**
     * @var int
     */
    protected $iteratorPosition = 0;

    /**
     * Constructor
     *
     * @param mixed $value
     */
    public function __construct($value = null, $encoding = null)
    {
        if ($encoding === null) {
            $this->encoding = mb_internal_encoding();
        } else {
            $this->encoding = $this->getRealEncoding($encoding);
        }

        $this->set($value);
    }

    /**
     * Get the value
     *
     * @param  string $encoding
     * @return string
     */
    public function value($encoding = null)
    {
        if ($this->value !== null) {
            if ($encoding === null) {
                return mb_convert_encoding($this->value, $this->encoding, 'UTF-8');
            } else {
                $encoding = $this->getRealEncoding($encoding);
                return mb_convert_encoding($this->value, $encoding, 'UTF-8');
            }
        }
    }

    /**
     * Check the value
     *
     * @param  mixed  $value
     * @return string
     */
    protected function check($value)
    {
        if ($value === false || $value === 0 || $value === 0.0 || $value === '0') {
            return '0';
        }

        if ($value === true || $value === 1 || $value === 1.0 || $value === '1') {
            return '1';
        }

        if ($value instanceof StringType) {
            return $value->value($this->encoding);
        }

        if ($value instanceof Type) {
            $value = $value->value();
        } else {
            if (is_array($value)) {
                throw new InvalidArgumentException('Invalid string, array given');
            }

            if (is_resource($value)) {
                throw new InvalidArgumentException('Invalid string, resource given');
            }

            if (is_object($value)) {
                throw new InvalidArgumentException('Invalid string, object given');
            }
        }

        if (is_array($value) || is_object($value) || is_resource($value)) {
            throw new InvalidArgumentException('Invalid string: ' . $value);
        }

        return mb_convert_encoding($value, 'UTF-8', $this->encoding);
    }

    /**
     * Cast instance to string
     *
     * @return string
     */
    public function __toString()
    {
        if ($this->value === null) {
            return '';
        }

        return mb_convert_encoding($this->value, $this->encoding, 'UTF-8');
    }

    /**
     * Creates an array with all of the aliases->encodings
     *
     * @return array
     */
    public static function supportedEncodings()
    {
        if (static::$supported_encodings === null) {
            $supported = mb_list_encodings();

            foreach ($supported as $key => $value) {
                static::$supported_encodings[strtolower($value)] = $value;

                foreach (mb_encoding_aliases($value) as $k => $v) {
                    static::$supported_encodings[strtolower($v)] = $value;
                }
            }
        }

        return static::$supported_encodings;
    }

    /**
     * Is this encoding supported?
     *
     * @param  string  $encoding
     * @return bool
     */
    public static function isEncodingSupported($encoding)
    {
        $encoding = strtolower($encoding);

        if (isset (static::supportedEncodings()[$encoding])) {
            return true;
        }

        return false;
    }

    /**
     * Return the real encoding of the given alias
     *
     * @param  string $encoding
     * @return string
     */
    public function getRealEncoding($encoding)
    {
        if (static::isEncodingSupported($encoding) === false) {
            throw new \Exception('Encoding is not supported: "' . $encoding . '"');
        }

        return static::supportedEncodings()[strtolower($encoding)];
    }

    /**
     * Returns the length of the string
     *
     * @return int
     */
    public function length()
    {
        return mb_strlen($this->value, 'UTF-8');
    }

    /**
     * Substring
     *
     * @param  int $from
     * @param  int $length
     * @return string|null
     */
    public function substr($from, $length = null)
    {
        $from = Cast::Int($from);
        $length = Cast::_Int($length);

        if ($this->length() < $from) {
            throw new LengthException('From parameter must be smaller than the length of the string');
        }

        if ($this->length() < $length) {
            throw new LengthException('Length parameter must be smaller than the length of the string');
        }

        return mb_convert_encoding(mb_substr($this->value, $from, $length, 'UTF-8'), $this->encoding, 'UTF-8');
    }

    /**
     * Lowercase
     *
     * @return this
     */
    public function toLower()
    {
        $this->value = mb_strtolower($this->value, 'UTF-8');
        return $this;
    }

    /**
     * Uppercase
     *
     * @return this
     */
    public function toUpper()
    {
        $this->value = mb_strtoupper($this->value, 'UTF-8');
        return $this;
    }

    /**
     * Uppercase first letter
     *
     * @return this
     */
    public function upperFirst()
    {
        $this->value = mb_strtoupper(mb_substr($this->value, 0, 1, 'UTF-8'), 'UTF-8') . mb_substr($this->value, 1, null, 'UTF-8');
        return $this;
    }

    /**
     * Uppercase first letter of every word
     *
     * @return this
     */
    public function upperWords()
    {
        $this->value = mb_convert_case($this->value, MB_CASE_TITLE, 'UTF-8');
        return $this;
    }

    /**
     * @see ArrayAccess::offsetExists
     */
    public function offsetExists($offset)
    {
        $offset = Cast::_Int($offset);

        if ($offset !== null && $offset >= 0 && $this->length() > $offset)
        {
            return true;
        }

        return false;
    }

    /**
     * @see ArrayAccess::offsetGet
     */
    public function offsetGet($offset)
    {
        if ($this->offsetExists($offset) === false) {
            throw new InvalidArgumentException('Invalid offset: "' . $offset . '"');
        }

        return $this->substr($offset, 1);
    }

    /**
     * @see ArrayAccess::offsetSet
     */
    public function offsetSet($offset, $value)
    {
        $value = Cast::_String($value, $this->encoding);

        $new = static::create($this->substr(0, $offset) . $value . $this->substr($offset + 1), $this->encoding);
        $this->value = $new->value;
    }

    /**
     * @see ArrayAccess::offsetUnset
     */
    public function offsetUnset($offset)
    {
        $this->offsetSet($offset, '');
    }

    /**
     * @see Iterator::rewind
     */
    public function rewind()
    {
        $this->iteratorPosition = 0;
    }

    /**
     * @see Iterator::current
     */
    public function current()
    {
        return $this->offsetGet($this->iteratorPosition);
    }

    /**
     * @see Iterator::key
     */
    public function key()
    {
        return $this->iteratorPosition;
    }

    /**
     * @see Iterator::next
     */
    public function next()
    {
        $this->iteratorPosition++;
    }

    /**
     * @see Iterator::valid
     */
    public function valid()
    {
        return $this->offsetExists($this->iteratorPosition);
    }

    /**
     * @see Countable::count
     */
    public function count()
    {
        return $this->length();
    }
}


<?php
/*
 * WellCommerce Open-Source E-Commerce Platform
 *
 * This file is part of the WellCommerce package.
 *
 * (c) Adam Piotrowski <adam@wellcommerce.org>
 *
 * For the full copyright and license information,
 * please view the LICENSE file that was distributed with this source code.
 */
namespace WellCommerce\Bundle\ProductStatusBundle\Form\Admin;

use WellCommerce\Bundle\CoreBundle\Form\AbstractFormBuilder;
use WellCommerce\Component\Form\Elements\FormInterface;

/**
 * Class ProductStatusFormBuilder
 *
 * @author  Adam Piotrowski <adam@wellcommerce.org>
 */
class ProductStatusFormBuilder extends AbstractFormBuilder
{
    /**
     * {@inheritdoc}
     */
    public function buildForm(FormInterface $form)
    {
        $mainData = $form->addChild($this->getElement('nested_fieldset', [
            'name'  => 'required_data',
            'label' => $this->trans('common.fieldset.general')
        ]));

        $mainData->addChild($this->getElement('text_field', [
            'name'  => 'symbol',
            'label' => $this->trans('common.label.symbol'),
            'rules' => [
                $this->getRule('required')
            ]
        ]));

        $languageData = $mainData->addChild($this->getElement('language_fieldset', [
            'name'        => 'translations',
            'label'       => $this->trans('common.fieldset.translations'),
            'transformer' => $this->getRepositoryTransformer('translation', $this->get('product_status.repository'))
        ]));

        $name = $languageData->addChild($this->getElement('text_field', [
            'name'  => 'name',
            'label' => $this->trans('common.label.name'),
            'rules' => [
                $this->getRule('required')
            ]
        ]));

        $languageData->addChild($this->getElement('slug_field', [
            'name'            => 'slug',
            'label'           => $this->trans('common.label.slug'),
            'name_field'      => $name,
            'generate_route'  => 'admin.routing.generate',
            'translatable_id' => $this->getRequestHelper()->getAttributesBagParam('id'),
            'rules'           => [
                $this->getRule('required')
            ]
        ]));

        $languageData->addChild($this->getElement('text_field', [
            'name'    => 'cssClass',
            'label'   => $this->trans('product_status.label.css_class'),
            'comment' => $this->trans('product_status.comment.css_class'),
        ]));

        $this->addMetadataFieldset($form, $this->get('product_status.repository'));

        $form->addFilter($this->getFilter('no_code'));
        $form->addFilter($this->getFilter('trim'));
        $form->addFilter($this->getFilter('secure'));
    }
}


<?php

namespace Orchid\Log\Utilities;

use Illuminate\Contracts\Config\Repository as ConfigContract;
use Orchid\Log\Contracts\Utilities\LogStyler as LogStylerContract;

class LogStyler implements LogStylerContract
{
    /**
     * The config repository instance.
     *
     * @var \Illuminate\Contracts\Config\Repository
     */
    protected $config;

    /**
     * @var array
     */
    protected $icons = [
        'all'       => 'fa fa-fw fa-list',
        'emergency' => 'fa fa-fw fa-bug',
        'alert'     => 'fa fa-fw fa-bullhorn',
        'critical'  => 'fa fa-fw fa-heartbeat',
        'error'     => 'fa fa-fw fa-times-circle',
        'warning'   => 'fa fa-fw fa-exclamation-triangle',
        'notice'    => 'fa fa-fw fa-exclamation-circle',
        'info'      => 'fa fa-fw fa-info-circle',
        'debug'     => 'fa fa-fw fa-life-ring',
    ];

    /**
     * Create a new instance.
     *
     * @param \Illuminate\Contracts\Config\Repository $config
     */
    public function __construct(ConfigContract $config)
    {
        $this->config = $config;
    }

    /**
     * Make level icon.
     *
     * @param string      $level
     * @param string|null $default
     *
     * @return string
     */
    public function icon($level, $default = null)
    {
        if (array_key_exists($level, $this->icons)) {
            return $this->icons[$level];
        }

        return $default;
    }

    /**
     * Get level color.
     *
     * @param string      $level
     * @param string|null $default
     *
     * @return string
     */
    public function color($level, $default = null)
    {
        return $this->get("colors.levels.$level", $default);
    }

    /**
     * Get config.
     *
     * @param string $key
     * @param mixed  $default
     *
     * @return mixed
     */
    private function get($key, $default = null)
    {
        return $this->config->get("log-viewer.$key", $default);
    }
}


<?php

namespace Peyote;

/**
 * The base Query class for SELECT, INSERT, UPDATE and DELETE statement.
 *
 * These four classes will share some functionality, so let us share!
 *
 * @package    Peyote
 * @author     Dave Widmer <dave@davewidmer.net>
 */
abstract class Query implements \Peyote\Builder
{
	/**
	 * @var array  Bound parameters
	 */
	protected $params = array();

	/**
	 * @var array  A map of passthru methods
	 */
	private $method_map = array();

	/**
	 * @var array  A list of mixins that the query can passthru
	 */
	protected $mixins = array();

	/**
	 * @var string  The name of the table
	 */
	protected $table = null;

	/**
	 * Creates the method map. Make sure you call parent::__construct()
	 * after all of your main passthru objects are created.
	 *
	 * @param string $table       The name of the table
	 */
	public function __construct($table = null)
	{
		$this->table = $table;

		foreach ($this->mixins as $mixin)
		{
			$this->addMethods($mixin, $this->{$mixin}->getMethods());
		}
	}

	/**
	 * Sets the name of the table.
	 *
	 * @param  string $name  The table name
	 * @return \Peyote\Query
	 */
	public function table($name)
	{
		$this->table = $name;
		return $this;
	}

	/**
	 * Adds "mixin" methods to this class.
	 *
	 * @param  string $mixin  The name of the mixin
	 * @param  array $methods  A list of methods to add
	 * @return \Petoyte\Query
	 */
	public function addMethods($mixin, array $methods)
	{
		foreach ($methods as $method)
		{
			$this->method_map[$method] = $mixin;
		}

		return $this;
	}

	/**
	 * Gets all of the bound parameters for this query.
	 *
	 * @return array
	 */
	public function getParams()
	{
		return $this->params;
	}

	/**
	 * The only bit of magic in this codebase. This is necessary so we can add
	 * mixins.
	 *
	 * @throws \Peyote\Exception
	 *
	 * @param  string $name   The name of the method to call
	 * @param  array  $param  The passed in parameters
	 * @return \Peyote\Query
	 */
	public function __call($name, $params)
	{
		if (array_key_exists($name, $this->method_map))
		{
			$property = $this->method_map[$name];

			call_user_func_array(array($this->{$property}, $name), $params);
			return $this;
		}
		else
		{
			throw new \Peyote\Exception("Call to undefined method ".get_called_class()."::{$name}()");
		}
	}

	/**
	 * Compiles all of the mixins into an array.
	 *
	 * @return array  All of the mixins into an array.
	 */
	protected function compileMixins()
	{
		$sql = array();

		foreach ($this->mixins as $mixin)
		{
			$compiled = $this->{$mixin}->compile();
			if ($compiled !== "")
			{
				$sql[] = $compiled;
			}
		}

		return $sql;
	}

}


<?php
/**
 * This file is part of the "litgroup/sms" package.
 *
 * (c) Roman Shamritskiy <roman@litgroup.ru>
 *
 * This source file is subject to the MIT license that is bundled
 * with this source code in the file LICENSE.
 */

namespace LitGroup\Sms\Gateway;

use LitGroup\Sms\Exception\CascadeGatewayException;
use LitGroup\Sms\Exception\GatewayException;
use LitGroup\Sms\Message;
use Psr\Log\LoggerInterface;
use Psr\Log\NullLogger;

/**
 * Cascade gateway.
 *
 * @author Roman Shamritskiy <roman@litgroup.ru>
 */
class CascadeGateway implements GatewayInterface
{
    /**
     * @var array
     */
    private $gateways;

    /**
     * @var LoggerInterface
     */
    private $logger;

    /**
     * CascadeGateway constructor.
     *
     * @param array $gateways Map of gateways with name of gateway as key.
     * @param LoggerInterface|null $logger
     */
    public function __construct(array $gateways, LoggerInterface $logger = null)
    {
        $this->setGateways($gateways);
        $this->setLogger($logger);
    }

    /**
     * Sends message.
     *
     * @param Message $message It is expected that the facility has verified and contains correct information.
     *
     * @return void
     *
     * @throws CascadeGatewayException
     */
    public function sendMessage(Message $message)
    {
        $exceptions = [];

        /** @var string $gatewayName */
        /** @var GatewayInterface $gateway*/
        foreach ($this->gateways as $gatewayName => $gateway) {
            try {
                $gateway->sendMessage($message);

                return;
            } catch (GatewayException $e) {
                $exceptions[$gatewayName] = $e;

                $this->logger->warning(
                    sprintf('(Cascade gateway: %s) %s', $gatewayName, $e->getMessage()),
                    ['exception' => $e]
                );
            }
        }

        throw new CascadeGatewayException($exceptions);
    }

    /**
     * @param array $gateways
     *
     * @return void
     */
    private function setGateways(array $gateways)
    {
        $this->gateways = [];
        foreach ($gateways as $name => $gateway) {
            $this->addGateway($name, $gateway);
        }
    }

    /**
     * @param string $name
     * @param GatewayInterface $gateway
     *
     * @return void
     */
    private function addGateway($name, GatewayInterface $gateway)
    {
        $this->gateways[$name] = $gateway;
    }

    /**
     * @param LoggerInterface|null $logger
     *
     * @return void
     */
    private function setLogger(LoggerInterface $logger = null)
    {
        $this->logger = $logger !== null ? $logger : new NullLogger();
    }
}


<?php
/**
 * @link http://www.yiiframework.com/
 * @copyright Copyright (c) 2008 Yii Software LLC
 * @license http://www.yiiframework.com/license/
 */

namespace yii\filters\auth;

use Yii;
use yii\base\Action;
use yii\base\ActionFilter;
use yii\web\UnauthorizedHttpException;
use yii\web\User;
use yii\web\Request;
use yii\web\Response;

/**
 * AuthMethod is a base class implementing the [[AuthInterface]] interface.
 *
 * @author Qiang Xue <qiang.xue@gmail.com>
 * @since 2.0
 */
abstract class AuthMethod extends ActionFilter implements AuthInterface
{
    /**
     * @var User the user object representing the user authentication status. If not set, the `user` application component will be used.
     */
    public $user;
    /**
     * @var Request the current request. If not set, the `request` application component will be used.
     */
    public $request;
    /**
     * @var Response the response to be sent. If not set, the `response` application component will be used.
     */
    public $response;
    /**
     * @var array list of action IDs that this filter will be applied to, but auth failure will not lead to error.
     * It may be used for actions, that are allowed for public, but return some additional data for authenticated users.
     * @see isOptional
     * @since 2.0.7
     */
    public $optional = [];

    /**
     * @inheritdoc
     */
    public function beforeAction($action)
    {
        $response = $this->response ? : Yii::$app->getResponse();

        try {
            $identity = $this->authenticate(
                $this->user ? : Yii::$app->getUser(),
                $this->request ? : Yii::$app->getRequest(),
                $response
            );
        } catch (UnauthorizedHttpException $e) {
            if ($this->isOptional($action)) {
                return true;
            }

            throw $e;
        }

        if ($identity !== null || $this->isOptional($action)) {
            return true;
        } else {
            $this->challenge($response);
            $this->handleFailure($response);
            return false;
        }
    }

    /**
     * @inheritdoc
     */
    public function challenge($response)
    {
    }

    /**
     * @inheritdoc
     */
    public function handleFailure($response)
    {
        throw new UnauthorizedHttpException('You are requesting with an invalid credential.');
    }

    /**
     * Checks, whether the $action is optional
     *
     * @param Action $action
     * @return boolean
     * @see optional
     * @since 2.0.7
     */
    protected function isOptional($action) {
        $id = $this->getActionId($action);
        return in_array($id, $this->optional, true);
    }

    /**
     * {@inheritdoc}
     */
    protected function isActive($action)
    {
        return parent::isActive($action) || $this->isOptional($action);
    }
}


<?php
/**
 * This file is part of the BEAR.Accept package.
 *
 * @license http://opensource.org/licenses/MIT MIT
 */
namespace BEAR\Accept;

use BEAR\Accept\Annotation\Available;
use BEAR\Accept\Annotation\Produces;
use Ray\Di\AbstractModule;

final class AcceptModule extends AbstractModule
{
    /**
     * @var array
     */
    private $available;

    public function __construct(array $available, AbstractModule $module = null)
    {
        $this->available = $available;
        parent::__construct($module);
    }

    /**
     * {@inheritdoc}
     */
    protected function configure()
    {
        $this->bind()->annotatedWith(Available::class)->toInstance($this->available);
        $this->bind(AcceptInterface::class)->to(Accept::class);
        $this->bindInterceptor(
            $this->matcher->any(),
            $this->matcher->annotatedWith(Produces::class),
            [AcceptInterceptor::class]
        );
    }
}


<?php declare(strict_types=1);

namespace Onion\Console\Router\Factory;

use Onion\Framework\Console\Interfaces\ArgumentParserInterface;
use Onion\Framework\Dependency\Interfaces\FactoryInterface;
use Onion\Console\Router\Router;
use Psr\Container\ContainerInterface as Container;

class RouterFactory implements FactoryInterface
{
    /**
     * Method that is called by the container, whenever a new
     * instance of the application is necessary. It is the only
     * method called when creating instances and thus, should
     * produce/return the fully configured object it is intended
     * to build.
     *
     * @param Container $container
     *
     * @return Router
     */
    public function build(Container $container): Router
    {
        $commands = $container->get('commands');
        $router = new Router(
            $container->get(ArgumentParserInterface::class)
        );
        foreach ($commands as $command) {
            $command = array_merge([
                'parameters' => [],
            ], $command);

            $name = $command['name'];
            $handler = $container->get($command['handler']);
            unset($command['name'], $command['handler']);

            $router->addCommand($name, $handler, $command);
        }
        return $router;
    }
}


<?php

/**
 * This file is part of the Minion package.
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * @license MIT License
 */

namespace Minion\Service;

use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException;
use Symfony\Component\HttpFoundation\ParameterBag;

/**
 * Class ServiceConfig.
 *
 * @package Minion
 * @author Damian Szczerbiński <dszczer@gmail.com>
 */
class ServiceConfig implements ServiceConfigInterface
{
    /** @var string Service identifier */
    protected $id;
    /** @var string Service provider fully qualified class name */
    protected $providerClass;
    /** @var array Service related tags */
    protected $tags;
    /** @var ParameterBag Service options */
    protected $options;

    /**
     * {@inheritdoc}
     */
    public function __construct($id, array $parsed) {
        $class = null;
        $options = $tags = [];
        if(isset($parsed['class']))
            if(\is_string($parsed['class']))
                if(\class_exists($parsed['class']))
                    $class = $parsed['class'];
                else throw new InvalidConfigurationException("Class '{$parsed['class']}' defined in '$id' not found");
            else throw new InvalidConfigurationException("Class argument is not a string");
        else throw new InvalidConfigurationException("Missing 'class' for '$id' service");
        if(isset($parsed['options'])) {
            if(\is_array($parsed['options']))
                $options = $parsed['options'];
            else throw new InvalidConfigurationException("service options must be an array");
        }
        if(isset($parsed['tags'])) {
            if(\is_array($parsed['tags']))
                $tags = $parsed['tags'];
            else throw new InvalidConfigurationException("service tags must be an array");
        }

        $this->id = $id;
        $this->providerClass = $class;
        $this->options = new ParameterBag($options);
        $this->tags = $tags;
    }

    /**
     * {@inheritdoc}
     */
    public function getTags() {
        return $this->tags;
    }

    /**
     * {@inheritdoc}
     */
    public function getId() {
        return $this->id;
    }

    /**
     * {@inheritdoc}
     */
    public function getOption($name) {
        if(!$this->options->has($name))
            throw new \InvalidArgumentException("Option '$name' is not defined");

        return $this->options->get($name);
    }

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

    /**
     * {@inheritdoc}
     */
    public function getProviderClass() {
        return $this->providerClass;
    }
}


<?php
/*
 * Copyright (c) 2015 @trashtoy
 * https://github.com/trashtoy/
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of
 * this software and associated documentation files (the "Software"), to deal in
 * the Software without restriction, including without limitation the rights to use,
 * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
 * Software, and to permit persons to whom the Software is furnished to do so,
 * subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */
/**
 * PHP class file.
 * @auhtor trashtoy
 * @since  2.1.0
 * @ignore
 */
namespace Peach\DF\JsonCodec;

/**
 * 以下の BNF ルールをあらわす Expression です.
 *
 * <pre>
 * JSON-text = ws value ws
 * </pre>
 *
 * @ignore
 */
class Root implements Expression
{
    /**
     * デコードした結果の値です.
     *
     * @var mixed
     */
    private $result;

    /**
     * 新しい Root インスタンスを構築します.
     */
    public function __construct()
    {
        $this->result = null;
    }

    /**
     * 指定された Context を解析します.
     *
     * @param Context $context
     * @throws DecodeException
     */
    public function handle(Context $context)
    {
        $ws = WS::getInstance();
        $ws->handle($context);
        $value = new Value();
        $value->handle($context);
        $ws->handle($context);

        if ($context->hasNext()) {
            $current = $context->current();
            throw $context->createException("Unexpected character('{$current}')");
        }

        $this->result = $value->getResult();
    }

    /**
     * 解析結果を返します.
     *
     * @return mixed
     */
    public function getResult()
    {
        return $this->result;
    }
}


<?php
/*
 * WellCommerce Open-Source E-Commerce Platform
 *
 * This file is part of the WellCommerce package.
 *
 * (c) Adam Piotrowski <adam@wellcommerce.org>
 *
 * For the full copyright and license information,
 * please view the LICENSE file that was distributed with this source code.
 */

namespace WellCommerce\Bundle\ProductStatusBundle\DataSet\Transformer;

use Symfony\Component\OptionsResolver\OptionsResolver;
use WellCommerce\Component\DataSet\Transformer\AbstractDataSetTransformer;

/**
 * Class ProductStatusTransformer
 *
 * @author  Adam Piotrowski <adam@wellcommerce.org>
 */
class ProductStatusTransformer extends AbstractDataSetTransformer
{
    /**
     * {@inheritdoc}
     */
    public function transformValue($value)
    {
        $productStatuses = explode(',', $value);
        $value           = [];

        foreach ($productStatuses as $status) {
            $information = $this->getStatusData($status);

            if (null !== $information) {
                $value[] = $information;
            }
        }

        return $value;
    }

    /**
     * {@inheritdoc}
     */
    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setRequired([
            'statuses'
        ]);

        $resolver->setDefaults([
            'statuses' => []
        ]);

        $resolver->setAllowedTypes('statuses', 'array');
    }

    /**
     * Returns status information
     *
     * @param int $identifier
     *
     * @return array|null
     */
    protected function getStatusData($identifier)
    {
        foreach ($this->options['statuses'] as $status) {
            if ((int)$status['id'] === (int)$identifier) {
                return $status;
            }
        }

        return null;
    }
}


<?php

namespace BluePsyduck\Common\Data;

use DateTime;
use Traversable;

/**
 * A class able to build up an array while ensuring specific data types.
 *
 * @author BluePsyduck <bluepsyduck@gmx.com>
 * @license http://opensource.org/licenses/GPL-3.0 GPL v3
 */
class DataBuilder
{
    /**
     * The built data array.
     * @var array
     */
    protected $data = [];

    /**
     * Returns the built data array.
     * @return array
     */
    public function getData()
    {
        return $this->data;
    }

    /**
     * Sets a value to the builder.
     * @param string $key
     * @param mixed $value
     * @param mixed $ignoredDefaultValue
     * @return $this
     */
    public function set(string $key, $value, $ignoredDefaultValue = null)
    {
        if ($value !== $ignoredDefaultValue) {
            $this->data[$key] = $value;
        }
        return $this;
    }

    /**
     * Sets a boolean value to the builder.
     * @param string $key
     * @param mixed $value
     * @param bool|null $ignoredDefaultValue
     * @return $this
     */
    public function setBoolean(string $key, $value, bool $ignoredDefaultValue = null)
    {
        $this->set($key, (bool) $value, $ignoredDefaultValue);
        return $this;
    }

    /**
     * Sets an integer value to the builder.
     * @param string $key
     * @param mixed $value
     * @param int|null $ignoredDefaultValue
     * @return $this
     */
    public function setInteger(string $key, $value, int $ignoredDefaultValue = null)
    {
        $this->set($key, (int) $value, $ignoredDefaultValue);
        return $this;
    }

    /**
     * Sets a float value to the builder.
     * @param string $key
     * @param mixed $value
     * @param float|null $ignoredDefaultValue
     * @return $this
     */
    public function setFloat(string $key, $value, float $ignoredDefaultValue = null)
    {
        $this->set($key, (float) $value, $ignoredDefaultValue);
        return $this;
    }

    /**
     * Sets a string value to the builder.
     * @param string $key
     * @param mixed $value
     * @param string|null $ignoredDefaultValue
     * @return $this
     */
    public function setString(string $key, $value, string $ignoredDefaultValue = null)
    {
        $this->set($key, (string) $value, $ignoredDefaultValue);
        return $this;
    }

    /**
     * Sets a date and time value to the builder.
     * @param string $key
     * @param mixed $value
     * @param string $format
     * @param string|null $ignoredDefaultValue
     * @return $this
     */
    public function setDateTime(string $key, $value, string $format, string $ignoredDefaultValue = null)
    {
        if ($value instanceof DateTime) {
            $this->set($key, $value->format($format), $ignoredDefaultValue);
        }
        return $this;
    }

    /**
     * Sets an array of values to the builder.
     * @param string $key
     * @param mixed $value
     * @param callable|null $callback
     * @param array|null $ignoredDefaultValue
     * @return $this
     */
    public function setArray(string $key, $value, callable $callback = null, array $ignoredDefaultValue = null)
    {
        if ($value instanceof Traversable) {
            $value = iterator_to_array($value);
        }
        if (is_array($value)) {
            if (is_callable($callback)) {
                $value = array_map($callback, $value);
            }
            $this->set($key, $value, $ignoredDefaultValue);
        }
        return $this;
    }
}


<?php

// be safe and sane.  use strictmode if available via composer.
$autoload_file = __DIR__ . '/vendor/autoload.php';
if( file_exists( $autoload_file )) {
    require_once($autoload_file);
    \strictmode\initializer::init();
}
require_once(__DIR__ . '/texttable.class.php');

/***
 * A class to print text in human friendly markdown tables.
 */

/***
 * A class to print text in formatted tables.
 */
class texttable_markdown {

    /**
     * Formats a fixed-width text table, with borders.
     *
     * @param $rows  array of rows.  each row contains table cells.
     * @param $headertype  keys | firstrow
     * @param $empty_row_string  String to use when there is no data, or null.
     */
    static public function table( $rows, $headertype = 'keys', $footertype = 'none', $empty_row_string = 'No Data' ) {

        if( !@count( $rows ) ) {

            if( $empty_row_string !== null ) {
                $rows = [ [ $empty_row_string ] ];
            }
            else {
                return '';
            }
        }

        $header = null;
        if( $headertype == 'keys' ) {
            $header = array_keys( static::obj_arr( $rows[0] ) );
        }
        else if( $headertype == 'firstrow' ) {
            $header = static::obj_arr( array_shift( $rows ) );
        }

        $col_widths = array();

        static::calc_row_col_widths_and_align( $col_widths, $align, $header );
        foreach( $rows as $row ) {
            $row = static::obj_arr( $row );
            static::calc_row_col_widths_and_align( $col_widths, $align, $row );
        }

        $buf  = static::print_row( $col_widths, $align, $header );
        $buf .= static::print_divider_row( $col_widths, $align );
        foreach( $rows as $row ) {
            $row = static::obj_arr( $row );
            $buf .= static::print_row( $col_widths, $align, $row );
        }

        return $buf;
    }

    static protected function print_divider_row( $col_widths, $align) {
        $buf = '|';
        $idx = 0;
        foreach( $col_widths as $width ) {
            $rchar = $align[$idx] == 'right' ? ':' : '-';
            $buf .= '-' . str_pad( '-', $width, '-' ) . $rchar . "|";
            $idx ++;
        }
        $buf .= "\n";
        return $buf;
    }

    static protected function print_row( $col_widths, $align, $row ) {
        $buf = '|';
        $idx = 0;
        foreach( $row as $val ) {
            $pad_type = $align[$idx] == 'right' ? STR_PAD_LEFT : STR_PAD_RIGHT;
            $buf .= ' ' . str_pad( $val, $col_widths[$idx], ' ', $pad_type ) . " |";
            $idx ++;
        }
        return $buf . "\n";
    }

    static protected function calc_row_col_widths_and_align( &$col_widths, &$align, $row ) {
        $idx = 0;
        foreach( $row as $val ) {
            $len = strlen( $val );
            if( $len > @$col_widths[$idx] ) {
                $col_widths[$idx] = $len;
            }
            $align[$idx] = @$align[$idx] == 'right' ? 'right' : (is_numeric(trim($val)) ? 'right' : 'left');
            $idx ++;
        }
    }

    static protected function obj_arr( $t ) {
       return is_object( $t ) ? get_object_vars( $t ) : $t;
    }
}


<?php namespace Maduser\Minimal\Log;

/**
 * Class Logger
 *
 * @package Maduser\Minimal\Log
 */
class Logger
{
    /**
     *
     */
    const DEBUG = 5;
    /**
     *
     */
    const SYSTEM = 4;
    /**
     *
     */
    const INFO = 3;
    /**
     *
     */
    const WARNING = 2;
    /**
     *
     */
    const ERROR = 1;
    /**
     *
     */
    const LEVELS = [null, 'ERROR  ', 'WARNING', 'INFO   ', 'SYSTEM ', 'DEBUG  '];

    /**
     * @var string
     */
    private $dir = '';

    /**
     * @var string|callable
     */
    private $filename;

    /**
     * @var string
     */
    private $fileExt = '.log';

    /**
     * @var int
     */
    private $level = 0;

    /**
     * @var callable
     */
    private $lineFormat;

    /**
     * @var bool
     */
    private $withBenchmarks = false;

    /**
     * @return mixed
     */
    public function getDir(): string
    {
        return $this->dir;
    }

    /**
     * @param string $dir
     *
     * @return Logger
     */
    public function setDir(string $dir)
    {
        $this->dir = rtrim($dir, '/') . '/';

        return $this;
    }

    /**
     * @return mixed
     */
    public function getLineFormat()
    {
        return $this->lineFormat;
    }

    /**
     * @param mixed $lineFormat
     *
     * @return Logger
     */
    public function setLineFormat($lineFormat)
    {
        $this->lineFormat = $lineFormat;

        return $this;
    }

    /**
     * @return string
     */
    public function getFilename(): string
    {
        if (is_callable($this->filename)) {
            return $this->filename();
        }

        if ($this->filename) {
            return $this->filename;
        }

        return strftime('%Y-%m-%d') . $this->getFileExt();
    }

    /**
     * @param string|callable $filename
     *
     * @return Logger
     */
    public function setFilename($filename)
    {
        $this->filename = $filename;

        return $this;
    }

    /**
     * @return string
     */
    public function getFileExt(): string
    {
        return $this->fileExt;
    }

    /**
     * @param string $fileExt
     *
     * @return Logger
     */
    public function setFileExt(string $fileExt): Logger
    {
        $this->fileExt = $fileExt;

        return $this;
    }

    /**
     * @return int
     */
    public function getLevel(): int
    {
        return $this->level;
    }

    /**
     * @param int $level
     *
     * @return Logger
     */
    public function setLevel(int $level): Logger
    {
        $this->level = $level;

        return $this;
    }

    /**
     * @return bool
     */
    public function isWithBenchmarks(): bool
    {
        return $this->withBenchmarks;
    }

    /**
     * @param bool $withBenchmarks
     *
     * @return Logger
     */
    public function setWithBenchmarks(bool $withBenchmarks): Logger
    {
        $this->withBenchmarks = $withBenchmarks;

        return $this;
    }

    /**
     * Logger constructor.
     *
     * @param string $dir
     * @param int    $logLevel
     * @param bool   $withBenchmarks
     */
    public function __construct(string $dir, int $logLevel = 0, bool $withBenchmarks = false)
    {
        $this->setDir($dir);
        $this->setLevel($logLevel);
        $this->setWithBenchmarks($withBenchmarks);
    }

    /**
     * @param string $msg
     * @param null   $data
     */
    public function debug(string $msg, $data = null)
    {
        $this->log(self::DEBUG, $msg, $data);
    }

    /**
     * @param string $msg
     * @param null   $data
     */
    public function system(string $msg, $data = null)
    {
        $this->log(self::SYSTEM, $msg, $data);
    }

    /**
     * @param string $msg
     * @param null   $data
     */
    public function info(string $msg, $data = null)
    {
        $this->log(self::INFO, $msg, $data);
    }

    /**
     * @param string $msg
     * @param null   $data
     */
    public function warn(string $msg, $data = null)
    {
        $this->log(self::WARNING, $msg, $data);
    }

    /**
     * @param string $msg
     * @param null   $data
     */
    public function error(string $msg, $data = null)
    {
        $this->log(self::ERROR, $msg, $data);
    }

    /**
     * @param int    $level
     * @param string $msg
     * @param null   $data
     */
    public function log(int $level, string $msg, $data = null)
    {
        if ($level <= $this->level) {

            if ($this->isWithBenchmarks()) {
                $msg = $this->interval() . $msg;
            }

            $file = $this->getFile();
            $line = $this->getLine($level, $msg, $data);

            if (file_exists($file)) {
                file_put_contents($file, $line, FILE_APPEND | LOCK_EX);
            } else {
                file_put_contents($file, $line, LOCK_EX);
            }
        }
    }

    /**
     * @param string $date
     *
     * @return string
     */
    public function getFile(): string
    {
        return $this->getDir() . $this->getFilename();
    }

    /**
     * @param int    $level
     * @param string $msg
     * @param null   $data
     *
     * @return string
     */
    public function getLine(int $level, string $msg, $data = null)
    {
        if (is_callable($this->lineFormat)) {
            $line = $this->lineFormat;
            return $line($level, $msg, $data);
        }

        return $this->formatLine($level, $msg);
    }

    /**
     * @param int    $level
     * @param string $msg
     *
     * @return string
     */
    public function formatLine(int $level, string $msg)
    {
        return
            strftime('%Y-%m-%d %H:%M:%S')
            . ' | ' . self::LEVELS[$level]
            . ' | ' . $msg
            . PHP_EOL;
    }

    /**
     * @return string
     */
    protected function interval(): string
    {
        if (isset($_SERVER["REQUEST_TIME_FLOAT"])) {
            return microtime(true) - $_SERVER["REQUEST_TIME_FLOAT"] . ' - ';
        }

        return '';
    }

}