<?php

namespace Reaction\Base\Logger;

use Reaction\Helpers\ArrayHelper;
use Psr\Log\AbstractLogger;
use Psr\Log\LogLevel;
use React\EventLoop\LoopInterface;
use React\Stream\WritableResourceStream;
use React\Stream\WritableStreamInterface;
use Reaction\Exceptions\InvalidArgumentException;

/**
 * Class StdioLogger
 * @package Reaction\Base\Logger
 */
class StdioLogger extends AbstractLogger implements LoggerInterface
{
    const LOG_LEVEL_RAW = 'raw';

    /**
     * Logging levels PSR-3 LogLevel enum.
     */
    const LOG_LEVELS = [
        self::LOG_LEVEL_RAW => 'RAW',
        LogLevel::DEBUG     => 'DEBUG',
        LogLevel::INFO      => 'INFO',
        LogLevel::NOTICE    => 'NOTICE',
        LogLevel::WARNING   => 'WARNING',
        LogLevel::ERROR     => 'ERROR',
        LogLevel::CRITICAL  => 'CRITICAL',
        LogLevel::ALERT     => 'ALERT',
        LogLevel::EMERGENCY => 'EMERGENCY',
    ];

    const NEW_LINE = PHP_EOL;

    const STYLE_OFF = 0;

    const FG_WHITE = 30;
    const FG_RED = 31;
    const FG_GREEN = 32;
    const FG_YELLOW = 33;
    const FG_BLUE = 34;
    const FG_MAGENTA = 35;
    const FG_CYAN = 36;
    const FG_BLACK = 37;

    const BG_RED = 41;
    const BG_GREEN = 42;
    const BG_YELLOW = 43;
    const BG_BLUE = 44;
    const BG_MAGENTA = 45;
    const BG_CYAN = 46;
    const BG_WHITE = 47;

    const BOLD = 1;
    const ITALIC = 3;
    const UNDERLINE = 4;

    public $withLineNum = false;

    protected static $LOG_COLORS = [
        LogLevel::ERROR => [self::FG_RED],
        LogLevel::ALERT => [self::FG_WHITE, self::BG_RED],
        LogLevel::INFO => [self::FG_BLUE, self::ITALIC],
        LogLevel::NOTICE => [self::FG_BLUE, self::ITALIC],
        LogLevel::CRITICAL => [self::FG_WHITE, self::BG_RED, self::BOLD],
        LogLevel::EMERGENCY => [self::FG_WHITE, self::BG_RED, self::BOLD],
        LogLevel::WARNING => [self::FG_YELLOW, self::BOLD],
    ];

    /** @var WritableStreamInterface Writable stream interface */
    private $stdio;

    /** @var bool */
    private $hideLevel = false;
    /** @var bool */
    private $newLine = false;
    /** @var LoopInterface  */
    private $loop;

    private $profilerData = [];

    /**
     * @param WritableStreamInterface $stream
     * @param LoopInterface           $loop
     *
     * @internal
     */
    public function __construct(WritableStreamInterface $stream, LoopInterface $loop)
    {
        $this->stdio = $stream;
        $this->loop = $loop;
    }

    /**
     * @param LoopInterface $loop
     * @return StdioLogger
     */
    public static function create(LoopInterface $loop): StdioLogger
    {
        return new self(new WritableResourceStream(STDOUT, $loop), $loop);
    }

    /**
     * Hide labels
     * @param bool $hideLevel
     * @return StdioLogger
     */
    public function withHideLevel(bool $hideLevel): StdioLogger
    {
        $clone = clone $this;
        $clone->hideLevel = $hideLevel;

        return $clone;
    }

    /**
     * Insert new line at the end
     * @param bool $newLine
     * @return StdioLogger
     */
    public function withNewLine(bool $newLine): StdioLogger
    {
        $clone = clone $this;
        $clone->newLine = $newLine;

        return $clone;
    }

    /**
     * System is unusable.
     *
     * @param string|mixed $message
     * @param array        $context
     * @param int          $traceShift
     * @return void
     */
    public function emergency($message, array $context = array(), $traceShift = 0)
    {
        $this->log(LogLevel::EMERGENCY, $message, $context, $traceShift);
    }

    /**
     * Action must be taken immediately.
     *
     * Example: Entire website down, database unavailable, etc. This should
     * trigger the SMS alerts and wake you up.
     *
     * @param string|mixed $message
     * @param array        $context
     * @param int          $traceShift
     *
     * @return void
     */
    public function alert($message, array $context = array(), $traceShift = 0)
    {
        $this->log(LogLevel::ALERT, $message, $context, $traceShift);
    }

    /**
     * Critical conditions.
     *
     * Example: Application component unavailable, unexpected exception.
     *
     * @param string|mixed $message
     * @param array        $context
     * @param int          $traceShift
     *
     * @return void
     */
    public function critical($message, array $context = array(), $traceShift = 0)
    {
        $this->log(LogLevel::CRITICAL, $message, $context, $traceShift);
    }

    /**
     * Runtime errors that do not require immediate action but should typically
     * be logged and monitored.
     *
     * @param string|mixed $message
     * @param array        $context
     * @param int          $traceShift
     *
     * @return void
     */
    public function error($message, array $context = array(), $traceShift = 0)
    {
        $this->log(LogLevel::ERROR, $message, $context, $traceShift);
    }

    /**
     * Exceptional occurrences that are not errors.
     *
     * Example: Use of deprecated APIs, poor use of an API, undesirable things
     * that are not necessarily wrong.
     *
     * @param string|mixed $message
     * @param array        $context
     * @param int          $traceShift
     *
     * @return void
     */
    public function warning($message, array $context = array(), $traceShift = 0)
    {
        $this->log(LogLevel::WARNING, $message, $context, $traceShift);
    }

    /**
     * Normal but significant events.
     *
     * @param string|mixed $message
     * @param array        $context
     * @param int          $traceShift
     *
     * @return void
     */
    public function notice($message, array $context = array(), $traceShift = 0)
    {
        $this->log(LogLevel::NOTICE, $message, $context, $traceShift);
    }

    /**
     * Interesting events.
     *
     * Example: User logs in, SQL logs.
     *
     * @param string|mixed $message
     * @param array        $context
     * @param int          $traceShift
     *
     * @return void
     */
    public function info($message, array $context = array(), $traceShift = 0)
    {
        $this->log(LogLevel::INFO, $message, $context, $traceShift);
    }

    /**
     * Detailed debug information.
     *
     * @param string|mixed $message
     * @param array        $context
     * @param int          $traceShift
     *
     * @return void
     */
    public function debug($message, array $context = array(), $traceShift = 0)
    {
        $this->log(LogLevel::DEBUG, $message, $context, $traceShift);
    }

    /**
     * Print raw message
     *
     * @param string|mixed $message
     * @param array        $context
     * @param int          $traceShift
     * @return void
     */
    public function logRaw($message, array $context = array(), $traceShift = 0)
    {
        $this->log(static::LOG_LEVEL_RAW, $message, $context, $traceShift);
    }

    /**
     * Profiler
     * @param string $message
     * @param string $endId
     * @param int    $traceShift
     * @return null|string
     */
    public function profile($message = null, $endId = null, $traceShift = 0) {
        if (!isset($endId)) {
            $timeStart = microtime(true);
            $endId = ceil($timeStart * 100000) . mt_rand(11111, 99999);
            $this->profilerData[$endId] = [
                'message' => $message,
                'start' => $timeStart,
                'shift' => $traceShift,
            ];
            return $endId;
        } else {
            $data = ArrayHelper::remove($this->profilerData, $endId, null);
            if (!isset($data)) {
                return null;
            }
            $traceShift = isset($traceShift) ? $traceShift : (int)$data['shift'];
            $message = isset($message) ? $message : (string)$data['message'];
            if ($message === "") {
                $message = '{EMPTY MESSAGE}';
            }
            $timeSpent = (microtime(true) - $data['start']) * 1000;
            $message .= "\nTime: {_timeSpent} ms. Memory usage: {_memoryUsage} MB";
            $memoryUsage = memory_get_usage() / (1024 * 1024);
            $this->debug($message, [
                '_timeSpent' => sprintf('%.2f', $timeSpent),
                '_memoryUsage' => sprintf('%.2f', $memoryUsage),
            ], $traceShift);
        }
        return null;
    }

    /**
     * Profiler shortcut method for end
     * @param string $message
     * @param string $endId
     * @param int    $traceShift
     */
    public function profileEnd($endId, $message = null, $traceShift = null)
    {
        if (!isset($endId)) {
            return;
        }
        $this->profile($message, $endId, $traceShift);
    }

    /**
     * Log message to STDOUT
     * @param string $level
     * @param string $message
     * @param array  $context
     * @param int    $traceShift
     */
    public function log($level, $message, array $context = [], $traceShift = 0)
    {
        $this->checkCorrectLogLevel($level);
        $message = $this->convertMessageToString($message);
        $message = $this->processPlaceHolders($message, $context);
        if (strlen($message) > 0 && mb_substr($message, -1) !== "\n" && !$this->newLine) {
            $message .= self::NEW_LINE;
        }
        if ($this->hideLevel === false) {
            $logColors = isset(static::$LOG_COLORS[$level]) ? static::$LOG_COLORS[$level] : [];
            if ($level !== static::LOG_LEVEL_RAW) {
                $message = str_pad('[' . $level . ']', 10, ' ') . $message;
            }
            if (!empty($logColors)) {
                $message = $this->colorizeText($message, $logColors);
            }
        }
        if ($this->newLine === true) {
            $message .= self::NEW_LINE;
        }
        //Add script and line number
        if ($this->withLineNum) {
            $trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
            $lineNum = $this->getCalleeData($trace, $traceShift + 1);
            $unixTime = microtime(true);
            $micro = substr(sprintf("%06d", ($unixTime - floor($unixTime)) * 1000000), 0, 3);
            $time = date('H:i:s') . '.' . $micro;
            $message .= $this->colorizeText('^^^ ' . $time . ' - ' . $lineNum, static::FG_BLACK) . self::NEW_LINE;
        }
        $message = $this->format($message, $context);
        $this->stdio->write($message);
    }

    /**
     * Convert message to string
     * @param mixed $message
     * @return mixed|string
     */
    protected function convertMessageToString($message) {
        $messageStr = $message;
        if ($message === null) {
            $messageStr = 'NULL';
        } elseif ($message instanceof \Throwable) {
            $messageStr = $this->convertErrorToString($message);
        } elseif (is_bool($message)) {
            $messageStr = $message ? 'TRUE' : 'FALSE';
        } elseif (!is_scalar($message)) {
            $messageStr = print_r($message, true);
        }
        return $messageStr;
    }

    /**
     * Convert exception to string
     * @param \Throwable $e
     * @param bool       $withTrace
     * @return string
     */
    protected function convertErrorToString(\Throwable $e, $withTrace = true) {
        $message = [
            $e->getMessage(),
            !empty($e->getFile()) ? $e->getFile() . ' #' . $e->getLine() : "",
            $e->getTraceAsString(),
        ];
        if ($withTrace) {
            $message[] = $e->getTraceAsString();
            if ($e->getPrevious() !== null) {
                $message[] = $this->convertErrorToString($e->getPrevious(), false);
            }
        }
        return implode("\n", $message);
    }

    /**
     * Colorize text for console
     * @param string $text
     * @param mixed  ...$colors
     * @return bool|string
     */
    protected function colorizeText($text, ...$colors) {
        if (is_array($colors[0])) {
            $colors = $colors[0];
        }
        for ($i = 0; $i < count($colors); $i++) {
            $text = $this->_colorizeTextInternal($text, $colors[$i]);
        }
        return $text;
    }

    /**
     * @param string $text
     * @param string $color
     * @return bool|string
     */
    protected function _colorizeTextInternal($text, $color) {
        $off = static::STYLE_OFF;
        $newLineEnd = substr($text, -1) === "\n";
        if ($newLineEnd) {
            $text = substr($text, 0, -1);
        }
        $text = "\033[" . $color . "m" . $text . "\033[" . $off . "m";
        if ($newLineEnd) {
            $text .= "\n";
        }
        return $text;
    }

    /**
     * Get callee data from backtrace array
     * @param array $trace
     * @param int $pos
     * @return string
     */
    private function getCalleeData($trace, $pos = 0) {
        $traceRow = isset($trace[$pos]) ? $trace[$pos] : end($trace);
        $file = isset($traceRow['file']) ? $traceRow['file'] : '[internal function]';
        $line = isset($traceRow['line']) ? '#' . $traceRow['line'] : '';
        $str = $file . " " . $line;
        return $str;
    }

    /**
     * Format message
     * @param string $message
     * @param array  $context
     * @return string
     */
    private function format(string $message, array $context): string
    {
        if (false !== strpos($message, '{') && !empty($context)) {
            $replacements = array();
            foreach ($context as $key => $val) {
                if (null === $val || is_scalar($val) || (\is_object($val) && method_exists($val, '__toString'))) {
                    $replacements["{{$key}}"] = $val;
                } elseif ($val instanceof \DateTimeInterface) {
                    $replacements["{{$key}}"] = $val->format(\DateTime::RFC3339);
                } elseif (\is_object($val)) {
                    $replacements["{{$key}}"] = '[object ' . \get_class($val) . ']';
                } else {
                    $replacements["{{$key}}"] = '[' . \gettype($val) . ']';
                }
            }

            $message = strtr($message, $replacements);
        }

        return $message;
    }

    /**
     * Replace placeholders in text
     * @param  string $message
     * @param  array  $context
     * @return string
     */
    protected function processPlaceHolders(string $message, array $context): string
    {
        if (false === strpos($message, '{')) {
            return $message;
        }

        $replacements = [];
        foreach ($context as $key => $value) {
            $replacements['{' . $key . '}'] = $this->formatValue($value);
        }

        return strtr($message, $replacements);
    }

    /**
     * @param string $level
     * @return bool
     */
    private function checkCorrectLogLevel(string $level): bool
    {
        $level = strtolower($level);
        $levels = static::LOG_LEVELS;
        if (!isset($levels[$level])) {
            throw new InvalidArgumentException(
                'Level "' . $level . '" is not defined, use one of: ' . implode(', ', array_keys(static::LOG_LEVELS))
            );
        }

        return true;
    }

    /**
     * Format mixed value as a String
     * @param mixed $value
     * @return string
     */
    protected function formatValue($value): string
    {
        if (is_null($value) || is_scalar($value) || (is_object($value) && method_exists($value, '__toString'))) {
            return (string)$value;
        }

        if (is_object($value)) {
            return '[object ' . get_class($value) . ']';
        }

        return '[' . gettype($value) . ']';
    }
}


<?php
/**
 * Model for store and access SEO data for ActiveRecord in Yii2 framework
 *
 * @link https://github.com/inblank/yii2-seobility
 * @copyright Copyright (c) 2016 Pavel Aleksandrov <inblank@yandex.ru>
 * @license http://opensource.org/licenses/MIT
 */

namespace inblank\seobility\models;

use yii\base\Model;
use yii\db\ActiveRecord;
use yii\db\Query;

/**
 * Model for store and access SEO data for ActiveRecord in Yii2 framework
 *
 * @package inblank\seobility
 */
class Seo extends Model
{
    /**
     * @var string suffix for build table name for the tables stored SEO data for ActiveRecord
     */
    static public $tableSuffix = 'seo';
    /**
     * @var int SEO data owner model id
     */
    public $model_id;
    /**
     * @var int SEO data condition
     */
    public $condition = 0;
    /**
     * @var string SEO title
     */
    public $title = '';
    /**
     * @var string SEO keywords
     */
    public $keywords = '';
    /**
     * @var string SEO description
     */
    public $description = '';
    /**
     * @var bool new record flag
     */
    protected $_isNewRecord;
    /**
     * @var ActiveRecord SEO data owner
     */
    protected $_owner;

    /**
     * Search SEO data. If not found, will be returned new SEO model with empty data
     * @param ActiveRecord $owner the ActiveRecord model for which to find data
     * @param int $condition optional condition for searched SEO data
     * @return self
     */
    public static function find(ActiveRecord $owner, $condition = 0)
    {
        $seo = new self();
        $seo->_owner = $owner;
        $condition = (int)$condition;
        $data = $owner->getIsNewRecord() ? false : (new Query())
            ->from(Seo::tableName($owner))
            ->limit(1)
            ->andWhere([
                'condition' => $condition,
                'model_id' => $owner->getPrimaryKey(),
            ])->one($owner->getDb());
        $seo->_isNewRecord = empty($data);
        if ($data) {
            $seo->setAttributes($data);
        }
        $seo->condition = $condition;
        return $seo;
    }

    /**
     * Get table name of SEO data table for ActiveRecord
     * @param ActiveRecord $activeRecord
     * @return string
     */
    public static function tableName(ActiveRecord $activeRecord)
    {
        $tableName = $activeRecord->tableName();
        if (substr($tableName, -2) == '}}') {
            return preg_replace('/{{(.+)}}/', '{{$1_' . self::$tableSuffix . '}}', $tableName);
        } else {
            return $tableName . '_' . self::$tableSuffix;
        }
    }

    /**
     * Find all SEO data.
     * Result will be in format ['condition1'=>Seo(), 'condition2'=>Seo(), ...]
     * @param ActiveRecord $owner the model for which to find data
     * @return self[]
     */
    public static function findAll(ActiveRecord $owner)
    {
        /** @var self[] $seoList */
        $seoList = [];
        if ($owner->getIsNewRecord()) {
            return $seoList;
        }
        $query = (new Query())->from(Seo::tableName($owner))->andWhere(['model_id' => $owner->getPrimaryKey()]);
        foreach ($query->all($owner->getDb()) as $seo) {
            $seo = new Seo($seo);
            $seo->_isNewRecord = false;
            $seo->_owner = $owner;
            $seoList[$seo['condition']] = $seo;
        }
        return $seoList;
    }

    /**
     * Delete all SEO data for ActiveRecord
     * @param ActiveRecord $owner
     */
    public static function deleteAll(ActiveRecord $owner)
    {
        $owner->getDb()->createCommand()->delete(self::tableName($owner), ['model_id' => $owner->getPrimaryKey()])->execute();
    }

    /**
     * @return array
     */
    public function rules()
    {
        return [
            [['title', 'keywords', 'description'], 'safe'],
        ];
    }

    /**
     * Save SEO data
     */
    public function save()
    {
        if (empty($this->_owner)) {
            $this->addError('owner', "You can't use Seo model without owner");
            return false;
        }
        $this->model_id = $this->_owner->getPrimaryKey();
        $command = $this->_owner->getDb()->createCommand();
        $attributes = ['title', 'keywords', 'description'];
        $tableName = self::tableName($this->_owner);
        if ($this->_isNewRecord) {
            if (empty(array_filter($this->getAttributes($attributes)))) {
                // don't save new SEO data with empty values
                return true;
            }
            $command->insert($tableName, $this->toArray());
        } else {
            $command->update(
                $tableName, $this->toArray($attributes),
                ['model_id' => $this->model_id, 'condition' => $this->condition]
            );
        }
        $command->execute();
        $this->_isNewRecord = false;
        return true;
    }

    /**
     * Delete SEO data
     * @return $this|bool
     */
    public function delete()
    {
        if (!$this->_isNewRecord) {
            $this->_owner->getDb()
                ->createCommand()
                ->delete(
                    self::tableName($this->_owner),
                    ['model_id' => $this->_owner->getPrimaryKey(), 'condition' => $this->condition]
                )->execute();
        }
    }

    /**
     * Get isNewRecord flag
     * @return bool
     */
    public function getIsNewRecord()
    {
        return $this->_isNewRecord;
    }
}


<?php
// emulate the silverstripe DB::query() function

/** @noinspection PhpUndefinedClassInspection */
class DB {
	/** @var mysqli */
	static $conn;

	/** @var DB */
	private static $instance;

	/**
	 * Creates the connection
	 */
	static function init(){
		global $databaseConfig;

		if (!isset($databaseConfig)) {
			$databaseConfig = array (
				'server'    => SS_DATABASE_SERVER,
				'username'  => SS_DATABASE_USERNAME,
				'password'  => SS_DATABASE_PASSWORD,
				'database'  => SS_DATABASE_NAME,
			);
		}

		self::$conn = new mysqli($databaseConfig['server'], $databaseConfig['username'], $databaseConfig['password'], $databaseConfig['database']);
		self::$conn->query("set sql_mode='ansi'");
	}

	/**
	 * @param string $sql
	 * @param int $errorLevel
	 * @return LivePubQuery
	 */
	static function query($sql, $errorLevel = E_USER_ERROR){
		$handle = self::$conn->query($sql);

		if (!$handle && $errorLevel) {
			die("SQL Error: " . self::$conn->error);
		}

		return new LivePubQuery($handle);
	}

	/**
	 * @return DB
	 */
	static function getConn() {
		if (!isset(self::$instance)) self::$instance = new self;
		return self::$instance;
	}

	/**
	 * @param $str
	 * @return string
	 */
	function addSlashes($str) {
		return self::$conn->real_escape_string($str);
	}
}

class LivePubQuery {
	/** @var  mysqli_result */
	private $handle;

	/**
	 * @param $handle
	 */
	public function __construct($handle) {
		$this->handle = $handle;
	}

	public function __destruct() {
		if(is_object($this->handle)) {
			$this->handle->free();
		}
	}

	/**
	 * {@inheritdoc}
	 */
	public function seek($row) {
		if(is_object($this->handle)) {
			return $this->handle->data_seek($row);
		}
	}

	/**
	 * {@inheritdoc}
	 */
	public function numRecords() {
		if(is_object($this->handle)) {
			return $this->handle->num_rows;
		}
	}

	/**
	 * {@inheritdoc}
	 */
	public function nextRecord() {
		if(is_object($this->handle) && ($data = $this->handle->fetch_assoc())) {
			return $data;
		} else {
			return false;
		}
	}

}


<?php

namespace Khayyam;

use DateTime as PhpDateTime;
use DateTimeZone;
use DateInterval;

//http://www.fourmilab.ch/documents/calendar/

class DateTime extends PhpDateTime
{
	protected $timestamp;

	protected $timezone;

	//protected $convertor;

	public function __construct($time = "now", DateTimeZone $timezone = null)
	{
		if (!is_string($time))
		{
			throw new \InvalidArgumentException("DateTime::__construct() expects parameter 1 to be string, ". gettype($time) ." given", 1);
		}

		$this->modify($time);

		$this->timezone = $timezone ?: new DateTimeZone(date_default_timezone_get());
	}

	/*public function add(DateInterval $interval)
	{
		return $this;
	}*/

	public static function createFromFormat($format ,$time, $timezone = null)
	{
		$dateInfo = date_parse_from_format($format, $time);

		$timestamp = static::parseJalaliDateInfoToUTCTimestamp($dateInfo);

		return new static('@'.$timestamp, $timezone);
	}

	/*public static function getLastErrors()
	{

	}*/

	public function modify($time)
	{
		// now
		if (empty($time) || $time === 'now')
		{
			$this->timestamp = time();

			return $this;
		}
		// @1212132132
		/*elseif (preg_match('#^@(\d+)$#', $time, $matched))
		{
			$this->timestamp = $matched[1];

			return $this;
		}*/

		$parsed = date_parse($time);

		$timestamp = $relativeTimestamp = 0;

		if ($this->hasAnyTime($parsed))
		{
			$timestamp = static::parseJalaliDateInfoToUTCTimestamp($parsed);
		}
		else
		{
			$timestamp = $this->timestamp ?: time();
		}

		if ($this->hasRelativeTime($parsed))
		{
			$relativeTimestamp = $this->parseRelative($parsed);
		}

		if ($parsed['is_localtime'] !== false)
		{
			$this->timestamp = $relativeTimestamp;

			return $this;
		}

		$this->timestamp = $timestamp + $relativeTimestamp;

		return $this;
	}

	protected function hasAnyTime($time)
	{
		return
			$time['year'] !== false ||
			$time['month'] !== false ||
			$time['day'] !== false ||
			$time['hour'] !== false ||
			$time['minute'] !== false ||
			$time['second'] !== false ||
			$time['fraction'] !== false
			;
	}

	protected function hasRelativeTime($time)
	{
		return isset($time['relative']);
	}

	public static function parseJalaliDateInfoToUTCTimestamp($dateInfo)
	{
		$year          = $dateInfo['year'];
		$month         = $dateInfo['month'];
		$day           = $dateInfo['day'];
		$hour          = $dateInfo['hour'];
		$minute        = $dateInfo['minute'];
		$second        = $dateInfo['second'];
		$fraction      = $dateInfo['fraction'];
		$warning_count = $dateInfo['warning_count'];
		$warnings      = $dateInfo['warnings'];
		$error_count   = $dateInfo['error_count'];
		$errors        = $dateInfo['errors'];
		$is_localtime  = $dateInfo['is_localtime'];

		$year = ($year === false) ? static::date('Y') : $year;
		$month = ($month === false) ? static::date('n') : $month;
		$day = ($day === false) ? static::date('j') : $day;

		if ($hour === false)
		{
			$hour = static::date('G');
			$minute = ($minute === false) ? static::date('i') : $minute;
			$second = ($second === false) ? static::date('s') : $second;
		}
		else
		{
			$minute = ($minute === false) ? 0 : $minute;
			$second = ($second === false) ? 0 : $second;
		}

		return \jDateTime::mktime($hour, $minute, $second, $month, $day, $year);
	}

	/*public static function __set_state($array)
	{

	}*/

	/*public function setDate($year, $month, $day)
	{
		$this->year  = (int)$year;

		$this->month = (int)$month;

		$this->day   = (int)$day;

		return $this;
	}*/

	/*public function setISODate($year, $week, $day = 1)
	{
		return $this;
	}*/

	/*public function setTime($hour, $minute, $second = 0)
	{
		$this->hour   = (int)$hour;

		$this->minute = (int)$minute;

		$this->second = (int)$second;

		return $this;
	}*/

	public function setTimestamp($timestamp)
	{
		$this->timestamp = $timestamp;

		return $this;
	}

	public function setTimezone($timezone)
	{
		$this->timezone = $timezone;

		return $this;
	}

	/*public function sub(DateInterval $interval)
	{
		return $this;
	}*/

	/*public function diff(DateTimeInterface $datetime2, $absolute = false)
	{
		//return $this;
	}*/

	public function format($format)
	{
		return static::date($format, $this->timestamp);
	}

	/*public function getOffset()
	{
		return $this;
	}*/

	public function getTimestamp()
	{
		return $this->timestamp;
	}

	public function getTimezone()
	{
		return $this->timezone;
	}

	/*public function __wakeup()
	{
		//return DateTimeZone;
	}*/

	public function parseRelative($time)
	{
		$relative = $time['relative'];

		$ts = 0;

		$year   = (int)$relative['year'];
		$month  = (int)$relative['month'];
		$day    = (int)$relative['day'];
		$hour   = (int)$relative['hour'];
		$minute = (int)$relative['minute'];
		$second = (int)$relative['second'];

		$ts += $year * 365 * 24 * 60 * 60;
		$ts += $month * 30 * 24 * 60 * 60;
		$ts += $day * 24 * 60 * 60;
		$ts += $hour * 60 * 60;
		$ts += $minute * 60;
		$ts += $second * 1;

		return $ts;
	}

	public static function date($format, $timestamp = null)
	{
		$timestamp = $timestamp ?: time();

		return \jDateTime::date($format, $timestamp, false, true);
	}

}


<?php
/**
 * PEAR_Command_Common base class
 *
 * PHP versions 4 and 5
 *
 * @category   pear
 * @package    PEAR
 * @author     Stig Bakken <ssb@php.net>
 * @author     Greg Beaver <cellog@php.net>
 * @copyright  1997-2009 The Authors
 * @license    http://opensource.org/licenses/bsd-license.php New BSD License
 * @version    CVS: $Id: Common.php 313023 2011-07-06 19:17:11Z dufuz $
 * @link       http://pear.php.net/package/PEAR
 * @since      File available since Release 0.1
 */

/**
 * base class
 */
require_once 'PEAR.php';

/**
 * PEAR commands base class
 *
 * @category   pear
 * @package    PEAR
 * @author     Stig Bakken <ssb@php.net>
 * @author     Greg Beaver <cellog@php.net>
 * @copyright  1997-2009 The Authors
 * @license    http://opensource.org/licenses/bsd-license.php New BSD License
 * @version    Release: 1.9.4
 * @link       http://pear.php.net/package/PEAR
 * @since      Class available since Release 0.1
 */
class PEAR_Command_Common extends PEAR
{
    /**
     * PEAR_Config object used to pass user system and configuration
     * on when executing commands
     *
     * @var PEAR_Config
     */
    var $config;
    /**
     * @var PEAR_Registry
     * @access protected
     */
    var $_registry;

    /**
     * User Interface object, for all interaction with the user.
     * @var object
     */
    var $ui;

    var $_deps_rel_trans = array(
                                 'lt' => '<',
                                 'le' => '<=',
                                 'eq' => '=',
                                 'ne' => '!=',
                                 'gt' => '>',
                                 'ge' => '>=',
                                 'has' => '=='
                                 );

    var $_deps_type_trans = array(
                                  'pkg' => 'package',
                                  'ext' => 'extension',
                                  'php' => 'PHP',
                                  'prog' => 'external program',
                                  'ldlib' => 'external library for linking',
                                  'rtlib' => 'external runtime library',
                                  'os' => 'operating system',
                                  'websrv' => 'web server',
                                  'sapi' => 'SAPI backend'
                                  );

    /**
     * PEAR_Command_Common constructor.
     *
     * @access public
     */
    function PEAR_Command_Common(&$ui, &$config)
    {
        parent::PEAR();
        $this->config = &$config;
        $this->ui = &$ui;
    }

    /**
     * Return a list of all the commands defined by this class.
     * @return array list of commands
     * @access public
     */
    function getCommands()
    {
        $ret = array();
        foreach (array_keys($this->commands) as $command) {
            $ret[$command] = $this->commands[$command]['summary'];
        }

        return $ret;
    }

    /**
     * Return a list of all the command shortcuts defined by this class.
     * @return array shortcut => command
     * @access public
     */
    function getShortcuts()
    {
        $ret = array();
        foreach (array_keys($this->commands) as $command) {
            if (isset($this->commands[$command]['shortcut'])) {
                $ret[$this->commands[$command]['shortcut']] = $command;
            }
        }

        return $ret;
    }

    function getOptions($command)
    {
        $shortcuts = $this->getShortcuts();
        if (isset($shortcuts[$command])) {
            $command = $shortcuts[$command];
        }

        if (isset($this->commands[$command]) &&
              isset($this->commands[$command]['options'])) {
            return $this->commands[$command]['options'];
        }

        return null;
    }

    function getGetoptArgs($command, &$short_args, &$long_args)
    {
        $short_args = '';
        $long_args = array();
        if (empty($this->commands[$command]) || empty($this->commands[$command]['options'])) {
            return;
        }

        reset($this->commands[$command]['options']);
        while (list($option, $info) = each($this->commands[$command]['options'])) {
            $larg = $sarg = '';
            if (isset($info['arg'])) {
                if ($info['arg']{0} == '(') {
                    $larg = '==';
                    $sarg = '::';
                    $arg = substr($info['arg'], 1, -1);
                } else {
                    $larg = '=';
                    $sarg = ':';
                    $arg = $info['arg'];
                }
            }

            if (isset($info['shortopt'])) {
                $short_args .= $info['shortopt'] . $sarg;
            }

            $long_args[] = $option . $larg;
        }
    }

    /**
    * Returns the help message for the given command
    *
    * @param string $command The command
    * @return mixed A fail string if the command does not have help or
    *               a two elements array containing [0]=>help string,
    *               [1]=> help string for the accepted cmd args
    */
    function getHelp($command)
    {
        $config = &PEAR_Config::singleton();
        if (!isset($this->commands[$command])) {
            return "No such command \"$command\"";
        }

        $help = null;
        if (isset($this->commands[$command]['doc'])) {
            $help = $this->commands[$command]['doc'];
        }

        if (empty($help)) {
            // XXX (cox) Fallback to summary if there is no doc (show both?)
            if (!isset($this->commands[$command]['summary'])) {
                return "No help for command \"$command\"";
            }
            $help = $this->commands[$command]['summary'];
        }

        if (preg_match_all('/{config\s+([^\}]+)}/e', $help, $matches)) {
            foreach($matches[0] as $k => $v) {
                $help = preg_replace("/$v/", $config->get($matches[1][$k]), $help);
            }
        }

        return array($help, $this->getHelpArgs($command));
    }

    /**
     * Returns the help for the accepted arguments of a command
     *
     * @param  string $command
     * @return string The help string
     */
    function getHelpArgs($command)
    {
        if (isset($this->commands[$command]['options']) &&
            count($this->commands[$command]['options']))
        {
            $help = "Options:\n";
            foreach ($this->commands[$command]['options'] as $k => $v) {
                if (isset($v['arg'])) {
                    if ($v['arg'][0] == '(') {
                        $arg = substr($v['arg'], 1, -1);
                        $sapp = " [$arg]";
                        $lapp = "[=$arg]";
                    } else {
                        $sapp = " $v[arg]";
                        $lapp = "=$v[arg]";
                    }
                } else {
                    $sapp = $lapp = "";
                }

                if (isset($v['shortopt'])) {
                    $s = $v['shortopt'];
                    $help .= "  -$s$sapp, --$k$lapp\n";
                } else {
                    $help .= "  --$k$lapp\n";
                }

                $p = "        ";
                $doc = rtrim(str_replace("\n", "\n$p", $v['doc']));
                $help .= "        $doc\n";
            }

            return $help;
        }

        return null;
    }

    function run($command, $options, $params)
    {
        if (empty($this->commands[$command]['function'])) {
            // look for shortcuts
            foreach (array_keys($this->commands) as $cmd) {
                if (isset($this->commands[$cmd]['shortcut']) && $this->commands[$cmd]['shortcut'] == $command) {
                    if (empty($this->commands[$cmd]['function'])) {
                        return $this->raiseError("unknown command `$command'");
                    } else {
                        $func = $this->commands[$cmd]['function'];
                    }
                    $command = $cmd;

                    //$command = $this->commands[$cmd]['function'];
                    break;
                }
            }
        } else {
            $func = $this->commands[$command]['function'];
        }

        return $this->$func($command, $options, $params);
    }
}


<?php
namespace CakeTaxonomy\Controller;

use CakeTaxonomy\Controller\AppController;

/**
 * Tags Controller
 *
 * @property \CakeTaxonomy\Model\Table\TagsTable $Tags
 */
abstract class AbstractTagsController extends AppController
{

    /**
     * Index method
     *
     * @return \Cake\Network\Response|null
     */
    public function index()
    {
        $tags = $this->paginate($this->Tags);

        $this->set(compact('tags'));
        $this->set('_serialize', ['tags']);
    }

    /**
     * View method
     *
     * @param string|null $id Tag id.
     * @return \Cake\Network\Response|null
     * @throws \Cake\Datasource\Exception\RecordNotFoundException When record not found.
     */
    public function view($id = null)
    {
        $tag = $this->Tags->get($id, [
            'contain' => []
        ]);

        $this->set('tag', $tag);
        $this->set('_serialize', ['tag']);
    }

    /**
     * Add method
     *
     * @return \Cake\Network\Response|void Redirects on successful add, renders view otherwise.
     */
    public function add()
    {
        $tag = $this->Tags->newEntity();
        if ($this->request->is('post')) {
            $tag = $this->Tags->patchEntity($tag, $this->request->data);
            if ($this->Tags->save($tag)) {
                $this->Flash->success(__('The tag has been saved.'));

                return $this->redirect(['action' => 'index']);
            } else {
                $this->Flash->error(__('The tag could not be saved. Please, try again.'));
            }
        }
        $this->set(compact('tag'));
        $this->set('_serialize', ['tag']);
    }

    /**
     * Edit method
     *
     * @param string|null $id Tag id.
     * @return \Cake\Network\Response|void Redirects on successful edit, renders view otherwise.
     * @throws \Cake\Network\Exception\NotFoundException When record not found.
     */
    public function edit($id = null)
    {
        $tag = $this->Tags->get($id, [
            'contain' => []
        ]);
        if ($this->request->is(['patch', 'post', 'put'])) {
            $tag = $this->Tags->patchEntity($tag, $this->request->data);
            if ($this->Tags->save($tag)) {
                $this->Flash->success(__('The tag has been saved.'));

                return $this->redirect(['action' => 'index']);
            } else {
                $this->Flash->error(__('The tag could not be saved. Please, try again.'));
            }
        }
        $this->set(compact('tag'));
        $this->set('_serialize', ['tag']);
    }

    /**
     * Delete method
     *
     * @param string|null $id Tag id.
     * @return \Cake\Network\Response|null Redirects to index.
     * @throws \Cake\Datasource\Exception\RecordNotFoundException When record not found.
     */
    public function delete($id = null)
    {
        $this->request->allowMethod(['post', 'delete']);
        $tag = $this->Tags->get($id);
        if ($this->Tags->delete($tag)) {
            $this->Flash->success(__('The tag has been deleted.'));
        } else {
            $this->Flash->error(__('The tag could not be deleted. Please, try again.'));
        }

        return $this->redirect(['action' => 'index']);
    }
}


<?php

namespace Nonetallt\Joptimize;

class LinearParameter extends JoptimizeParameter
{
    private $values;

    public function __construct(array $args)
    {
        parent::__construct($args);
        $this->values = null;
    }

    public function current()
    {
        return $this->getValues()[$this->iteration];
    }

    public function valid()
    {
        return isset($this->getValues()[$this->iteration]);
    }

    private function min()
    {
        return $this->parameters[0];
    }

    private function max()
    {
        return $this->parameters[1];
    }

    private function stepSize()
    {
        return $this->parameters[2] ?? 1;
    }

    public function maxIterations()
    {
        return count($this->getValues());
    }

    /* Use a lazy loader */
    public function getValues()
    {
        return $this->values ?? range($this->min(), $this->max(), $this->stepSize());
    }

    protected function requiredParameters()
    {
        return [
            'start'    => 'integer|double',
            'end'      => 'integer|double'
        ];
    }
}


<?php

namespace XiNG\OpenBiz\Config\Composer;

use Composer\Composer;
use Composer\DependencyResolver\Operation\InstallOperation;
use Composer\DependencyResolver\Operation\UpdateOperation;
use Composer\EventDispatcher\EventSubscriberInterface;
use Composer\IO\IOInterface;
use Composer\Installer\PackageEvent;
use Composer\Installer\PackageEvents;
use Composer\Package\PackageInterface;
use Composer\Plugin\PluginInterface;
use Composer\Script\ScriptEvents;
use Composer\Script\Event;
use Composer\Util\ProcessExecutor;

/**
 * Class Plugin
 *
 * @package XiNG\OpenBiz\Config\Composer
 */
class Plugin implements PluginInterface, EventSubscriberInterface
{

    /**
     * @var Composer
     */
    protected $composer;

    /**
     * @var IOInterface
     */
    protected $io;

    /**
     * @var
     */
    protected $eventDispatcher;

    /**
     * @var ProcessExecutor
     */
    protected $executor;

    /**
     * @var string
     */
    protected $OenBizPackageName = 'xing/openbiz-config';

    /**
     * @var PackageInterface
     */
    protected $OpenBizPackage;

    /**
     * @param Composer    $composer
     * @param IOInterface $io
     */
    public function activate(Composer $composer, IOInterface $io)
    {
        $this->composer = $composer;
        $this->eventDispatcher = $composer->getEventDispatcher();
        $this->io = $io;
        // Set timeout 3000.
        ProcessExecutor::setTimeout(3000);
        $this->executor = new ProcessExecutor($this->io);
    }

    /**
     * Returns an array of event names this subscriber wants to listen to.
     */
    public static function getSubscribedEvents()
    {
        return [
            PackageEvents::POST_PACKAGE_INSTALL => "onPostPackageEvent",
            PackageEvents::POST_PACKAGE_UPDATE => "onPostPackageEvent",
            ScriptEvents::POST_UPDATE_CMD => 'onPostCmdEvent',
        ];
    }

    /**
     * Execute update after update command has been executed, if applicable.
     *
     * @param PackageEvent $event
     */
    public function onPostPackageEvent(PackageEvent $event)
    {
        $package = $this->getOpenBizPackage($event->getOperation());
        if ($package) {
            // By explicitly setting the package, the onPostCmdEvent() will
            // process the update automatically.
            $this->OpenBizPackage = $package;
        }
    }

    /**
     * @param Event $event
     */
    public function onPostCmdEvent(Event $event)
    {
        // Deploy profile libraries.
        \XiNG\OpenBiz\Deploy\DeployLibraries::deployLibraries($event);

        // Only install the template files if xing/openbiz-config was installed.
        if (isset($this->OpenBizPackage)) {
            $version = $this->OpenBizPackage->getVersion();
            $this->executeUpdate($version);
        }
    }

    /**
     * @param $operation
     *
     * @return null
     */
    protected function getOpenBizPackage($operation)
    {
        if ($operation instanceof InstallOperation) {
            $package = $operation->getPackage();
        } elseif ($operation instanceof UpdateOperation) {
            $package = $operation->getTargetPackage();
        }
        if (isset($package) && $package instanceof PackageInterface && $package->getName() == $this->OenBizPackageName) {
            return $package;
        }

        return null;
    }

    /**
     * @param $version
     */
    protected function executeUpdate($version)
    {
        $this->io->write('<comment>Skipping update of templated files</comment>');
    }

}


<?php
/*
 * This file is a part of Solve framework.
 *
 * @author Alexandr Viniychuk <alexandr.viniychuk@icloud.com>
 * @copyright 2009-2014, Alexandr Viniychuk
 * created: 07.05.14 16:46
 */

namespace Solve\Database\Adapters;
use Solve\Database\QC;

/**
 * Class BaseAdapter
 * @package Solve\Database\Adapters
 *
 * Class BaseAdapter is used to ...
 *
 * @version 1.0
 * @author Alexandr Viniychuk <alexandr.viniychuk@icloud.com>
 */
abstract class BaseDBAdapter {

    private $_handler   = null;

    public function __construct($options) {
        if (!$options) throw new \Exception('Options for connection doesn\'t specified!');

        if ($this->connect($options) !== true) {
            throw new \Exception('Cannot connect to Database via Adapter');
        }
    }

    /**
     * Should be realized connect to database
     * @param mixed $options for connection
     */
    abstract public function connect($options);

    /**
     * Execute query
     * @abstract
     * @param QC $query
     */
    abstract public function executeQuery(QC $query);

    /**
     * Process query to SQL
     * @abstract
     * @param QC $qc
     */
    abstract public function buildQuery(QC $qc);

    /**
     * Parse database config and prepare DSN
     *
     * @static
     * @param @params part of database config
     * @return array
     */
    static public function compileDSN(&$params) {
        $dsn = '';
        if (!isset($params['user'])) $params['user'] = 'root';
        if (!isset($params['pass'])) $params['pass'] = null;
        if (!isset($params['type'])) $params['type'] = 'mysql';
        if (!isset($params['host'])) $params['host'] = '127.0.0.1';

        if (!empty($params['dsn'])) {
            $dsn = $params['dsn'];
        } else {
            $dsn = $params['type'] . ':host='.$params['host'];
        }
        return $dsn;
    }

    /**
     * Escape on value using database driver specific
     * @abstract
     * @param mixed $value to be escaped
     * @return mixed escaped
     */
    abstract protected function escapeOne($value);

    /**
     * Escape values for using in queries
     *
     * @param mixed $value to be escaped
     * @return mixed $value  Escaped
     */
    public function escape($value) {
        if (is_array($value)) {
            $res = '';
            if (count($value) == 0) return 'null';
            foreach($value as $val) {
                $res .= $this->escapeOne($val).',';
            }
            $res = substr($res, 0, -1);
            return $res;
        } else {
            return $this->escapeOne($value);
        }
    }

    /**
     * Escape identifiers
     * @param $value
     * @return string
     */
    protected function escapeSqlName($value) {
        if (is_array($value)) {
            $res = '';
            foreach($value as $val) $res .= $this->escapeSqlName($val).',';
            return substr($res, 0, -1);
        }
        $chk_chars = array('.', '(', ' ');
        foreach($chk_chars as $chr) {
            if (strpos($value, $chr) !== false) {
                return $value;
            }
        }
        return '`'.$value.'`';
    }

    public function isValidSQLIdentifier($identifier) {
        if (is_string($identifier) && strpos($identifier, ' ') === false) return true;
    }

    /**
     * By default, throw exception. You need to clear connection to DB in destructor of adapter
     */
    public function __destruct() {
        throw new \Exception('Connection need to be cleared in desctructor of slDBAdapter!');
    }
}


<?php

namespace Oxygen\Data\Validation\Laravel;

use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\QueryBuilder;
use Illuminate\Validation\PresenceVerifierInterface;

class DoctrinePresenceVerifier implements PresenceVerifierInterface {

    /**
     * The Entity Manager factory.
     *
     * @var callable
     */

    protected $factory;

    /**
     * The Entity Manager.
     *
     * @var EntityManagerInterface
     */

    protected $entities;

    /**
     * Constructs the PresenceVerifier.
     *
     * @param callable $entitiesFactory
     */
    public function __construct(callable $entitiesFactory) {
        $this->factory = $entitiesFactory;
    }

    /**
     * Count the number of objects in a collection having the given value.
     *
     * @param  string $collection
     * @param  string $column
     * @param  string $value
     * @param  int $excludeId
     * @param  string $idColumn
     * @param  array $extra
     * @return int
     */
    public function getCount($collection, $column, $value, $excludeId = null, $idColumn = null, array $extra = []) {
        $idColumn = $idColumn !== null ? $idColumn : 'id';

        $qb = $this->createCountQuery($collection)
                   ->where('o.' . $column . ' = :value')
                   ->setParameter('value', $value);

        if (!is_null($excludeId) && $excludeId != 'NULL')  {
            $qb->andWhere('o.' . $idColumn .' <> :excludeId')
               ->setParameter('excludeId', $excludeId);
        }

        foreach($extra as $key => $extraValue) {
            $this->addWhere($qb, $key, $extraValue);
        }

        return (int) $qb->getQuery()->getSingleScalarResult();
    }

    /**
     * Count the number of objects in a collection with the given values.
     *
     * @param  string $collection
     * @param  string $column
     * @param  array $values
     * @param  array $extra
     * @return int
     */
    public function getMultiCount($collection, $column, array $values, array $extra = []) {
        $qb = $this->createCountQuery($collection)
                   ->where('o.', $column . ' IN (:values)')
                   ->setParameter('values', array_values($values));

        foreach($extra as $key => $extraValue) {
            $this->addWhere($qb, $key, $extraValue);
        }

        return (int) $qb->getQuery()->getSingleScalarResult();
    }

    /**
     * Add a "where" clause to the given query.
     *
     * @param  object $qb
     * @param  string $key
     * @param  string $extraValue
     * @param  string  $alias
     * @return void
     */

    protected function addWhere($qb, $key, $extraValue, $alias = 'o') {
        $reference = $key . '.' . $alias;
        if($extraValue === 'NULL') {
            $qb->andWhere($reference . ' is NULL');
        } elseif($extraValue === 'NOT_NULL') {
            $qb->andWhere($reference . ' is NOT NULL');
        } elseif(is_array($extraValue)) {
            list($operator, $value) = $extraValue;
            $this->addWhereAdvanced($qb, $key, $operator, $value, $alias);
        } else {
            $this->addWhereAdvanced($qb, $key, '=', $extraValue, $alias);
        }
    }

    /**
     * Add a "where" clause to the given query.
     *
     * @param  object $qb
     * @param  string $key
     * @param  string $operator
     * @param  mixed  $value
     * @return void
     */

    protected function addWhereAdvanced($qb, $key, $operator, $value, $alias) {
        $parameter = 'where' . ucfirst($key);
        $qb->andWhere($alias . '.' . $key .  ' ' . $operator . ' :'  . $parameter)
           ->setParameter($parameter, $value);
    }

    /**
     * Creates a query builder.
     *
     * @param string $collection
     * @param string $alias
     * @return QueryBuilder
     */

    protected function createCountQuery($collection, $alias = 'o') {
        return $this->getEntityManager()->createQueryBuilder()
            ->select('COUNT(' . $alias . ')')
            ->from($collection, $alias);
    }

    /**
     * Returns the EntityManager, loading it if it hasn't been created yet.
     *
     * @return \Doctrine\ORM\EntityManagerInterface
     */

    protected function getEntityManager() {
        if($this->entities === null) {
            $callable = $this->factory;
            $this->entities = $callable();
        }

        return $this->entities;
    }

}


<?php
//TODO: Come back later after making web User

namespace Reaction\Helpers;

use Reaction;
use Reaction\Exceptions\InvalidArgumentException;
use Reaction\RequestApplicationInterface;

/**
 * Url provides a set of static methods for managing URLs.
 *
 * For more details and usage information on Url, see the [guide article on url helpers](guide:helper-url).
 *
 */
class Url
{
    /**
     * Creates a URL for the given route.
     *
     * This method will use [[\Reaction\Web\UrlManager]] to create a URL.
     *
     * You may specify the route as a string, e.g., `site/index`. You may also use an array
     * if you want to specify additional query parameters for the URL being created. The
     * array format must be:
     *
     * ```php
     * // generates: /index.php?r=site/index&param1=value1&param2=value2
     * ['site/index', 'param1' => 'value1', 'param2' => 'value2']
     * ```
     *
     * If you want to create a URL with an anchor, you can use the array format with a `#` parameter.
     * For example,
     *
     * ```php
     * // generates: /index.php?r=site/index&param1=value1#name
     * ['site/index', 'param1' => 'value1', '#' => 'name']
     * ```
     *
     * A route may be either absolute or relative. An absolute route has a leading slash (e.g. `/site/index`),
     * while a relative route has none (e.g. `site/index` or `index`). A relative route will be converted
     * into an absolute one by the following rules:
     *
     * - If the route is an empty string, the current [[\yii\web\Controller::route|route]] will be used;
     * - If the route contains no slashes at all (e.g. `index`), it is considered to be an action ID
     *   of the current controller and will be prepended with [[\yii\web\Controller::uniqueId]];
     * - If the route has no leading slash (e.g. `site/index`), it is considered to be a route relative
     *   to the current module and will be prepended with the module's [[\yii\base\Module::uniqueId|uniqueId]].
     *
     * Route can also be specified as an alias. In this case, the alias
     * will be converted into the actual route first before conducting the above transformation steps.
     *
     * Below are some examples of using this method:
     *
     * ```php
     * // /index.php?r=site%2Findex
     * echo Url::toRoute('site/index');
     *
     * // /index.php?r=site%2Findex&src=ref1#name
     * echo Url::toRoute(['site/index', 'src' => 'ref1', '#' => 'name']);
     *
     * // http://www.example.com/index.php?r=site%2Findex
     * echo Url::toRoute('site/index', true);
     *
     * // https://www.example.com/index.php?r=site%2Findex
     * echo Url::toRoute('site/index', 'https');
     *
     * // /index.php?r=post%2Findex     assume the alias "@posts" is defined as "post/index"
     * echo Url::toRoute('@posts');
     * ```
     *
     * @param string|array $route use a string to represent a route (e.g. `index`, `site/index`),
     * or an array to represent a route with query parameters (e.g. `['site/index', 'param1' => 'value1']`).
     * @param bool|string                 $scheme the URI scheme to use in the generated URL:
     *
     * - `false` (default): generating a relative URL.
     * - `true`: returning an absolute base URL whose scheme is the same as that in [[\yii\web\UrlManager::$hostInfo]].
     * - string: generating an absolute URL with the specified scheme (either `http`, `https` or empty string
     *   for protocol-relative URL).
     *
     * @param RequestApplicationInterface $app
     * @return string the generated URL
     */
    public static function toRoute($route, $scheme = false, RequestApplicationInterface $app)
    {
        $route = (array) $route;
        $route[0] = static::normalizeRoutePath($route[0], $app);

        $urlManager = $app->getUrlManager();

        if ($scheme !== false) {
            return $urlManager->createAbsoluteUrl($route, is_string($scheme) ? $scheme : null);
        }

        return $urlManager->createUrl($route);
    }

    /**
     * Creates a URL based on the given parameters.
     *
     * This method is very similar to [[toRoute()]]. The only difference is that this method
     * requires a route to be specified as an array only. If a string is given, it will be treated as a URL.
     * In particular, if `$url` is
     *
     * - an array: [[toRoute()]] will be called to generate the URL. For example:
     *   `['site/index']`, `['post/index', 'page' => 2]`. Please refer to [[toRoute()]] for more details
     *   on how to specify a route.
     * - a string with a leading `@`: it is treated as an alias, and the corresponding aliased string
     *   will be returned.
     * - an empty string: the currently requested URL will be returned;
     * - a normal string: it will be returned as is.
     *
     * When `$scheme` is specified (either a string or `true`), an absolute URL with host info (obtained from
     * [[\yii\web\UrlManager::$hostInfo]]) will be returned. If `$url` is already an absolute URL, its scheme
     * will be replaced with the specified one.
     *
     * Below are some examples of using this method:
     *
     * ```php
     * // /index.php?r=site%2Findex
     * echo Url::to(['site/index']);
     *
     * // /index.php?r=site%2Findex&src=ref1#name
     * echo Url::to(['site/index', 'src' => 'ref1', '#' => 'name']);
     *
     * // /index.php?r=post%2Findex     assume the alias "@posts" is defined as "/post/index"
     * echo Url::to(['@posts']);
     *
     * // the currently requested URL
     * echo Url::to();
     *
     * // /images/logo.gif
     * echo Url::to('@web/images/logo.gif');
     *
     * // images/logo.gif
     * echo Url::to('images/logo.gif');
     *
     * // http://www.example.com/images/logo.gif
     * echo Url::to('@web/images/logo.gif', true);
     *
     * // https://www.example.com/images/logo.gif
     * echo Url::to('@web/images/logo.gif', 'https');
     *
     * // //www.example.com/images/logo.gif
     * echo Url::to('@web/images/logo.gif', '');
     * ```
     *
     *
     * @param array|string                $url the parameter to be used to generate a valid URL
     * @param bool|string                 $scheme the URI scheme to use in the generated URL:
     *
     * - `false` (default): generating a relative URL.
     * - `true`: returning an absolute base URL whose scheme is the same as that in [[\Reaction\Web\UrlManager::$hostInfo]].
     * - string: generating an absolute URL with the specified scheme (either `http`, `https` or empty string
     *   for protocol-relative URL).
     *
     * @param RequestApplicationInterface $app
     * @return string the generated URL
     * @throws Reaction\Exceptions\InvalidConfigException
     */
    public static function to($url = '', $scheme = false, RequestApplicationInterface $app = null)
    {
        if (is_array($url)) {
            return isset($app) ? static::toRoute($url, $scheme, $app) : null;
        }

        $url = Reaction::$app->getAlias($url);
        if ($url === '' && isset($app)) {
            $url = $app->reqHelper->getUrl();
        }

        if ($scheme === false) {
            return $url;
        }

        if (static::isRelative($url)) {
            // turn relative URL into absolute
            $url = static::getUrlManager()->getHostInfo() . '/' . ltrim($url, '/');
        }

        return static::ensureScheme($url, $scheme);
    }

    /**
     * Normalize URL by ensuring that it use specified scheme.
     *
     * If URL is relative or scheme is not string, normalization is skipped.
     *
     * @param string $url the URL to process
     * @param string $scheme the URI scheme used in URL (e.g. `http` or `https`). Use empty string to
     * create protocol-relative URL (e.g. `//example.com/path`)
     * @return string the processed URL
     */
    public static function ensureScheme($url, $scheme)
    {
        if (static::isRelative($url) || !is_string($scheme)) {
            return $url;
        }

        if (substr($url, 0, 2) === '//') {
            // e.g. //example.com/path/to/resource
            return $scheme === '' ? $url : "$scheme:$url";
        }

        if (($pos = strpos($url, '://')) !== false) {
            if ($scheme === '') {
                $url = substr($url, $pos + 1);
            } else {
                $url = $scheme . substr($url, $pos);
            }
        }

        return $url;
    }

    /**
     * Returns the base URL of the current request.
     * @param bool|string $scheme the URI scheme to use in the returned base URL:
     *
     * - `false` (default): returning the base URL without host info.
     * - `true`: returning an absolute base URL whose scheme is the same as that in [[\yii\web\UrlManager::$hostInfo]].
     * - string: returning an absolute base URL with the specified scheme (either `http`, `https` or empty string
     *   for protocol-relative URL).
     * @return string
     */
    public static function base($scheme = false)
    {
        $url = static::getUrlManager()->getBaseUrl();
        if ($scheme !== false) {
            $url = static::getUrlManager()->getHostInfo() . $url;
            $url = static::ensureScheme($url, $scheme);
        }

        return $url;
    }

    /**
     * Remembers the specified URL so that it can be later fetched back by [[previous()]].
     *
     * @param string|array                $url the URL to remember. Please refer to [[to()]] for acceptable formats.
     * If this parameter is not specified, the currently requested URL will be used.
     * @param string                      $name the name associated with the URL to be remembered. This can be used
     * later by [[previous()]]. If not set, [[\Reaction\Web\User::setReturnUrl()]] will be used with passed URL.
     * @param RequestApplicationInterface $app
     * @throws Reaction\Exceptions\InvalidConfigException
     * @see previous()
     * @see \Reaction\Web\User::setReturnUrl()
     */
    public static function remember($url = '', $name = null, RequestApplicationInterface $app)
    {
        $url = static::to($url);

        if ($name === null) {
            $app->user->setReturnUrl($url);
        } else {
            $app->session->set($name, $url);
        }
    }

    /**
     * Returns the URL previously [[remember()|remembered]].
     *
     * @param string                      $name the named associated with the URL that was remembered previously.
     * If not set, [[\Reaction\Web\User::getReturnUrl()]] will be used to obtain remembered URL.
     * @param RequestApplicationInterface $app
     * @return string|null the URL previously remembered. Null is returned if no URL was remembered with the given name
     * and `$name` is not specified.
     * @see remember()
     * @see \Reaction\Web\User::getReturnUrl()
     */
    public static function previous($name = null, RequestApplicationInterface $app)
    {
        if ($name === null) {
            return $app->user->getReturnUrl();
        }

        return $app->session->get($name);
    }

    /**
     * Returns the canonical URL of the currently requested page.
     *
     * The canonical URL is constructed using the current controller's [[\Reaction\Routes\Controller::route]] and
     * [[\yii\web\Controller::actionParams]]. You may use the following code in the layout view to add a link tag
     * about canonical URL:
     *
     * ```php
     * $this->registerLinkTag(['rel' => 'canonical', 'href' => Url::canonical()]);
     * ```
     *
     * @param RequestApplicationInterface $app
     * @return string the canonical URL of the currently requested page
     */
    public static function canonical(RequestApplicationInterface $app)
    {
        $routePath = static::getCurrentPath($app, true);
        if ($routePath === null) {
            return null;
        }
        $params = $app->getRoute()->getRouteParams();
        $params[0] = $routePath;

        return static::getUrlManager()->createAbsoluteUrl($params);
    }

    /**
     * Returns the home URL.
     *
     * @param bool|string $scheme the URI scheme to use for the returned URL:
     *
     * - `false` (default): returning a relative URL.
     * - `true`: returning an absolute base URL whose scheme is the same as that in [[\yii\web\UrlManager::$hostInfo]].
     * - string: returning an absolute URL with the specified scheme (either `http`, `https` or empty string
     *   for protocol-relative URL).
     *
     * @return string home URL
     */
    public static function home($scheme = false)
    {
        $url = Reaction::$app->urlManager->getHomeUrl();

        if ($scheme !== false) {
            $url = static::getUrlManager()->getHostInfo() . $url;
            $url = static::ensureScheme($url, $scheme);
        }

        return $url;
    }

    /**
     * Returns a value indicating whether a URL is relative.
     * A relative URL does not have host info part.
     * @param string $url the URL to be checked
     * @return bool whether the URL is relative
     */
    public static function isRelative($url)
    {
        return strncmp($url, '//', 2) && strpos($url, '://') === false;
    }

    /**
     * Creates a URL by using the current route and the GET parameters.
     *
     * You may modify or remove some of the GET parameters, or add additional query parameters through
     * the `$params` parameter. In particular, if you specify a parameter to be null, then this parameter
     * will be removed from the existing GET parameters; all other parameters specified in `$params` will
     * be merged with the existing GET parameters. For example,
     *
     * ```php
     * // assume $_GET = ['id' => 123, 'src' => 'google'], current route is "post/view"
     *
     * // /index.php?r=post%2Fview&id=123&src=google
     * echo Url::current();
     *
     * // /index.php?r=post%2Fview&id=123
     * echo Url::current(['src' => null]);
     *
     * // /index.php?r=post%2Fview&id=100&src=google
     * echo Url::current(['id' => 100]);
     * ```
     *
     * Note that if you're replacing array parameters with `[]` at the end you should specify `$params` as nested arrays.
     * For a `PostSearchForm` model where parameter names are `PostSearchForm[id]` and `PostSearchForm[src]` the syntax
     * would be the following:
     *
     * ```php
     * // index.php?r=post%2Findex&PostSearchForm%5Bid%5D=100&PostSearchForm%5Bsrc%5D=google
     * echo Url::current([
     *     $postSearch->formName() => ['id' => 100, 'src' => 'google'],
     * ]);
     * ```
     *
     * @param array               $params an associative array of parameters that will be merged with the current GET parameters.
     * If a parameter value is null, the corresponding GET parameter will be removed.
     * @param bool|string         $scheme the URI scheme to use in the generated URL:
     *
     * - `false` (default): generating a relative URL.
     * - `true`: returning an absolute base URL whose scheme is the same as that in [[\yii\web\UrlManager::$hostInfo]].
     * - string: generating an absolute URL with the specified scheme (either `http`, `https` or empty string
     *   for protocol-relative URL).
     *
     * @param RequestApplicationInterface $app
     * @return string the generated URL
     */
    public static function current(array $params = [], $scheme = false, RequestApplicationInterface $app)
    {
        $routePath = static::getCurrentPath($app, true);
        if ($routePath === null) {
            return null;
        }
        $currentParams = $app->reqHelper->getQueryParams();
        $currentParams[0] = $routePath;
        $route = array_replace_recursive($currentParams, $params);
        return static::toRoute($route, $scheme, $app);
    }

    /**
     * Normalizes route and makes it suitable for UrlManager. Absolute routes are staying as is
     * while relative routes are converted to absolute ones.
     *
     * A relative route is a route without a leading slash, such as "view", "post/view".
     *
     * - If the route is an empty string, the current [[\yii\web\Controller::route|route]] will be used;
     * - If the route contains no slashes at all, it is considered to be an action ID
     *   of the current controller and will be prepended with [[\yii\web\Controller::uniqueId]];
     * - If the route has no leading slash, it is considered to be a route relative
     *   to the current module and will be prepended with the module's uniqueId.
     *
     * A route can also be specified as an alias. In this case, the alias
     * will be converted into the actual route first before conducting the above transformation steps.
     *
     * @param string                      $routePath the route. This can be either an absolute route or a relative route.
     * @param RequestApplicationInterface $app
     * @return string normalized route suitable for UrlManager
     */
    protected static function normalizeRoutePath($routePath, RequestApplicationInterface $app)
    {
        $routePath = Reaction::$app->getAlias((string) $routePath);
        if (strncmp($routePath, '/', 1) === 0) {
            // absolute route
            return $routePath;
        }

        $route = $app->getRoute();

        // relative route
        if ($route === null || $route->controller === null) {
            throw new InvalidArgumentException("Unable to resolve the relative route: $routePath. No active controller is available.");
        }

        return $routePath === '' ? $route->getRoutePath(true) : $route->controller->group() . '/' . $routePath;
    }

    /**
     * Get current path from request & current controller
     * @param RequestApplicationInterface $app
     * @param bool                $onlyStaticPart
     * @return null|string
     */
    protected static function getCurrentPath(RequestApplicationInterface $app, $onlyStaticPart = false) {
        $route = $app->getRoute();
        return $route ? $route->getRoutePath($onlyStaticPart) : null;
    }

    /**
     * @return Reaction\Routes\UrlManager URL manager used to create URLs
     */
    protected static function getUrlManager()
    {
        return Reaction::$app->urlManager;
    }
}


<?php

namespace Think\Template\TagLib;

use Think\Template\TagLib;

/**
 * CX标签库解析类
 */
final class Cx extends TagLib
{

    /**
     * 标签定义
     * @var array $tags
     */
    protected $tags = [
        // 标签定义： attr 属性列表 close 是否闭合（0 或者1 默认1） alias 标签别名 level 嵌套层次
        'php'        => [],
        'volist'     => ['attr' => 'name,id,offset,length,key,mod', 'level' => 3, 'alias' => 'iterate'],
        'foreach'    => ['attr' => 'name,item,key', 'level' => 3],
        'if'         => ['attr' => 'condition', 'level' => 2],
        'elseif'     => ['attr' => 'condition', 'close' => 0],
        'else'       => ['attr' => '', 'close' => 0],
        'switch'     => ['attr' => 'name', 'level' => 2],
        'case'       => ['attr' => 'value,break'],
        'default'    => ['attr' => '', 'close' => 0],
        'compare'    => [
            'attr'  => 'name,value,type',
            'level' => 3,
            'alias' => 'eq,equal,notequal,neq,gt,lt,egt,elt,heq,nheq',
        ],
        'range'      => ['attr' => 'name,value,type', 'level' => 3, 'alias' => 'in,notin,between,notbetween'],
        'empty'      => ['attr' => 'name', 'level' => 3],
        'notempty'   => ['attr' => 'name', 'level' => 3],
        'present'    => ['attr' => 'name', 'level' => 3],
        'notpresent' => ['attr' => 'name', 'level' => 3],
        'defined'    => ['attr' => 'name', 'level' => 3],
        'notdefined' => ['attr' => 'name', 'level' => 3],
        'assign'     => ['attr' => 'name,value', 'close' => 0],
        'define'     => ['attr' => 'name,value', 'close' => 0],
        'for'        => ['attr' => 'start,end,name,comparison,step', 'level' => 3],
    ];

    /**
     * php标签解析

     *
     * @param array $tag 标签属性
     * @param string $content 标签内容
     *
     * @return string
     */
    public function _php($tag, $content)
    {
        return '<?php '.$content.' ?>';
    }

    /**
     * volist标签解析 循环输出数据集
     * 格式：
     * <volist name="userList" id="user" empty="" >
     * {user.username}
     * {user.email}
     * </volist>

     *
     * @param array $tag 标签属性
     * @param string $content 标签内容
     *
     * @return string
     */
    public function _volist(array $tag = [], $content = '')
    {
        $name = $tag['name'];
        $id = $tag['id'];
        $empty = isset($tag['empty']) ? $tag['empty'] : '';
        $key = !empty($tag['key']) ? $tag['key'] : 'i';
        $mod = isset($tag['mod']) ? $tag['mod'] : '2';
        // 允许使用函数设定数据集 <volist name=":fun('arg')" id="vo">{$vo.name}</volist>
        $parseStr = '<?php ';
        if (0 === strpos($name, ':')) {
            $parseStr .= '$_result='.substr($name, 1).';';
            $name = '$_result';
        } else {
            $name = $this->autoBuildVar($name);
        }
        $parseStr .= 'if(is_array('.$name.')): $'.$key.' = 0;';
        if (isset($tag['length']) && '' != $tag['length']) {
            $parseStr .= ' $__LIST__ = array_slice('.$name.','.$tag['offset'].','.$tag['length'].',true);';
        } elseif (isset($tag['offset']) && '' != $tag['offset']) {
            $parseStr .= ' $__LIST__ = array_slice('.$name.','.$tag['offset'].',null,true);';
        } else {
            $parseStr .= ' $__LIST__ = '.$name.';';
        }
        $parseStr .= 'if( count($__LIST__)==0 ) : echo "'.$empty.'" ;';
        $parseStr .= 'else: ';
        $parseStr .= 'foreach($__LIST__ as $key=>$'.$id.'): ';
        $parseStr .= '$mod = ($'.$key.' % '.$mod.' );';
        $parseStr .= '++$'.$key.';?>';
        $parseStr .= $this->tpl->parse($content);
        $parseStr .= '<?php endforeach; endif; else: echo "'.$empty.'" ;endif; ?>';

        return $parseStr;
    }

    /**
     * foreach标签解析 循环输出数据集

     *
     * @param array $tag 标签属性
     * @param string $content 标签内容
     *
     * @return string
     */
    public function _foreach(array $tag = [], $content = '')
    {
        $name = $tag['name'];
        $item = $tag['item'];
        $key = !empty($tag['key']) ? $tag['key'] : 'key';
        $name = $this->autoBuildVar($name);
        $parseStr = '<?php if(is_array('.$name.')): foreach('.$name.' as $'.$key.'=>$'.$item.'): ?>';
        $parseStr .= $this->tpl->parse($content);
        $parseStr .= '<?php endforeach; endif; ?>';

        if (!empty($parseStr)) {
            return $parseStr;
        }

        return '';
    }

    /**
     * if标签解析
     * 格式：
     * <if condition=" $a eq 1" >
     * <elseif condition="$a eq 2" />
     * <else />
     * </if>
     * 表达式支持 eq neq gt egt lt elt == > >= < <= or and || &&

     *
     * @param array $tag 标签属性
     * @param string $content 标签内容
     *
     * @return string
     */
    public function _if(array $tag = [], $content = '')
    {
        $condition = $this->parseCondition($tag['condition']);

        return '<?php if('.$condition.'): ?>'.$content.'<?php endif; ?>';
    }

    /**
     * else标签解析
     * 格式：见if标签

     *
     * @param array $tag 标签属性
     * @param string $content 标签内容
     *
     * @return string
     */
    public function _elseif($tag, $content)
    {
        $condition = $this->parseCondition($tag['condition']);

        return '<?php elseif('.$condition.'): ?>';
    }

    /**
     * else标签解析

     *
     * @param array $tag 标签属性
     *
     * @return string
     */
    public function _else($tag)
    {
        return '<?php else: ?>';
    }

    /**
     * switch标签解析
     * 格式：
     * <switch name="a.name" >
     * <case value="1" break="false">1</case>
     * <case value="2" >2</case>
     * <default />other
     * </switch>

     *
     * @param array $tag 标签属性
     * @param string $content 标签内容
     *
     * @return string
     */
    public function _switch(array $tag = [], $content = '')
    {
        $name = $tag['name'];
        $varArray = explode('|', $name);
        $name = array_shift($varArray);
        $name = $this->autoBuildVar($name);
        if (count($varArray) > 0) {
            $name = $this->tpl->parseVarFunction($name, $varArray);
        }

        return '<?php switch('.$name.'): ?>'.$content.'<?php endswitch;?>';
    }

    /**
     * case标签解析 需要配合switch才有效

     *
     * @param array $tag 标签属性
     * @param string $content 标签内容
     *
     * @return string
     */
    public function _case(array $tag = [], $content = '')
    {
        $value = $tag['value'];
        if ('$' == substr($value, 0, 1)) {
            $varArray = explode('|', $value);
            $value = array_shift($varArray);
            $value = $this->autoBuildVar(substr($value, 1));
            if (count($varArray) > 0) {
                $value = $this->tpl->parseVarFunction($value, $varArray);
            }
            $value = 'case '.$value.': ';
        } elseif (strpos($value, '|')) {
            $values = explode('|', $value);
            $value = '';
            foreach ($values as $val) {
                $value .= 'case "'.addslashes($val).'": ';
            }
        } else {
            $value = 'case "'.$value.'": ';
        }
        $parseStr = '<?php '.$value.' ?>'.$content;
        $isBreak = isset($tag['break']) ? $tag['break'] : '';
        if ('' == $isBreak || $isBreak) {
            $parseStr .= '<?php break;?>';
        }

        return $parseStr;
    }

    /**
     * default标签解析 需要配合switch才有效
     * 使用： <default />some value

     *
     * @param array $tag 标签属性
     *
     * @return string
     */
    public function _default($tag)
    {
        return '<?php default: ?>';
    }

    /**
     * compare标签解析
     * 用于值的比较 支持 eq neq gt lt egt elt heq nheq 默认是eq
     * 格式： <compare name="" type="eq" value="" >content</compare>

     *
     * @param array $tag 标签属性
     * @param string $content 标签内容
     * @param string $type
     *
     * @return string
     */
    public function _compare(array $tag = [], $content = '', $type = 'eq')
    {
        $name = $tag['name'];
        $value = $tag['value'];
        $type = isset($tag['type']) ? $tag['type'] : $type;
        $type = $this->parseCondition(' '.$type.' ');
        $varArray = explode('|', $name);
        $name = array_shift($varArray);
        $name = $this->autoBuildVar($name);
        if (count($varArray) > 0) {
            $name = $this->tpl->parseVarFunction($name, $varArray);
        }
        if ('$' == substr($value, 0, 1)) {
            $value = $this->autoBuildVar(substr($value, 1));
        } else {
            $value = '"'.$value.'"';
        }

        return '<?php if(('.$name.') '.$type.' '.$value.'): ?>'.$content.'<?php endif; ?>';
    }

    /**
     * <EQ>...</EQ>
     *
     * @param $tag
     * @param $content
     *
     * @return string
     */
    public function _eq(array $tag = [], $content = '')
    {
        return $this->_compare($tag, $content, 'eq');
    }

    /**
     * @param array $tag
     * @param string $content
     *
     * @return string
     */
    public function _equal(array $tag = [], $content = '')
    {
        return $this->_compare($tag, $content, 'eq');
    }

    /**
     * @param array $tag
     * @param string $content
     *
     * @return string
     */
    public function _neq(array $tag = [], $content = '')
    {
        return $this->_compare($tag, $content, 'neq');
    }

    /**
     * @param array $tag
     * @param string $content
     *
     * @return string
     */
    public function _notequal(array $tag = [], $content = '')
    {
        return $this->_compare($tag, $content, 'neq');
    }

    /**
     * @param array $tag
     * @param string $content
     *
     * @return string
     */
    public function _gt(array $tag = [], $content = '')
    {
        return $this->_compare($tag, $content, 'gt');
    }

    /**
     * @param array $tag
     * @param string $content
     *
     * @return string
     */
    public function _lt(array $tag = [], $content = '')
    {
        return $this->_compare($tag, $content, 'lt');
    }

    /**
     * @param array $tag
     * @param string $content
     *
     * @return string
     */
    public function _egt(array $tag = [], $content = '')
    {
        return $this->_compare($tag, $content, 'egt');
    }

    /**
     * @param array $tag
     * @param string $content
     *
     * @return string
     */
    public function _elt(array $tag = [], $content = '')
    {
        return $this->_compare($tag, $content, 'elt');
    }

    /**
     * @param array $tag
     * @param string $content
     *
     * @return string
     */
    public function _heq(array $tag = [], $content = '')
    {
        return $this->_compare($tag, $content, 'heq');
    }

    /**
     * @param array $tag
     * @param string $content
     *
     * @return string
     */
    public function _nheq(array $tag = [], $content = '')
    {
        return $this->_compare($tag, $content, 'nheq');
    }

    /**
     * range标签解析
     * 如果某个变量存在于某个范围 则输出内容 type= in 表示在范围内 否则表示在范围外
     * 格式： <range name="var|function"  value="val" type='in|notin' >content</range>
     * example: <range name="a"  value="1,2,3" type='in' >content</range>

     *
     * @param array $tag 标签属性
     * @param string $content 标签内容
     * @param string $type 比较类型
     *
     * @return string
     */
    public function _range(array $tag = [], $content = '', $type = 'in')
    {
        $name = $tag['name'];
        $value = $tag['value'];
        $varArray = explode('|', $name);
        $name = array_shift($varArray);
        $name = $this->autoBuildVar($name);
        if (count($varArray) > 0) {
            $name = $this->tpl->parseVarFunction($name, $varArray);
        }

        $type = isset($tag['type']) ? $tag['type'] : $type;

        if ('$' == substr($value, 0, 1)) {
            $value = $this->autoBuildVar(substr($value, 1));
            $str = 'is_array('.$value.')?'.$value.':explode(\',\','.$value.')';
        } else {
            $value = '"'.$value.'"';
            $str = 'explode(\',\','.$value.')';
        }
        if ($type == 'between') {
            $parseStr = '<?php $_RANGE_VAR_='.$str.';if('.$name.'>= $_RANGE_VAR_[0] && '.$name.'<= $_RANGE_VAR_[1]):?>'.$content.'<?php endif; ?>';
        } elseif ($type == 'notbetween') {
            $parseStr = '<?php $_RANGE_VAR_='.$str.';if('.$name.'<$_RANGE_VAR_[0] || '.$name.'>$_RANGE_VAR_[1]):?>'.$content.'<?php endif; ?>';
        } else {
            $fun = ($type == 'in') ? 'in_array' : '!in_array';
            $parseStr = '<?php if('.$fun.'(('.$name.'), '.$str.')): ?>'.$content.'<?php endif; ?>';
        }

        return $parseStr;
    }

    /**
     * range标签的别名 用于in判断
     *
     * @param array $tag
     * @param string $content
     *
     * @return string
     */
    public function _in(array $tag = [], $content = '')
    {
        return $this->_range($tag, $content, 'in');
    }

    /**
     * range标签的别名 用于notin判断
     *
     * @param array $tag
     * @param string $content
     *
     * @return string
     */
    public function _notin(array $tag = [], $content = '')
    {
        return $this->_range($tag, $content, 'notin');
    }

    /**
     * 判断变量是否在某个区间范围内
     *
     * @param array $tag
     * @param string $content
     *
     * @return string
     */
    public function _between(array $tag = [], $content = '')
    {
        return $this->_range($tag, $content, 'between');
    }

    /**
     * 判断变量是否不在某个区间范围内
     *
     * @param array $tag
     * @param string $content
     *
     * @return string
     */
    public function _notbetween(array $tag = [], $content = '')
    {
        return $this->_range($tag, $content, 'notbetween');
    }

    /**
     * present标签解析
     * 如果某个变量已经设置 则输出内容
     * 格式： <present name="" >content</present>

     *
     * @param array $tag 标签属性
     * @param string $content 标签内容
     *
     * @return string
     */
    public function _present(array $tag = [], $content = '')
    {
        $name = $tag['name'];
        $name = $this->autoBuildVar($name);

        return '<?php if(isset('.$name.')): ?>'.$content.'<?php endif; ?>';
    }

    /**
     * notpresent标签解析
     * 如果某个变量没有设置，则输出内容
     * 格式： <notpresent name="" >content</notpresent>

     *
     * @param array $tag 标签属性
     * @param string $content 标签内容
     *
     * @return string
     */
    public function _notpresent(array $tag = [], $content = '')
    {
        $name = $tag['name'];
        $name = $this->autoBuildVar($name);

        return '<?php if(!isset('.$name.')): ?>'.$content.'<?php endif; ?>';
    }

    /**
     * empty标签解析
     * 如果某个变量为empty则输出内容
     * 格式： <empty name="" >content</empty>

     *
     * @param array $tag 标签属性
     * @param string $content 标签内容
     *
     * @return string
     */
    public function _empty(array $tag = [], $content = '')
    {
        $name = $tag['name'];
        $name = $this->autoBuildVar($name);

        return '<?php if(empty('.$name.')): ?>'.$content.'<?php endif; ?>';
    }

    /**
     * 如果某个变量不为empty则输出内容
     *
     * @param array $tag
     * @param string $content
     *
     * @return string
     */
    public function _notempty(array $tag = [], $content = '')
    {
        $name = $tag['name'];
        $name = $this->autoBuildVar($name);

        return '<?php if(!empty('.$name.')): ?>'.$content.'<?php endif; ?>';
    }

    /**
     * 判断是否已经定义了该常量
     * <defined name='TXT'>已定义</defined>
     *
     * @param array $tag
     * @param string $content
     *
     * @return string
     */
    public function _defined(array $tag = [], $content = '')
    {
        $name = $tag['name'];

        return '<?php if(defined("'.$name.'")): ?>'.$content.'<?php endif; ?>';
    }

    /**
     * 判断是否未某常量
     *
     * @param array $tag
     * @param string $content
     *
     * @return string
     */
    public function _notdefined(array $tag = [], $content = '')
    {
        $name = $tag['name'];

        return '<?php if(!defined("'.$name.'")): ?>'.$content.'<?php endif; ?>';
    }

    /**
     * assign标签解析
     * 在模板中给某个变量赋值 支持变量赋值
     * 格式： <assign name="" value="" />
     * @deprecated

     *
     * @param array $tag 标签属性
     * @param string $content 标签内容
     *
     * @return string
     */
    public function _assign($tag, $content)
    {
        $name = $this->autoBuildVar($tag['name']);
        if ('$' == substr($tag['value'], 0, 1)) {
            $value = $this->autoBuildVar(substr($tag['value'], 1));
        } else {
            $value = '\''.$tag['value'].'\'';
        }

        return '<?php '.$name.' = '.$value.'; ?>';
    }

    /**
     * define标签解析
     * 在模板中定义常量 支持变量赋值
     * 格式： <define name="" value="" />

     *
     * @param array $tag 标签属性
     * @param string $content 标签内容
     *
     * @return string
     */
    public function _define($tag, $content)
    {
        $name = '\''.$tag['name'].'\'';
        if ('$' == substr($tag['value'], 0, 1)) {
            $value = $this->autoBuildVar(substr($tag['value'], 1));
        } else {
            $value = '\''.$tag['value'].'\'';
        }

        return '<?php define('.$name.', '.$value.'); ?>';
    }

    /**
     * for标签解析
     * 格式： <for start="" end="" comparison="" step="" name="" />

     *
     * @param array $tag 标签属性
     * @param string $content 标签内容
     *
     * @return string
     */
    public function _for(array $tag = [], $content = '')
    {
        //设置默认值
        $start = 0;
        $end = 0;
        $step = 1;
        $comparison = 'lt';
        $name = 'i';
        //添加随机数，防止嵌套变量冲突
        $rand = mt_rand();
        //获取属性
        foreach ($tag as $key => $value) {
            $value = trim($value);
            if (':' == substr($value, 0, 1)) {
                $value = substr($value, 1);
            } elseif ('$' == substr($value, 0, 1)) {
                $value = $this->autoBuildVar(substr($value, 1));
            }
            switch ($key) {
                case 'start':
                    $start = $value;
                    break;
                case 'end' :
                    $end = $value;
                    break;
                case 'step':
                    $step = $value;
                    break;
                case 'comparison':
                    $comparison = $value;
                    break;
                case 'name':
                    $name = $value;
                    break;
                default:
                    break;
            }
        }

        $parseStr = '<?php $__FOR_START_'.$rand.'__='.$start.';$__FOR_END_'.$rand.'__='.$end.';';
        $parseStr .= 'for($'.$name.'=$__FOR_START_'.$rand.'__;'.$this->parseCondition(
                '$'.$name.' '.$comparison.' $__FOR_END_'.$rand.'__'
            ).';$'.$name.'+='.$step.'){ ?>';
        $parseStr .= $content;

        return $parseStr.'<?php } ?>';
    }

}


<?php
/**
 * This file is part of the CarteBlanche PHP framework.
 *
 * (c) Pierre Cassat <me@e-piwi.fr> and contributors
 *
 * License Apache-2.0 <http://github.com/php-carteblanche/carteblanche/blob/master/LICENSE>
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace CarteBlanche\App;

use \Patterns\Abstracts\AbstractSingleton;
use \Patterns\Commons\Registry;
use \Library\Helper\Code as CodeHelper;
use \Library\Helper\Text as TextHelper;
use \CarteBlanche\App\Kernel;
use \CarteBlanche\App\Bundle;
use \CarteBlanche\Interfaces\ContainerInterface;
use \Psr\Log\LoggerAwareInterface;
use \Psr\Log\LoggerInterface;
use \CarteBlanche\Exception\DomainException;
use \CarteBlanche\Exception\InvalidArgumentException;

/**
 * The global container singleton class
 *
 * The Container is callable from any script as long as the Kernel had been created.
 * It contains and manages every dependencies objects.
 *
 * @author  Piero Wbmstr <me@e-piwi.fr>
 */
final class Container
    extends AbstractSingleton
    implements ContainerInterface, LoggerAwareInterface
{

    /**
     * @var \Patterns\Commons\Registry  The instances registry
     */
    protected $instances;

    /**
     * Constructor : defines the current URL and gets the routes
     */
    protected function __construct()
    {
        $this->instances = new Registry;
    }

    /**
     * Global getter
     *
     * @param   string  $name   The variable name to get
     * @return  object  The value of the registry variable
     */
    public function get($name)
    {
        return true===$this->instances->isEntry($name) ? $this->instances->getEntry($name) : null;
    }

    /**
     * Global setter
     *
     * @param   string  $name           The variable name to set
     * @param   object  $object         The object to set
     * @param   bool    $force_overload Over-write an existing value ?
     * @return  bool
     * @throws  \CarteBlanche\Exception\DomainException if `$object` is not an object
     * @throws  \CarteBlanche\Exception\InvalidArgumentException if the entry is already defined and `$force_overload = false`
     */
    public function set($name, $object, $force_overload = false)
    {
        if (!is_object($object)) {
            throw new DomainException(
                sprintf('A container entry must be an object (got "%s" for "%s")!', gettype($object), $name)
            );
        }
        if (true===$this->instances->isEntry($name) && true!==$force_overload) {
            throw new InvalidArgumentException(
                sprintf('You can not over-write a container entry (for "%s")!', $name)
            );
        }
        return (Boolean) $this->instances->setEntry($name, $object);
    }

    /**
     * Instance loader and setter
     *
     * @param   string  $name           The variable name to set
     * @param   array   $params         An array of parameters to pass to loader
     * @param   object  $object_loader  The loader class if so
     * @param   bool    $force_overload Over-write an existing value ?
     * @return  bool
     *
     * @todo Pass arguments (via parameter here and configuration settings)
     */
    public function load($name, array $params = array(), $object_loader = null, $force_overload = false)
    {
        $config = $this->get('config')->get($name, \CarteBlanche\App\Config::NOT_FOUND_GRACEFULLY, array());
        $factory = \Library\Factory::create()
            ->factoryName(__CLASS__)
            ->mustImplement(Kernel::DEPENDENCY_LOADER_INTERFACE)
            ->defaultNamespace(array(
                Kernel::DEPENDENCY_LOADER_DEFAULT_NAMESPACE,
                Kernel::CARTE_BLANCHE_NAMESPACE.Kernel::DEPENDENCY_LOADER_DEFAULT_NAMESPACE
            ))
            ->classNameMask(array('%s', '%s'.Kernel::DEPENDENCY_LOADER_SUFFIX))
            ->callMethod('load')
            ;
        if (!isset($params['config'])) {
            $params['config'] = $config;
        }
        if (!isset($params['options'])) {
            $params['options'] = $config;
        }
        if (!isset($params['container'])) {
            $params['container'] = $this;
        }
        $object = $factory->build(empty($object_loader) ? $name : $object_loader, $params);

/*
        if (empty($object_loader)) {
            $object_loader = Kernel::DEPENDENCY_LOADER_DEFAULT_NAMESPACE
                .ucfirst(TextHelper::toCamelCase($name));
            if (!class_exists($object_loader)) {
                $object_loader .= Kernel::DEPENDENCY_LOADER_SUFFIX;
            }
        }
        if (!class_exists($object_loader)) {
            throw new \RuntimeException(
                sprintf('Unknown dependency loader for reference "%s"!', $name)
            );
        } elseif (!CodeHelper::impelementsInterface($object_loader, Kernel::DEPENDENCY_LOADER_INTERFACE)) {
            throw new \DomainException(
                sprintf('Dependency loader "%s" doesn\'t implement the "%s" interface!',
                    $object_loader, Kernel::DEPENDENCY_LOADER_INTERFACE)
            );
        }
        $loader = new $object_loader;
        $config = $this->get('config')->get($name, \CarteBlanche\App\Config::NOT_FOUND_GRACEFULLY, array());
        $object = $loader->load($config, $this);
*/
        return $this->set($name, $object, $force_overload);
    }

    /**
     * Clear a container entry
     *
     * @param   string  $name   The variable name to set
     * @return  bool
     */
    public function clear($name)
    {
        if (true===$this->instances->isEntry($name)) {
            $this->instances->setEntry($name, null);
        }
    }

    /**
     * Global bundle getter
     *
     * @param   string  $name   The bundle name to get
     * @return  mixed   The value of the registry bundle
     * @see     \Patterns\Commons\Registry::getEntry()
     */
    public function getBundle($name)
    {
        if (true===$this->instances->isEntry($name,'bundles')) {
            return $this->instances->getEntry($name,'bundles');
        }
        return null;
    }

    /**
     * Global bundle setter
     *
     * @param   string  $name           The bundle name to set
     * @param   mixed   $val            The bundle value to set
     * @param   bool    $force_overload Over-write an existing value ?
     * @return  \Patterns\Commons\Registry::setEntry()
     * @throws  \CarteBlanche\Exception\DomainException if `$val` is not an object
     * @throws  \CarteBlanche\Exception\DomainException if `$val` is not a `\CarteBlanche\App\Kernel::BUNDLE_CLASS` instance
     * @throws  \CarteBlanche\Exception\InvalidArgumentException if the entry is already defined and `$force_overload = false`
     */
    public function setBundle($name = null, $val = null, $force_overload = false)
    {
        if (!is_object($val)) {
            throw new DomainException(
                sprintf('A bundle entry must be an object (got "%s" for bundle "%s")!', gettype($val), $name)
            );
        }
        if (!CodeHelper::isClassInstance($val, Kernel::BUNDLE_CLASS)) {
            throw new DomainException(
                sprintf('A bundle entry must be a "%s" instance (for "%s")!', Kernel::BUNDLE_CLASS, $name)
            );
        }
        if (true===$this->instances->isEntry($name, 'bundles') && true!==$force_overload) {
            throw new InvalidArgumentException(
                sprintf('You can not over-write a container bundle (for "%s")!', $name)
            );
        }
        return $this->instances->setEntry($name,$val,'bundles');
    }

    /**
     * Clear a container bundle entry
     *
     * @param   string  $name   The bundle name to unset
     */
    public function clearBundle($name)
    {
        if (true===$this->instances->isEntry($name,'bundles')) {
            $this->instances->setEntry($name,null,'bundles');
        }
    }

    /**
     * Sets a logger instance on the object
     *
     * @param   LoggerInterface     $logger
     * @return  null
     */
    public function setLogger(LoggerInterface $logger)
    {
        $this->instances->setEntry('logger',$logger);
    }

}

// Endfile